虚拟化相关
虚拟化相关
ZEROKO14包含虚拟机和docker相关知识点
虚拟化网络设置
docker网络
Docker网络剖析
官方文档给出了5种网络驱动模型,如下:
bridge:网桥类型网络;其实就是五大虚拟化网络模型中的NAT网络,只不过这里叫做bridge网桥类型.需要映射接口才能让外部访问到容器默认bridge不支持容器名dns
自定义bridge支持容器名dns
host:该模式仅在linux可用,理解成容器变成了宿主的一个应用了.其原理是容器使用宿主机的网络空间,因此会直接看到并使用宿主机所有网络功能None:啥网络都没有
1 | docker命令 |
虚拟机网络
(以virtualBox为例)
NAT模式相当于虚拟了一层NAT,但是各个虚拟机之间隔离NAT网络模式虚拟了一层NAT,各个虚拟机之间不隔离VMware等虚拟机的NAT模式不太一样 虚拟了一层NAT,各个虚拟机之间可以互相访问,虚拟机与宿主机之间也可以互访
桥接相当于虚拟机放到了宿主机局域网里(适配器选项需要和宿主当前联网使用的适配器一致).结果是虚拟机和宿主处于同一网段,由路由器统一分配ip内部网络模式相当于仅仅用交换机网线把虚拟机们连接起来了.(需要提前设置系统设置,防止虚拟机启动时一直卡在DHCP服务里,同时还需要给虚拟机手动设置ip),虚拟机间互通,但不能访问宿主,不能访问网络仅主机模式仅允许虚拟机之间以及与宿主的互访
docker
优势
- 应用隔离
- 环境配置
- 安装部署
- 持续集成
- 持续发布
- DevOps
docker和虚拟机的区别
特性 普通虚拟机 Docker 跨平台 通常只能在桌面级系统运行,例如 Windows/Mac,无法在不带图形界面的服务器上运行 支持的系统非常多,各类 windows 和 Linux 都支持 性能 性能损耗大,内存占用高,因为是把整个完整系统都虚拟出来了 性能好,只虚拟软件所需运行环境,最大化减少没用的配置 自动化 需要手动安装所有东西 一个命令就可以自动部署好所需环境 稳定性 稳定性不高,不同系统差异大 稳定性好,不同系统都一样部署方式 虚拟机使用Hypervisor虚拟化技术
Docker 通常用来做什么
- 应用分发、部署,方便传播给他人安装。特别是开源软件和提供私有部署的应用
- 快速安装测试/学习软件,用完就丢(类似小程序),不把时间浪费在安装软件上。例如 Redis / MongoDB / ElasticSearch / ELK
- 多个版本软件共存,不污染系统,例如 Python2、Python3,Redis4.0,Redis5.0
- Windows 上体验/学习各种 Linux 系统
概念理解
- 打包:就是把你软件运行所需的依赖、第三方库、软件打包到一起,变成一个安装包
- 分发:你可以把你打包好的“安装包”上传到一个镜像仓库,其他人可以非常方便的获取和安装
- 部署:拿着“安装包”就可以一个命令运行起来你的应用,自动模拟出一摸一样的运行环境,不管是在 Windows/Mac/Linux。
- 镜像:可以理解为软件安装包,可以方便的进行传播和安装。
- 容器:软件安装后的状态,每个软件运行环境都是独立的、隔离的,称之为容器。
安装
windows和mac需要安装Docker Desktop,在使用docker命令的时候要启动Docker Desktop
windows安装需要开启 Windows 虚拟化和 Linux 子系统(WSL2),如下图,不然启动会报错(新版本似乎不会报错了)
镜像加速源
6月6日大多数镜像源失效
| 镜像加速器 | 镜像加速器地址 |
|---|---|
| Docker 中国官方镜像 | https://registry.docker-cn.com |
| DaoCloud 镜像站 | http://f1361db2.m.daocloud.io |
| Azure 中国镜像 | https://dockerhub.azk8s.cn |
| 科大镜像站 | https://docker.mirrors.ustc.edu.cn |
| 阿里云 | https://ud6340vz.mirror.aliyuncs.com |
| 七牛云 | https://reg-mirror.qiniu.com |
| 网易云 | https://hub-mirror.c.163.com |
| 腾讯云 | https://mirror.ccs.tencentyun.com |
设置加速源
"registry-mirrors": ["https://registry.docker-cn.com","https://dockerhub.azk8s.cn"]
一览
基本知识
dockerhub找镜像相关
搜到一个docker镜像后
其中可能会有介绍或how to use的说明
还可能会罗列很多版本信息,可以根据版本进行下载
alpine 轻量级,瘦身版
镜像构建
Docker中包含Dockfile,镜像,容器三种概念.
其中镜像是用于构建容器的”菜谱”
镜像是按层次结构来构建的,每一层都是基于上一层的(底层是增量存储),通过编写Dockfile可以构建镜像.所以需要先指定一个基础镜像,然后在这个镜像的基础上添加其他我们需要的东西
使用
docker image history 镜像名/镜像id可以查看Dockerfile写的每一个指令(显示出来的需要从下往上看)
Dockerfile语法
FROM 基础镜像:表示新建的iamge(镜像)需要在node环境中进行,那么就需要node镜像。WORKDIR 工作目录:它可以指定容器启动后的默认工作目录,如声明了工作目录/app,即node代码在该目录下进行COPY 源路径 目标路径:作用是将当前目录的所有代码都复制到工作目录下(源路径为相对于Dockerfile文件的路径,目标路径为镜像内的路径)CMD:后面跟着一句shell 命令,该命令在容器运行的时候会得到执行,即当容器运行的时候,就会启动一个监听端口为3000的服务1
2
3
4
5
6#CMD命令后可接方括号
CMD ["node","/index.js"]
#第一个参数表示可执行程序的名字,其他参数表示该可执行程序需要的参数(注意一切路径基于镜像)
#CMD命令也可不接方括号
CMD node /index.js- CMD
-c追加命令会替换CMD指定的命令 - ENTRYPOINT
-c追加命令会追加到ENTRYPOINT指定的命令的后面(除此之外用法与CMD完全一样)
- CMD
ENV key value:设置环境变量key的值为value,如:ENV MY_NAME John Doe
依据Dockerfile构建新镜像使用命令:docker build -t my-docker-demo:1.0 . ,.表示dockerfile所在的目录
实例化该镜像,并运行
docker run -d -p 3000:3000 --name myContainerDemo my-docker-demo:1.0
进入容器shell命令行
docker exec -it myContainerDemo /bin/bash
操作完成后:可以将运行的容器提交为镜像
停止容器:
docker stop <container_name>提交容器为镜像
docker commit <container_name> <image_name>其中,
<container_name>是正在运行的容器的名称,<image_name>是要创建的新镜像的名称。创建一个新的容器,并使用
--entrypoint和--command选项来指定新的启动指令:如:
docker run -it --rm --entrypoint /bin/bash --command echo hello world <image_name>这将创建一个新的容器,该容器启动时将运行
/bin/bash程序,并执行echo hello world命令。
拉取命令: docker pull 镜像名 如果不指定架构,那么会默认拉取符合自身架构的镜像
arm架构的mac下使用
docker pull命令,如果需要拉amd64架构的镜像来通过Rosetta使用,需要使用命令docker pull --platform linux/amd64 镜像名
linux下,docker下的镜像,容器,虚拟网络,卷,插件都记录在/var/lib/docker下
目录挂载
现存问题
- 使用 Docker 运行后,我们改了项目代码不会立刻生效,需要重新
build和run,很是麻烦。 - 容器里面产生的数据,例如 log 文件,数据库备份文件,容器删除后就丢失了。
容器的特点:容器中的数据不会持久化,新建一个容器,它通常以一个干净的文件系统开始,我们可以创建文件,修改文件,但当我们停止容器时,容器中的所有数据都会丢失掉
想要持久化容器中的数据的话,需要通过目录挂载
几种挂载方式用于解决上述的问题
bind mount直接把宿主机目录映射到容器内,适合挂代码目录和配置文件。可挂到多个容器上用法:
-v 宿主机绝对路径:容器内绝对路径如:-v D:/code:/appvolume由容器创建和管理,创建在宿主机,所以删除容器不会丢失,官方推荐,更高效,Linux 文件系统,适合存储数据库数据。可挂到多个容器上用法
-v 逻辑卷名:容器内绝对路径(具名挂载) 如-v db-data:/app如果写成
-v 容器内绝对路径匿名挂载,会自动创建和容器id同名的逻辑卷tmpfs mount适合存储临时文件,存宿主机内存中。不可多容器共享。
目录挂载注意项
Docker 的两种挂载方式的差异
Bind Mount (本地目录):
格式:
-v /本机/路径:/容器/路径行为:强行覆盖。不管容器里原来有什么,都以本机目录为准。本机是空的,容器里看到的就是空的。
这就是导致 很多容器 跑不起来的原因,因为代码被“盖”没了。
两种常见方式
只挂载文件(最安全,推荐) 这样就像是在桌子上(容器目录)放了一张纸(配置文件),不会遮挡其他饭菜(代码)
挂载到子目录(如果程序支持) 如果程序允许从子目录读取配置,您可以挂载到一个不冲突的子目录。例如 LiteLLM 并没有
/app/custom_config这个代码目录,那您可以挂载到这里,然后通过参数配置路径位置(前提是程序允许)
Named Volume (命名卷):
- 格式:
-v my-data-volume:/容器/路径(注意这里没有/开头的路径) - 行为:初次初始化。如果这个卷是新的(空的),Docker 会把容器里对应路径下的原有文件复制到卷里。
- 如果是这种方式,容器里的文件确实会“反映”出来。如果使用的是本地路径挂载,不适用此规则。
- 格式:
docker命令
docker run [参数] 镜像名/镜像ID运行镜像中运行指令如
docker run -d --name container1 image-d表示后台启动--name 容器名表示给容器起名(不指定名字的话会随机起名)-p 宿主机端口:容器端口映射容器内端口到宿主机,如-p 9090:8080把容器内的8080端口暴露到宿主机的9090端口.默认映射针对的是tcp,如果要针对udp:-p 5000:5000/udp--network 虚拟网络名/网络模式指定容器所属的虚拟网络,也可以指定使用的网络模式--network-alias 容器在虚拟网络中的别名指定容器在虚拟网络中的别名(该别名在代码中可以直接作为ip地址来使用,能正确路由到对应容器)--rm代表在容器停止后自动删除容器--volumes-from 容器名指定容器名中所有的volumes都挂载过来准备启动的容器中-c 要执行的命令指定在容器启动时要执行的命令 (可以省略到-c,直接将要执行的命令接到镜像名后面),如果Dockerfile中有CMD命令带的指令,该-c指定的命令会替换CMD的命令,如果Dockerfile中有ENTRYPOINT,则-c指定的命令则会是追加执行命令docker build -t 镜像名:版本如:
docker build -t test:v1-t 镜像名:版本设置镜像名字和版本号-f Dockerfile文件可以指定不叫Dockerfile的Dockerfile文件docker network create 虚拟网络名创建虚拟网络docker exec -it 容器名/容器id /bin/bash使用/bin/bash与容器交互的方式进入容器
其他命令
docker ps 查看当前运行中的容器docker images 查看镜像列表docker rm container-id 删除指定 id 的容器docker stop/start container-id 停止/启动指定 id 的容器docker rmi image-id 删除指定 id 的镜像docker volume ls 查看 volume 列表docker network ls 查看网络列表
查看容器的ip地址,使用这句命令:docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名/容器id
多容器通信
创建虚拟网络
要想多容器之间互通,比如从 Web 容器访问 Redis 容器,我们只需要把他们放到同个网络中就可以了。
演示
创建一个名为
test-net的网络docker network create test-net运行 Redis 在
test-net网络中,别名redisdocker run -d --name redis --network test-net --network-alias redis redis:latest修改代码中通过别名redis来访问Redis容器
如js代码:
1
2
3
4const redis = require('redis');
let rds = redis.createClient({url: "redis://redis:6379"});
rds.on('connect', () => console.log('redis connect ok'));
rds.connect();运行 Web 项目,使用同个网络
docker run -p 8080:8080 --name test -v D:/test:/app --network test-net -d test:v1
这样两个容器之间就连接上了,但是如果管理的容器非常多呢,这时候就需要用到Docker-Compose
Docker-Compose
由Docker官方开源的项目
- 用于定义和运行多容器Docker应用程序的工具
- 使用YAML文件(
docker_compose.yaml)来配置应用程序的服务- 一条命令
docker compose up即可创建或启动所有服务服务之间的关联关系就是Docker Compose需要解决的问题
如果两个容器不在同一个网络,需要将它们连接到同一个网络。通常使用docker-compose时,它们会自动在同一个网络中
如果项目依赖更多的第三方软件,我们需要管理的容器就更多,每个都要单独配置运行,指定网络非常麻烦。
这里,我们使用 docker-compose 把项目的多个服务集合到一起,一键运行。
安装 Docker Compose
- 如果你是安装的桌面版 Docker,不需要额外安装,已经包含了。
- 如果是没图形界面的服务器版 Docker,你需要单独安装 安装文档
- 运行
docker-compose检查是否安装成功
编写脚本
要把项目依赖的多个服务集合到一起,我们需要编写一个docker-compose.yml文件,描述依赖哪些服务
[[数据序列化格式盘点#yaml|yaml格式参考]]
1 | version: "3.7" |
volumes部分定义了一个名为redis的volume。Volumes是用来在Docker容器之间共享数据的一种机制。在这个文件中,redis这个volume被用于存储Redis容器的数据,以便在容器重启或重新部署时保留数据
定义一个volume时,您可以选择使用具体的目录地址或者名称。在这种情况下,redis这个volume没有指定具体的目录地址,而是只给出了一个名称redis:/data。这意味着Docker会自动为这个volume创建一个挂载点,并将其用于存储容器中的数据。这种方式更加灵活,因为Docker会自动管理这个volume的位置和生命周期,而不需要您手动指定目录地址.若redis下的volumes下写为- ./redis_data:/data这就是手动指定目录地址的方式
容器默认时间不是背景时间,增加
TZ=Asia/Shanghai可以改为上海时区
在docker-compose.yml 文件所在目录,执行:docker-compose up就可以跑起来了。
相关命令
在后台运行只需要加一个
-d参数docker-compose up -d查看运行状态:
docker-compose ps停止运行:
docker-compose stop停止运行并删除旧容器(但数据卷会保留):
docker-compose down如果修改了docker-compose.yml文件,使用上面指令后再重新启动容器才能生效
重启:
docker-compose restart重启单个服务:
docker-compose restart service-name进入容器命令行:
docker-compose exec service-name sh查看容器运行log:
docker-compose logs [service-name]
发布和部署
镜像仓库介绍
镜像仓库用来存储我们 build 出来的“安装包”,Docker 官方提供了一个 镜像库,里面包含了大量镜像,基本各种软件所需依赖都有,要什么直接上去搜索。
我们也可以把自己 build 出来的镜像上传到 docker 提供的镜像库中,方便传播。
当然你也可以搭建自己的私有镜像库,或者使用国内各种大厂提供的镜像托管服务,例如:阿里云、腾讯云
首先你要先 打开官网,登录账号
创建一个镜像库
命令行登录账号: (下面的username均应填入实际的账号名)
docker login -u username新建一个tag(利于版本控制,便于回滚与追踪)
docker tag test:v1 username/test:v1推上去
docker push username/test:v1部署试下
docker run -dp 8080:8080 username/test:v1也可直接在docker-compose中直接使用这个镜像
username/test:v1了
阿里云容器托管: docker 官方的镜像托管有时候上传和下载都太慢了,如果你想要更快的速度,可以使用阿里云的免费镜像托管(镜像仓库100个 不限时长) 点击此处跳转阿里云容器镜像服务的镜像仓库
备份和迁移数据
容器中的数据,如果没有用挂载目录,删除容器后就会丢失数据。
参考如何挂载目录
如果你是用bind mount直接把宿主机的目录挂进去容器,那迁移数据很方便,直接复制目录就好了
如果你是用volume方式挂载的,由于数据是由容器创建和管理的,需要用特殊的方式把数据弄出来。
备份和导入Volume的流程
备份:
- 运行一个 ubuntu 的容器,挂载需要备份的 volume 到容器,并且挂载宿主机目录到容器里的备份目录。
- 运行 tar 命令把数据压缩为一个文件
- 把备份文件复制到需要导入的机器
导入:
- 运行 ubuntu 容器,挂载容器的 volume,并且挂载宿主机备份文件所在目录到容器里
- 运行 tar 命令解压备份文件到指定目录
备份 MongoDB 数据演示
运行一个 mongodb,创建一个名叫
mongo-data的 volume 指向容器的 /data 目录docker run -p 27018:27017 --name mongo -v mongo-data:/data -d mongo:4.4运行一个 Ubuntu 的容器,挂载
mongo容器的所有 volume,映射宿主机的 backup 目录到容器里面的 /backup 目录,然后运行 tar 命令把数据压缩打包到用于导出目录docker run --rm --volumes-from mongo -v d:/backup:/backup ubuntu tar cvf /backup/backup.tar /data/--rm代表在容器停止后自动删除容器
最后你就可以拿着这个 backup.tar 文件去其他地方导入了。
本质其实就是用一个ubuntu镜像的临时容器映射了宿主机的两个目录(分别是要备份的文件目录以及用于导出备份文件的目录),容器中
/data目录下的内容压缩放到容器下backup目录,执行完毕后到宿主机中的d:/backup就可以找到备份文件backup.tar
恢复 Volume 数据演示
- 运行一个 ubuntu 容器,挂载 mongo 容器的所有 volumes,然后读取 /backup 目录中的备份文件,解压到 /data/ 目录
docker run --rm --volumes-from mongo -v d:/backup:/backup ubuntu bash -c "cd /data/ && tar xvf /backup/backup.tar --strip 1"
本质就是将压缩包解压回容器中的
/data下–strip 1 表示解压时去掉前面1层目录,将文件提取到当前目录而不是保留原始目录结构
CMD与ENTRYPOINT
CMD示例
1 | FROM ubuntu |
运行时:
1 | docker run myimage |
ENTRYPOINT示例
强制执行固定命令
1 | FROM ubuntu |
运行时:
1 | docker run myimage |
CMD 和 ENTRYPOINT 组合
1 | FROM ubuntu |
运行结果:
1 | docker run myimage |
使用 ENTRYPOINT 制作工具化容器
工具型容器常用 ENTRYPOINT 设计成不可替换的行为。例如:
制作 curl 工具容器
1 | FROM curlimages/curl |
运行时:
1 | docker run mycurl -X GET https://example.com |
Alias创建别名
1 | alias mytool="docker run --rm -v $(pwd):/data my-image" |
添加到 ~/.bashrc 或 ~/.zshrc 中,使其在每次启动终端时生效。
如果经常使用docker容器中的命令,也可以创建一个函数来简化操作,如:
1 | binarychat() { |
一个C++开发环境的Dockerfile
Dockerfile -> 镜像 ->容器
编写Dockerfile
目录下新建Dockerfile文件
1 | # 基础镜像 |
构建镜像
执行下面命令构建docker镜像
docker build -t 镜像名 .
docker build: 这是 Docker 命令的一部分,用于构建 Docker 镜像。
-t 镜像名: -t 参数用于指定构建的镜像的标签(tag)。可以根据需要自行更改。.: 这表示 Dockerfile 的路径,.表示当前目录。Dockerfile 是一个包含构建指令的文本文件,它定义了如何构建 Docker 镜像。
使用这个命令,您可以在当前目录中的 Dockerfile 中定义的环境中构建一个名为 镜像名 的 Docker 镜像。Docker 将按照 Dockerfile 中指定的指令执行构建过程,并生成一个可用的镜像。
确认镜像构建成功: docker images 如果可以看到前面指定的镜像名,则构建成功
容器中运行镜像
在容器中运行镜像: docker run --name cpp_tutorials_container -v /Users/hejun/project/cpp_tutorials:/cpp_tutorials -it 镜像名
docker run: 这是 Docker 命令的一部分,用于在容器中运行镜像。--name 容器名:--name参数用于指定容器的名称。可以根据需要自行更改。-v /Users/hejun/project/cpp_tutorials:/cpp_tutorials:-v参数用于将主机的目录(/Users/hejun/project/cpp_tutorials)与容器内部的目录(/cpp_tutorials)进行挂载(映射)。这样可以在容器内访问主机上的文件和目录。这使得容器内的操作可以访问主机上的文件和目录,方便在开发环境中共享和处理代码。
-it: -i 和 -t 参数一起使用,以交互模式运行容器,并分配一个终端(TTY)以便与容器进行交互。镜像名: 这是要运行的镜像的名称。 使用这个命令,您可以在一个新的容器中运行名为指定镜像名的镜像。容器将会创建,并在交互模式下启动,您可以在容器的终端中执行命令和操作。
查看容器
docker ps
进入正在运行的容器
docker start -i 容器名
运行docker配置项
Ports左边为在宿主机上访问的端口,右边一般不需要填写,因为这是应用程序默认暴露的端口Volumes卷,可以将容器的目录挂到容器的应用目录下,通常:如果是使用这种方式,修改文件可以立即生效,最多也就是重启容器就可以生效
- Host path 本地的路径
- Container path 容器内的路径
Environment variables环境变量,表示可以配置docker环境中的环境变量注意,环境变量的设置需要停止并删除现有容器,然后重新创建容器
- Variable 环境变量的名
- Value 环境变量的值
常用docker命令盘点
docker内网络测试
使用docker exec执行内置命令:
docker exec 容器哈希/容器名 具体的命令创建一个临时容器(针对极简镜像测试网络),共享网络命名空间来测试:
docker run -it --rm --network container:容器哈希 alpine sh也可以直接通过临时容器一句话连指令一起发:
docker run --rm --network container:bb3995 alpine ping -c 2 8.8.8.8可以确定容器是否有基本的网络连接
docker容器内访问主机ip地址可以通过域名http://host.docker.internal
docker查看当前全部容器的ip地址
1 | 查看所有容器的IP地址 |
docker查看指定容器的信息格式化显示
1 | 查看容器基本信息表格 |
docker容器之间的网络连接
查看所有网络可以通过docker network ls
最常见的是各个容器都将自己的端口映射到宿主机的某个端口,互相之间通过
http://host.docker.internal:端口号的方式来互相访问这种方式虽然每个容器都是独立的网络(不填写network的情况下名字将是
容器名_default)另一种方式是将多个容器指定到一个网络中,network指向同一个名字即可
相互之间可以直接通过容器内子网的ip地址进行互相访问
各平台部署性能损耗对比
| 部署环境(Docker) | 核心运行机制 | CPU / 内存损耗 | 磁盘 I/O 损耗(核心场景) | 网络损耗(核心模式) | 性能定位 | 核心适用场景 | 极致优化建议 |
|---|---|---|---|---|---|---|---|
| Linux 原生系统(Ubuntu 24.04+/RHEL 9.3+) | 直接基于 Linux 6.6 + 内核,Namespace+Cgroupv2,无虚拟化层,overlay2 默认启用 fast diff 特性 | <1%(可忽略) | 1. 容器内 overlay2(fast diff):3-5% 2. 宿主机 bind mount:<3% 3. Volume(本地 / CSI):<2% |
1. 默认 bridge(nftables):延迟 + 1-3,吞吐量 < 3% 2. host 模式:几乎 0 损耗 3. 容器间 link:<2% |
准原生(无感知) | 生产环境(核心业务 / 高并发 / 高 I/O)、开发 / 测试 | 1. 启用 Cgroupv2+systemd 统一管理 2. 核心业务用 host 网络 + 本地 Volume 3. 大文件场景禁用 copy-up,使用 direct-lvm |
| macOS(Docker Desktop 26.2+,Apple Silicon/macOS 14+) | 基于 Apple 虚拟化框架 + VirtioFS(默认),轻量 Linux VM,文件共享通过 virtiofsd 原生加速 | 3-6% | 1. VirtioFS 共享目录(默认):8-15% 2. 容器内独立目录:5-10% 3. 旧版 gRPC-FUSE(已淘汰):50%+ |
1. 默认 bridge:延迟 + 3-5,吞吐量 8-10% 2. host 模式:延迟 + 2-4,吞吐量 5-8% 3. 容器互联:<3% |
低损耗(轻微感知) | 开发 / 测试环境(本地联调),不建议生产 | 1. 升级 macOS 14+,确认 VirtioFS 默认启用(26.2+) 2. 减少跨系统文件读写,优先容器内目录 3. 启用 Resource Saver 模式降低空闲 CPU 占用 |
| Windows WSL2(2.0.9+,Windows 11 23H2+) | 复用 WSL2 轻量 Hyper-V VM,Linux 5.15 + 内核,支持 VirtioFS 文件共享(2026 年默认) | <1.5%(接近原生) | 1. WSL2 内部目录(/home/):<3% 2. VirtioFS 共享 Windows 目录:8-12% 3. Volume:<2% |
1. 默认 bridge(WSLg 优化):延迟 + 1-2,吞吐量 < 3% 2. host 模式:几乎 0 损耗 3. 宿主机互通:<1.5% |
接近原生(无感知) | Windows 端开发 / 测试、轻量生产(非超高 I/O) | 1. 所有项目放在 WSL2 内部目录 2. 启用 WSL2 动态内存 + VirtioFS 3. 关闭 Windows Defender 对 WSL 目录实时扫描 |
| Windows Server 2025(进程隔离) | 基于 Windows Server 2025 内核,Namespace+Job Objects,无虚拟化层,默认进程隔离 | <1%(可忽略) | 1. 容器内原生目录:<3% 2. 宿主机挂载(SMB 4.1+):3-6% 3. Volume:<2% |
1. 默认 NAT(2025 优化版):延迟 + 1-2,吞吐量 < 3% 2. host 模式:几乎 0 损耗 3. 容器集群:<2% |
准原生(无感知) | Windows 原生业务生产环境(.NET 8+/Windows 服务) | 1. 确保容器镜像与宿主机版本完全匹配(2025 LTSC) 2. 核心业务用 host 网络 + 本地 Volume 3. 启用容器 CPU / 内存硬限制(Cgroupv2) |
| Windows Server 2025(Hyper-V 隔离) | 基于 Hyper-V 2025 轻量 VM,每个容器独立内核,安全隔离增强版 | 8-12% | 1. 容器内目录:12-18% 2. 宿主机挂载:18-22% 3. 固定磁盘:比动态磁盘降低 3-5% 损耗 |
1. 默认 NAT:延迟 + 6-8,吞吐量 8-12% 2. host 模式:延迟 + 4-6,吞吐量 6-10% 3. 隔离网络:+2% |
中等损耗(明显感知) | 高安全隔离需求(金融 / 政务)、多租户场景 | 1. 仅必要场景使用,避免高 I/O/ 高并发 2. 使用 Gen2 VM + 固定大小 VHDX 3. 启用 Hyper-V 性能计数器优化调度 |
| Windows Server 2025(Linux 容器) | 基于 Hyper-V 2025 运行 Linux 内核 VM,跨内核虚拟化层,无进程隔离选项 | 6-9% | 1. 容器内目录:12-18% 2. 宿主机挂载:18-25% 3. Volume:10-15% |
1. 默认 bridge:延迟 + 5-8,吞吐量 10-15% 2. host 模式:延迟 + 3-5,吞吐量 8-10% 3. 端口映射:+2% |
中等损耗(明显感知) | 仅 Windows Server 端临时 Linux 业务调试 | 1. 替换为 WSL2+Docker(性能提升 40%+) 2. 减少跨系统文件读写 3. 若必须使用,启用 Hyper-V 嵌套虚拟化 |
上面的Windows Server 2025(进程隔离)只用于启动windows容器
90%+的容器为 Linux 容器,Windows容器几乎仅用于微软系 Windows 原生业务
仅考虑运行Linux容器的排名如下:
排名 部署环境(仅运行 Linux 容器) 核心 CPU / 内存损耗 磁盘 I/O 核心损耗(主流场景) 网络核心损耗(bridge 模式) 性能定位 核心适用场景 1 Linux 原生(Ubuntu24.04+/RHEL9.3+) <1%(可忽略) Volume<2%/bind mount<3% 延迟 + 1-3ms / 吞吐量 < 3% 准原生(无感知) 生产核心业务、高并发 / 高 IO、开发测试 2 Windows WSL2 2026+(Docker 26.2+) <1.5%(接近原生) WSL2 内部目录 < 3%/VirtioFS 共享 8-12% 延迟 + 1-2ms / 吞吐量 < 3% 接近原生(无感知) Windows 端开发测试、Linux 轻量生产 3 macOS 14+(Docker 26.2+) 3-6%(低损耗) VirtioFS 共享 8-15%/ 容器内目录 5-10% 延迟 + 3-5ms / 吞吐量 8-10% 低损耗(轻微感知) macOS 端本地开发测试(无生产价值) 4 Windows Server 2025(原生 Docker 跑 Linux 容器) 6-9%(中等损耗) 容器内目录 12-18%/ 宿主机挂载 18-25% 延迟 + 5-8ms / 吞吐量 10-15% 中等损耗(明显感知) 临时 Linux 业务调试(强烈不推荐生产)
windows和windows server对docker的支持情况
| 对比维度 | Windows 11 23H2+(WSL2) | Windows Server 2025 |
|---|---|---|
| 系统核心定位 | 桌面端(开发 / 测试为主,兼顾轻量生产) | 服务端(纯生产级,聚焦稳定性 / 高可用 / 企业隔离) |
| Docker 核心支持模式 | 仅支持「WSL2+Linux 容器」(主流),Windows 容器为轻量兼容版(无生产级优化) | 双模式全支持: 1. 原生进程 / Hyper-V 隔离的 Windows 容器(生产级,专属特性) 2. WSL2+Linux 容器(适配 Linux 生态) |
| 专属 Docker 特性 | 无生产级特性,仅做开发适配(如 WSLg、文件无缝共享) | 企业级特性: 1. Cgroupv2 硬限制 2. SMB 4.1 + 挂载优化 3. Hyper-V 企业级隔离 4. 容器集群适配 |
| 底层虚拟化组件 | Hyper-V 为桌面轻量版(资源调度偏向桌面体验,无企业级性能优化) | Hyper-V 为服务端企业版(支持 Gen2 VM、固定磁盘、性能计数器优化,适配生产高负载) |
| Docker 优化重点 | 开发易用性(如 VirtioFS 无缝共享、动态内存) | 生产稳定性(如版本强匹配、CPU / 内存硬限制、隔离网络) |
| 默认运行的容器类型 | 99% 场景跑Linux 容器(WSL2),Windows 容器极少用 | 分场景: 1. Windows 原生业务跑进程隔离 Windows 容器(主流) 2. Linux 业务跑 WSL2+Linux 容器(适配) |
部分工业软件、硬件配套服务,依赖Windows 专属的硬件驱动(如工业采集卡、打印机驱动、串口驱动),Linux 无对应的驱动支持,只能通过 Windows 容器运行,同时映射宿主机硬件
Docker Desktop
防止Docker Desktop占用C盘
wsl实例迁移
Docker 会自动创建两个专属 WSL 实例: wsl存储机制
docker-desktop:运行 Docker 守护进程、CLI 等系统组件(占用几百 MB);docker-desktop-data:存储所有 Docker 镜像、容器、卷(你的 16GB 核心);
Docker 专属实例:C:\Users\<你的用户名>\AppData\Local\Docker\wsl\data\ext4.vhdx
这两个实例默认在 C 盘,即使 Docker 本体装在 D 盘,数据仍在 C 盘
Docker Desktop 的可视化设置改不了这个路径,只能通过 export/import 指令迁移
Docker 的所有数据(镜像、容器、卷、网络配置)都存储在 docker-desktop-data 这个 WSL 实例的虚拟磁盘(.vhdx)中
迁移脚本
下面迁移的方式已经被淘汰
- 4.30 以前
- docker-desktop → 引擎
- docker-desktop-data → 镜像 / 容器数据
- 4.30+ 新安装
- ❌ 不再创建 docker-desktop-data
- ✅ 改为 Docker 自己管理 VHD 磁盘
新版本直接在
Settings → Resources → Advanced改位置就可以!!!
以下是迁移 Docker 专属 WSL 实例的一键 PowerShell 脚本,脚本包含管理员权限检查、自动停止服务、路径自定义、异常处理,新手可直接使用,全程无需手动输零散命令
使用前必看(关键注意事项)
脚本运行前:必须关闭 Docker Desktop(托盘里右键退出,确保完全停止);
请修改脚本中
$targetRootPath变量为你想迁移到的 D 盘路径(默认是D:\Docker\WSL,可自定义);脚本需以管理员身份运行(否则会权限不足);
迁移过程中会生成临时 tar 备份文件(迁移完成后可自动删除,也可保留);
脚本里的
$keepTarFile设为$true,迁移后会保留 D 盘的 tar 文件迁移完成后,C 盘
%USERPROFILE%\AppData\Local\Docker\wsl目录下的旧文件会被注销,16GB 空间会释放。
1 | <# |
手动验证步骤:
- 执行
wsl -l -v确认 docker-desktop-data 和 docker-desktop 实例存在 - 检查
C:\Users\ADMIN\AppData\Local\Docker\wsl目录已清空 - 启动Docker Desktop验证镜像/容器是否正常
假如启动Docker Desktop后,容器不在,执行导入,如下:
1 | 挂载docker_data.vhdx到WSL2的块设备,并指定挂载点为/var/lib/docker |
日志占用C盘
删除C盘现有Docker日志: 打开路径 C:\Users\ADMIN\AppData\Local\Docker\logs,直接删除文件夹内所有文件 / 子文件夹(日志无核心数据,可放
清理容器残留日志
1 | 清理所有未使用的容器、镜像、卷、网络,以及容器日志缓存 |
-a:清理所有未使用的镜像;--volumes:清理未使用的卷(含卷日志);-f:强制清理,无需确认。
迁移日志目录到 D 盘
根源解决日志写 C 盘
找到 Docker 的 daemon.json 配置文件:
默认路径:C:\Users\ADMIN\.docker\daemon.json(如果没有,手动创建);
如果找不到:打开 Docker Desktop → 设置(Settings)→ Docker Engine → 右侧编辑框就是 daemon.json 的内容。
修改 daemon.json,配置日志存储路径 + 日志驱动:
替换 或 添加以下内容(注意 JSON 格式,逗号分隔,无语法错误):
1 | { |
✅ 关键说明:
path:指定日志文件存储到D:\Docker\logs(脚本会自动创建,无需手动建);data-root:把 Docker 的核心数据根目录也迁到 D 盘,彻底杜绝 C 盘写入;max-size/max-file:提前限制日志大小(第三步详细说)。
重启 Docker Desktop 使配置生效:
保存 daemon.json 后 → 点击 Docker Desktop 右上角「Apply & Restart」→ 等待 Docker 重启完成。
限制日志大小
防止后续日志再次涨满
上面daemon.json中的max-size(单文件最大)和max-file(保留文件数)是全局配置,所有容器都会遵守:
max-size: "100m":单个容器的日志文件最大 100MB;max-file: "3":超过 100MB 后,会生成新日志文件,最多保留 3 个(总大小≤300MB / 容器);- 可根据需求调整(比如
"500m"/"5")。
K8S
Docker Compose和Kubernetes(通常简写为k8s)都是用于容器编排的工具,但它们的用途不同,适用于不同的环境。
- Docker Compose是一个工具,允许您定义和运行多个容器的Docker应用程序。它主要用于开发和测试环境,您需要在单个主机上运行多个互连的容器。Docker Compose使用YAML文件定义应用程序所需的服务、网络和卷。
- Kubernetes是一个容器编排平台,自动化部署、扩展和管理容器化应用程序。它设计用于生产环境,在这种环境中,您需要在一个机器集群上运行容器。Kubernetes提供自动扩展、自愈和滚动更新等功能,以确保应用程序的可靠性和可扩展性。
- Docker Compose更适用于本地开发和测试
- Kubernetes更适用于在生产环境中部署和管理容器化应用程序。
Lima
Lima是一个在macOS(以及Linux等系统)上快速启动和管理Linux虚拟机的工具
核心目标是: 为macOS用户提供一个接近无缝的Linux环境,特别专注于运行容器
Lima的主要特点:
自动配置:它自动处理了虚拟机中很多繁琐的配置,比如文件共享(你的 macOS 用户目录会自动挂载到虚拟机中)、端口转发等。
在 macOS 上,由于 Docker 依赖 Linux 内核特性,它无法直接运行。因此,需要一个 Linux 环境作为“底座”。Lima 就是这个“底座”的创建和管理工具之一
- Docker Desktop for Mac:这是 Docker 官方的解决方案。它内部也使用了一个轻量级的 Linux 虚拟机(以前是 HyperKit,现在也可以是 Virtio-FS),但这个虚拟机对用户是隐藏的。你只需要安装 Docker Desktop,就能直接使用
docker命令。- Lima + Docker:这是一种替代方案。Lima 负责创建和管理 Linux 虚拟机,并在其中安装 Docker 引擎。然后,你需要配置你的 macOS 终端,让本地的
docker命令知道如何与虚拟机内部的 Docker 引擎通信(通过设置DOCKER_HOST环境变量)。p.s. 若公司需要避免 Docker Desktop 的许可费用,那么 Lima(或基于 Lima 的 Colima) 是一个非常好的替代方案
模板系统:Lima 提供了多种“模板”,可以一键创建预装了不同容器引擎的虚拟机,例如:
template://docker:创建一个已经安装好 Docker 的虚拟机。template://k8s:创建一个单节点的 Kubernetes 集群。template://podman:创建一个预装 Podman 的虚拟机。
核心是虚拟机:Lima 本身不直接运行容器,它的工作是创建和管理一个轻量级的 Linux 虚拟机(默认使用 QEMU),然后在这个虚拟机里运行你指定的容器引擎。
WSL
WSL(Windows Subsystem for Linux)
WSL 是微软推出的Windows 子系统 Linux,简单说就是在 Windows 系统中直接运行 Linux 环境(无需虚拟机 / 双系统),既能用 Windows 的图形界面,又能调用 Linux 的命令行、工具链和服务,是开发(尤其是 Docker、后端、前端)的核心工具
核心价值
- 无需单独装 Linux 系统 / 虚拟机,Windows 里直接运行
bash/zsh、git/npm/docker等 Linux 工具;- 与 Windows 系统深度集成:可直接访问 C 盘(
/mnt/c)、D 盘(/mnt/d),文件互通;- 性能接近原生 Linux(WSL2 版本),启动速度秒开,资源占用远低于虚拟机。
WSL1 vs WSL2
| 特性 | WSL1 | WSL2(推荐) |
|---|---|---|
| 底层架构 | 翻译层(直接调用 Windows 内核) | 轻量化虚拟机(基于 Hyper-V) |
| 性能 | 文件 IO 快(访问 Windows 盘) | 整体性能高,Linux 兼容性全 |
| 虚拟磁盘 | 无(文件直接存 Windows 目录) | 有(.vhdx 动态扩展虚拟磁盘) |
| Linux 内核特性 | 支持有限(无 Docker 完整功能) | 完整支持(Docker 必须用这个) |
| 存储路径 | %LOCALAPPDATA%\Packages\XXX | 同左(但核心是 .vhdx 文件) |
常用指令
基础管理指令(最常用)
| 指令 | 作用 | 示例(对应你的场景) |
|---|---|---|
wsl --list --verbose |
查看所有 WSL 实例(名称、状态、版本),简写 wsl -l -v | wsl -l -v → 看到你运行中的实例 |
wsl --shutdown |
停止所有 WSL 实例(迁移 / 清理前必做) | wsl --shutdown → 你的实例都会变成 Stopped |
wsl -d <实例名> |
进入指定 WSL 实例的命令行(d=distribution) | wsl -d Ubuntu → 进入 Ubuntu;wsl -d docker-desktop-data → 进入 Docker 数据盘 |
wsl --terminate <实例名> |
停止单个 WSL 实例(比 shutdown 精准) | wsl --terminate docker-desktop-data → 只停 Docker 数据盘 |
wsl --set-default <实例名> |
设置默认进入的 WSL 实例(去掉 * 前缀) | wsl --set-default docker-desktop → 默认进 Docker 实例 |
安装 / 卸载指令
| 指令 | 作用 | 示例 |
|---|---|---|
wsl --install |
一键安装 WSL(默认装 Ubuntu),自动启用 Hyper-V 等依赖 | wsl --install → 新手快速部署 |
wsl --install -d <发行版> |
安装指定发行版(如 CentOS、Debian) | wsl --install -d Debian → 装 Debian |
wsl --unregister <实例名> |
注销 WSL 实例(删除该实例所有数据,释放 C 盘空间) | wsl --unregister docker-desktop-data → 删 Docker 数据盘(迁移前必做) |
迁移 / 备份指令
| 指令 | 作用 |
|---|---|
wsl --export <实例名> <tar路径> |
导出 WSL 实例为 tar 备份文件(迁移前备份) |
wsl --import <新实例名> <存储路径> |
导入 tar 文件为新 WSL 实例(迁移核心) |
高级指令(优化 / 排查)
| 指令 | 作用 | 示例 |
|---|---|---|
wsl --set-version <实例名> 2 |
将 WSL1 实例升级为 WSL2(Docker 必须) | wsl --set-version Ubuntu 2 → 升级 Ubuntu 到 WSL2 |
wsl --help |
查看所有 WSL 指令(忘记指令时用) | wsl --help → 输出完整指令列表 |
optimize-vhd -Path <vhdx路径> -Mode Full |
压缩 WSL 虚拟磁盘(释放未使用空间) | optimize-vhd -Path D:\Docker\WSL\data\ext4.vhdx -Mode Full |
WSL存储机制
所有 WSL2 实例的 .vhdx 虚拟磁盘默认存在:
- 普通发行版(如 Ubuntu):
C:\Users\<你的用户名>\AppData\Local\Packages\<发行版包名>\LocalState\ext4.vhdx; - Docker 专属实例:
C:\Users\<你的用户名>\AppData\Local\Docker\wsl\data\ext4.vhdx(16GB 核心文件);
⚠️ 关键:Docker Desktop 的可视化设置改不了这个路径,只能通过 export/import 指令迁移。





