Ubuntu虚拟机安装Docker,这套组合我估计是大多数后端和运维同学碰到的第一套完整开发环境。在Windows笔记本上开一个VMware虚拟机,里面装Ubuntu,再装Docker,听起来简单,但真正操作下来会发现不少坑——虚拟化嵌套、网络模式选错、镜像拉不动、容器起不来、docker组权限,每一步都可能卡住半个小时起步。这篇文章把我实操过几十次的经验整理成一套完整方案,从创建虚拟机开始,到Docker跑起来、能拉镜像、能对外提供服务,再到最常见的故障排查,一条线讲透,适合刚入门Linux和容器的同学,也适合装完一遍还想优化配置的兄弟参考。
1. 环境准备:为什么优先选虚拟机方案
1.1 需求和场景拆解
先说清楚这套方案解决什么问题。你手头如果是一台Windows电脑,又需要在Linux环境下玩Docker,通常有两条路。一条是直接用Docker Desktop,Windows版本天然集成WSL2或Hyper-V,装完就能用,体验很顺滑。另一条就是虚拟机方案:把VMware或VirtualBox打开,装一个Ubuntu,在Ubuntu里装Docker。
为什么我优先推荐后者?最核心的原因是生产环境一致性。Docker官方文档里写得很明白,容器内进程跑的是Linux内核的系统调用,Windows上的Docker Desktop本质是借助WSL2或Hyper-V虚拟出一套Linux内核再跑容器。而虚拟机方案装的是完整Ubuntu系统,Docker以原生方式跑在真实Linux内核上,行为和生产服务器完全一致,调试出的网络、存储、权限问题,换到服务器上大概率也能复现同样的状态。对需要学习Docker技术细节、或者公司生产环境就是Linux的人,这种一致性价值很高。
另一个实际原因是资源占用。Docker Desktop的WSL2后端会常驻一个不小的虚拟机内存占用,对8GB内存的笔记本来说压力不小。而虚拟机里跑原生Docker,Ubuntu精简配置后可以控制在2GB内存左右,反而更轻。再加上Docker Desktop对大企业有商用授权问题,虚拟机方案完全没有这个顾虑。
1.2 虚拟化平台选型与对比
虚拟化平台我实测过三个:VMware Workstation Pro、VirtualBox、Hyper-V。简单对比一下:
| 平台 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| VMware Workstation Pro | 性能好、网络模式灵活、快照功能强、3D加速完善 | 软件体积大、旧版收费(新版本已面向个人免费) | 长期开发主力环境 |
| VirtualBox | 免费开源、跨平台、轻量 | 性能略逊于VMware、网络偶有坑、快照功能一般 | 临时用、预算敏感的个人学习 |
| Hyper-V | Windows内置、性能好、和系统结合深 | 需要开通系统功能、和VMware/VirtualBox冲突、管理界面不够直观 | 纯Windows环境、追求原生性能 |
单说个人的使用感受,最省心的是VMware Workstation Pro。它的NAT模式很成熟,默认情况下虚拟机可以直接上网,不需要额外配置。快照功能也是救命的:装了Docker基线环境后打一个快照,后面折腾坏了随时回滚,比重复装系统效率高太多。如果你用的是Windows 10/11专业版或以上,也可以考虑Hyper-V,但注意它和VMware不能同时开启,装过VMware的机器再开Hyper-V容易报错,需要二选一。
1.3 Ubuntu版本选择与硬件分配建议
Ubuntu版本我只推荐LTS(长期支持版)。当前常用的LTS是22.04和24.04,前者稳、各种教程最多,后者更新、内核版本更高。我的建议是:如果你的任务只是学习Docker和容器编排,选22.04就够用,网上能搜到的坑和解决方案几乎全匹配;如果涉及新硬件驱动或需要较新内核特性,再考虑24.04。不要装非LTS的中间版本,折腾的意义不大。
虚拟机硬件分配方面,给出我实测过的下限和推荐值:
- 内存:Ubuntu桌面版建议4GB起步,服务器版(不带桌面)2GB即可,容器多开时按需加到6-8GB。
- CPU:2核是基础,Docker编译或跑多容器时4核更稳。
- 磁盘:系统盘20GB起步,Docker镜像和容器日志吃空间很快,建议直接分配40-60GB。
- 网络:默认NAT即可,后面需要局域网访问再改桥接。
另外要注意一个关键选项:嵌套虚拟化。VMware创建虚拟机时在“处理器”设置里有一项“虚拟化Intel VT-x/EPT”,默认是关闭的。Docker本身不依赖硬件虚拟化所以能跑,但如果你以后想在虚拟机里再跑KVM、Android模拟器、或者嵌套启动其他虚拟化工具,就必须开启这个选项。建议创建时直接打开,免得后面踩坑。
2. Ubuntu虚拟机安装与基础初始化
2.1 创建虚拟机并安装Ubuntu系统
创建虚拟机我用VMware Workstation示范,其他平台思路一致。
第一步,打开VMware,选择“新建虚拟机”,向导选“典型(推荐)”就好。安装来源选“安装程序光盘映像文件(iso)”,指定Ubuntu镜像路径。Ubuntu镜像从官网下载即可,如果下载速度不理想,清华、阿里、中科大等高校和云厂商的镜像站点都有同步,下载ISO的校验值最好比对一下。
第二步,设置虚拟机名称和存储位置。存储位置不要放在C盘系统盘,装到D盘或数据盘,避免Windows系统重装或磁盘空间不足时殃及虚拟机。
第三步,指定磁盘大小。这一步建议直接给到60GB——别觉得浪费,Docker镜像、容器数据卷、日志文件占空间的速度比你想象中快得多。勾选“将虚拟磁盘存储为单个文件”,性能略优于拆分多个文件。
创建完成后不要急着开机,先编辑虚拟机设置:内存调到4GB,处理器给2核,网络适配器保持NAT,最后在“处理器”里勾选“虚拟化Intel VT-x/EPT”。然后开机。
Ubuntu安装过程比较直接。启动后选择“Install Ubuntu”,语言建议选English,避免后面终端操作时中文路径和locale问题。键盘布局按实际情况选。安装类型选“最小安装”即可——装完是纯净系统,桌面环境自带但不臃肿,Docker开发完全够用。磁盘分区直接选“擦除磁盘并安装Ubuntu”,虚拟机嘛,不用整太复杂。用户名、密码、主机名按自己习惯设置。等待安装完成重启。
2.2 系统基础配置:更新、换源、常用工具
装完系统第一件事不是装Docker,而是把系统基础配置好。uninstall install走一遍:
sudo apt update && sudo apt upgrade -y这里有个实操建议:Ubuntu默认的源是官方源,在国内虚拟机环境下载速度可能很慢,建议先换国内镜像源再更新。怎么判断该不该换?执行一下sudo apt update,如果速度能接受就继续用官方源,要是半天不动,就换。
Ubuntu 22.04及之前版本,软件源文件是/etc/apt/sources.list;24.04开始改为/etc/apt/sources.list.d/ubuntu.sources。对应的替换命令:
# Ubuntu 22.04 sudo sed -i.bak -e 's|http://archive.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list # Ubuntu 24.04 sudo sed -i.bak -e 's|http://archive.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list.d/ubuntu.sources提示:
-i.bak会在原文件旁生成一个.bak备份,万一替换出错可以快速恢复。这个习惯建议保留到所有需要改配置文件的场景,操作前先备份是专业习惯。
换源后再执行一次sudo apt update,你会明显感觉到快了很多。接着装几个后面会用到的工具:
sudo apt install -y curl ca-certificates gnupg lsb-release这几个包是Docker官方安装教程里明确要求的依赖,提前装好后面少一步。其他像vim、git这类用顺手就装,不影响主线。
2.3 虚拟机网络模式选择:NAT还是桥接
虚拟机网络配置选错了,后面Docker联网排查时非常折磨。先理解三种模式的本质区别:
- NAT模式:宿主机做网段转换,虚拟机能上网,但外部设备无法直接访问虚拟机的IP。优点是不依赖物理局域网环境,随便换网络都能用;缺点是局域网其他设备进不来。
- 桥接模式:虚拟机就像局域网里的另一台物理设备,有独立IP,外部设备可通过该IP直接访问。优点是对外访问方便;缺点是IP依赖路由器的DHCP分配,换了网络环境IP会变。
- 仅主机模式:虚拟机只能和宿主机通信,不能访问外网。适合做完全隔离的环境,一般不用于日常开发。
我个人建议先用NAT模式。Docker拉镜像、容器访问外网都不受影响,虚拟机自己的IP固定,折腾起来可控。等你把Docker容器跑起来、想让局域网里的手机或服务器访问容器时,再切换到桥接模式也不迟。切换方式:VMware菜单“虚拟机—设置—网络适配器”,改为桥接模式重启即可。
3. Docker CE安装全流程
3.1 安装方式选择:仓库安装优于官方脚本
Docker官方提供两种主流安装方式:一键脚本curl -fsSL https://get.docker.com | sh,和通过官方APT仓库安装。很多人图省事直接用脚本,但我更推荐仓库安装,原因有三点:
第一,脚本安装会帮你做很多隐式操作,虽然快但在公司内部或离网环境不可控;第二,仓库安装可以明确看到安装的是哪些包、版本是多少,后续升级管理都很清晰;第三,Docker仓库装的是docker-ce(社区版)整套组件,包括docker-ce-cli、containerd.io、docker-buildx-plugin、docker-compose-plugin,比脚本装的组件更完整,尤其docker compose现在是日常开发刚需。
Ubuntu系统装Docker,本质上就是三步:添加GPG密钥、添加APT源、更新并安装。下面按最新官方流程走一遍。
3.2 添加Docker官方GPG密钥与APT源
先创建密钥存放目录并导入官方GPG密钥:
sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg解释一下这三步在干什么。第一步创建目录,专门存放第三方软件的GPG公钥;第二步把Docker官方公钥从网络下载后,通过gpg --dearmor转为二进制格式并写入文件,APT通过该密钥校验下载的软件包是否真的来自Docker官方;第三步修改权限,确保系统所有用户都能读取密钥。
接下来添加APT源。这里有一个关键细节:命令里用到了$(lsb_release -cs),它会自动获取当前Ubuntu的发行代号。22.04对应jammy,24.04对应noble,不同代号对应不同软件包仓库地址,自动获取比手动填写更不容易出错。
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null3.3 安装Docker组件并启动验证
执行更新并安装:
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin安装完成后启动Docker服务,并设置开机自启:
sudo systemctl enable --now docker检查服务状态:
systemctl status docker状态显示active (running)就说明服务正常。接着运行官方验证镜像:
sudo docker run hello-world这条命令会从Docker Hub拉取一个最小的hello-world镜像,并在容器里打印一段提示。看到那句Hello from Docker!就说明Docker安装成功,拉取、创建、运行容器的全链路都没问题。
再确认一下版本和组件:
docker --version docker compose version到这里Docker装好了。但每次用docker都要打sudo很烦对不对?可以把你当前的用户加入docker用户组,之后免sudo使用docker命令:
sudo usermod -aG docker $USER注意:执行完直接重开终端或者重新登录用户才生效。你可能会遇到明明加了组但依然提示权限不足,多半是因为没有退出重新登录。另外,把用户加入docker组,相当于给了该用户操作Docker的完整权限,在个人开发机上没问题,服务器上要谨慎操作,有权限安全风险。
4. 虚拟机环境下Docker的进阶配置
4.1 Docker镜像加速配置
Docker装好了,但拉镜像慢或者拉不动,才是真实世界最常见的问题。Docker Hub官方仓库在国外,国内直连速度容易不理想。解决方案是配置镜像加速地址——本质上是让Docker从国内公共的镜像仓库拉取缓存过的镜像层,会明显提速。
配置在/etc/docker/daemon.json文件里。通常该文件不存在,直接创建:
sudo mkdir -p /etc/dockersudo vim /etc/docker/daemon.json写入:
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.1ms.run", "https://docker.mirrors.ustc.edu.cn" ] }提示:不同加速地址可用状态会随时间变化,配置后执行
sudo systemctl restart docker再docker info,在输出里查看Registry Mirrors字段确认配置生效。如果某个地址拉镜像时报错,把对应的行删掉换一个即可。
这里我补充一个经验:镜像加速只是缓解拉取慢的问题,对于企业内网或需要稳定拉取镜像的环境,更稳妥的是在服务器上搭建私有镜像仓库(Harbor或Registry),把常用镜像提前推送到私有仓库。不过那是后话,学习阶段配置公共加速器完全够用。
4.2 Docker数据存储路径迁移
默认情况下,Docker所有数据都存放在/var/lib/docker,包括镜像、容器、数据卷、日志。在虚拟机场景下,这个路径位于系统盘内。前面我建议把虚拟机磁盘分60GB,但如果你当时的磁盘分配不够,容器一多很快就满了。
这时候需要把Docker的数据目录迁移到独立挂载点的数据盘。操作前要明确:停服务、迁移数据、改配置、启服务,四步不能乱。
# 1. 停止docker服务 sudo systemctl stop docker # 2. 迁移原数据目录到新位置 sudo rsync -avz /var/lib/docker/ /data/docker/ # 3. 修改daemon.json,指定data-root sudo vim /etc/docker/daemon.json修改后的daemon.json:
{ "data-root": "/data/docker" }然后启动服务验证:
sudo systemctl start docker docker info | grep "Docker Root Dir"输出变为/data/docker即迁移成功。实际操作中如果原来的镜像很多,迁移过程可能比较久,耐心等。迁移完成后确认一切正常,再删除/var/lib/docker下的旧数据,避免双份占用空间。
4.3 Docker Compose与容器资源限制配置
装完Docker,下一个最常见的需求就是通过docker compose管理多容器项目。得益于我们上面安装的是完整组件,docker compose已经自带。写一个简单的Nginx加Redis的组合,试试compose的编排能力:
version: "3.8" services: web: image: nginx:1.25-alpine container_name: web-demo ports: - "8080:80" restart: always cache: image: redis:7-alpine container_name: cache-demo command: redis-server --requirepass "yourpass" restart: always保存为docker-compose.yml,在同目录执行:
docker compose up -ddocker compose ps查看状态,然后浏览器访问http://虚拟机IP:8080,能看到Nginx欢迎页。这个示例里我做了几处有代表性的配置:restart: always表示开机自启时容器也会跟着起来;端口映射把宿主机的8080转到容器80;Redis通过command指定密码。
在虚拟机环境里,还要给单个容器做资源限制,避免多个容器把虚拟机内存打满:
docker run -d --name nginx-limit --memory 512m --cpus 0.5 nginx:1.25-alpine--memory限制容器最大内存512MB,--cpus限制最多使用0.5核CPU。容器里跑Java、跑数据库这类吃内存的应用时,这个参数基本必加,否则OOM时可能导致整个虚拟机卡死。
5. 常见问题排查与避坑总结
5.1 Docker启动失败问题集合
我把实际环境中遇到最多的问题整理成一张速查表,方便对照排查:
| 现象 | 原因 | 解决方案 |
|---|---|---|
Cannot connect to the Docker daemon | docker服务未启动 | 执行sudo systemctl start docker |
Job for docker.service failed because ... address already in use | 端口被占用,多因本机装了其他容器运行时或端口冲突 | 执行`sudo ss -lnp |
Failed to start Docker ... iptables failed | 系统iptables规则异常 | 重启系统或执行sudo systemctl restart docker,仍失败则检查内核模块 |
docker: permission denied while trying to connect to the Docker daemon socket | 当前用户不在docker组 | 执行sudo usermod -aG docker $USER并重新登录 |
Get "https://registry-1.docker.io/v2/": net/http: request canceled | 网络问题导致拉取镜像超时 | 配置镜像加速,或检查虚拟机DNS |
第一个问题最坑的地方在于:有时候你看到docker已经通过systemd启动了,但是执行docker ps依然报连接不上。这时候先看环境变量里有没有DOCKER_HOST指向了不存在的地址:
env | grep DOCKER如果设置了DOCKER_HOST,unset DOCKER_HOST清掉再试,很可能就是之前装Docker Desktop或其他工具留下的环境变量残留。
5.2 容器网络不通排查思路
容器网络问题几乎是Docker学习中必踩的坑。典型症状包括三种:容器里ping不通外网、容器可以上网但宿主机访问不了容器端口、宿主机能访问端口但局域网其他设备进不来。
第一种,容器内访问不了外网。在运行中的容器里执行ping baidu.com,不通则按顺序排查。先看虚拟机本身能不能上网,ping 8.8.8.8,如果虚拟机就不通,那是虚拟机的网络问题,走NAT模式检查VMware网络服务;如果虚拟机通而容器不通,大概率是Docker的iptables转发规则被破坏了,重启docker服务试试:
sudo systemctl restart docker还不行就检查内核IP转发是否开启:
sysctl net.ipv4.ip_forward输出应为1,若不是,用echo 1 > /proc/sys/net/ipv4/ip_forward临时开启,再写入/etc/sysctl.conf持久化。
第二种,宿主机访问不了容器端口。检查端口映射是否在运行容器时加了-p参数,容器是8000:80还是127.0.0.1:8000:80——后者只能本机访问。执行docker port <容器名>查看实际映射情况。
第三种,局域网其他设备访问不了虚拟机里的容器。核心在于虚拟机网络模式是NAT还是桥接。NAT模式下宿主机之外的设备本来就不该直接访问,要么切换到桥接模式,要么在宿主机做端口转发。改桥接后注意虚拟机的IP会变化,用ip addr查看当前IP。
5.3 磁盘空间暴涨与日志抢占磁盘
Docker跑久了磁盘动不动占满,这是虚拟机场景里最容易忽略的坑。常见元凶有三个:悬空镜像、停止的容器、容器日志。
docker system df可以直观查看空间占用。清理命令:
docker system prune -a --volumes docker logs --tail 50 <容器名>docker system prune会清掉所有未被使用中的镜像、停止的容器、未命名的数据卷和构建缓存,在开发机上是安全操作,但执行前还是要确认没有正在使用中的数据卷。日志方面,最有效的方法是在daemon.json里配置日志轮转:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }这条配置限制单个容器日志最多3个文件、每个文件10MB,配合restart docker后对后续新容器生效。要知道一个不配日志轮转的容器,跑一个高并发的Nginx应用,一晚上产生的日志就能把磁盘塞满。
5.4 与Docker Desktop、其他虚拟化工具的冲突
这个坑只有在Windows宿主机上才会遇到,但我猜看到这篇文章的大多数人正是这种情况。
如果本机装过Docker Desktop,再在VMware里折腾Docker,容易出现奇怪现象:虚拟机里执行docker正常,但VMM对虚拟化的支持异常;或者VMware启动时提示“此主机支持Intel VT-x,但Intel VT-x处于禁用状态”。
排查原则有三条。第一,确认BIOS/UEFI中虚拟化已开启,可以在Windows任务管理器—性能—CPU里看“虚拟化”状态;第二,Docker Desktop基于WSL2/Hyper-V,如果启用了Hyper-V,VMware和它不能共存,需要关闭Hyper-V相关功能再使用VMware;第三,尽量在VMware里开启嵌套虚拟化(VT-x选项),让虚拟机内的Docker和WSL都工作更顺畅。
我在自己机器上实测的组合是:Windows 11宿主机 + VMware Workstation,关闭Hyper-V,VMware处理器设置中开启虚拟化引擎,Ubuntu 22.04 + Docker CE。这套组合运行非常稳定。如果你有强依赖Hyper-V的需求,那虚拟机方案就得让步,回到Docker Desktop。
最后聊几句实操体会
整理这套教程时我有个很深的感触:Docker安装本身不复杂,复杂的全在环境认知。很多报错根本原因不是Docker的问题,而是虚拟化嵌套、网络模式、系统源、资源分配这些东西。所以我建议,装环境时不要急着一步跑通,每完成一个阶段就打一个虚拟机快照——刚装完系统时打一个,Docker装好验证通过时再打一个。后面随便折腾坏了,几分钟回到干净状态,比重新装一遍系统快得多。
还有一个小习惯分享给你:每天结束工作前跑一下docker system prune,并定期看一眼docker system df,能避免绝大多数磁盘占满事故。容器环境不像传统应用,它的临时文件、悬空镜像、积压日志都是隐形的磁盘杀手,提前清理比事后补救轻松太多。
这套环境装好后,你完全可以继续往里面折腾:用Docker Compose搭一套Nginx反向代理加多个站点,跑一个MySQL 8加Redis做本地开发,甚至用Portainer给虚拟机加一个可视化管理界面。Docker这东西,跑起来才是第一步,关键在于敢折腾、会排查。