news 2026/10/5 18:35:20

VMware虚拟机中安装Ubuntu并配置Docker的完整指南与避坑手册

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VMware虚拟机中安装Ubuntu并配置Docker的完整指南与避坑手册

1. 为什么我推荐在虚拟机里装Docker,而不是在Windows上硬啃Docker Desktop

如果你正在Windows上折腾Docker Desktop,被那个"virtualization support not detected"的报错折磨得想把电脑扔出窗外,那这篇文章就是给你的。我把话先说在前面:与其在宿主机上跟虚拟机监视程序、WSL2、Hyper-V这几个东西较劲,不如直接在VMware里装一台Ubuntu虚拟机,然后在Ubuntu里装Docker。这套方案我用了好几年,省心、干净、出问题还能随时回滚。

1.1 Docker Desktop反复报错的那台Windows机器

我见过太多人卡在同一个地方:Docker Desktop在Windows上启动失败,报错提示"Virtualization support not detected"或者"VMware Workstation cannot connect to the virtual machine"。这个问题的根源在于Docker Desktop的Windows版依赖两块底层能力——WSL2或者Hyper-V。你一旦在Windows功能里启用了"虚拟机监控程序平台"或Hyper-V,VMware Workstation会和它抢占同一套虚拟化资源,结果就是Docker Desktop没起来,VMware里的虚拟机也连不上了。

我去年在某台笔记本上实测过,开Hyper-V之后VMware直接报错"无法连接到虚拟机。请确保您有权运行该程序",最后只能关掉Hyper-V才恢复正常。你要知道,Windows上跑Docker不是不可以,但它牵扯太多系统层改动:BIOS里开启VT-x、Windows功能里勾选WSL2、还要处理和VMware/VirtualBox的共存冲突。对于只想学Docker、想尽快把容器跑起来的人来说,这条路实在太绕了。

1.2 虚拟机方案真正的价值在哪

用虚拟机装Ubuntu再装Docker,好处有三点:第一,环境干净,Linux下跑Docker是原生支持,不需要任何翻译层;第二,快照功能太好用,装坏了直接恢复快照,几秒钟回到之前的状态,比在物理机上折腾安全得多;第三,和真实服务器环境对齐,你以后往云服务器上部署,操作方式一模一样,都是Linux命令行,都是systemd管理服务,不会有"Windows上可以,Linux上不行"的割裂感。

特别适合这个方案的人群有三类:刚接触Linux和Docker的新手、需要在干净环境里做各种实验的开发者、以及想在一台Windows电脑里模拟多台服务器做联调测试的运维学习者。这篇文章后面就按我的实操路线走一遍,从虚拟机配置到Docker落地,每一步都附带为什么这样做的解释。

2. 装虚拟机之前的配置:镜像版本、虚拟化开关、资源分配

别急着开机装系统,先把虚拟机平台的配置调好,后面能省掉很多麻烦。特别是VMware里那个"虚拟化引擎"的选项,不少人都没注意到它。

2.1 Ubuntu镜像选服务器版还是桌面版

Ubuntu的长期支持版本现在主流是22.04 LTS和24.04 LTS,选哪个都行,LTS版本有五年维护周期,不会用着用着仓库源就失效。版本不用追新,22.04和24.04对Docker来说完全没有体验差距。

关键分歧在于选桌面版还是服务器版。我的建议:如果你主要是学Docker,选Ubuntu Server版,没有图形界面,资源占用更少,而且命令行的操作习惯和真实服务器完全一致。如果你对Linux完全陌生,离开图形界面心里发慌,那选桌面版也行,反正现在Ubuntu桌面版装了Docker之后一切照常,只是多占几百MB内存。从官网下载iso镜像时注意文件名里的版本标识,arm架构的机器就下arm64的包,x86就下amd64,别下错。

2.2 VMware里被忽略的"虚拟化引擎"选项

创建虚拟机时,在"处理器"配置页面里,有一个"虚拟化引擎"区域,里面有一个选项写着"虚拟化Intel VT-x/EPT或AMD-V/RVI"。这个选项很多教程根本不会提,但对你后面在虚拟机里跑Docker很重要。

勾上它的含义是把宿主机的CPU虚拟化能力再透传给虚拟机,让虚拟机里的系统也认为自己运行在支持虚拟化的硬件上。Docker本身不强制要求嵌套虚拟化,因为它只是利用Linux内核的namespace和cgroup,但如果你后面想在Docker里再跑需要虚拟化支持的软件,或者想在虚拟机里用带硬件加速的工具,这个选项没勾会导致一系列莫名其妙的问题。我的做法很直接:只要是在虚拟机里跑Linux,这个选项永远勾上,无一例外。

还有一个经常出现的坑:如果你在创建虚拟机时提示"此主机支持Intel VT-x,但Intel VT-x处于禁用状态",那是BIOS/固件层面的虚拟化开关没打开。重启电脑进BIOS,找到Intel Virtualization Technology之类字样,改成Enabled,再进系统就好了。搜"vmware无法启用虚拟机平台"能搜到一堆求助帖,基本都是这个问题。

2.3 磁盘和内存怎么分配不后悔

内存方面,Docker本身的守护进程占不了多少资源,但容器镜像多起来、跑起来之后消耗就上来了。虚拟机我建议至少给4GB,8GB更好。如果你的宿主机内存够大,给Ubuntu虚拟机分8GB,同时运行两三个容器不会卡。我有一个跑着Nginx加MySQL加Redis的开发环境虚拟机,内存峰值也就3.5GB左右,所以4GB是底线。

磁盘分配要稍微放开一点。一套完整的Docker环境,光镜像就可能占掉5GB以上,mysql、nginx、redis、python这些常用镜像每个几百MB。加上虚拟机系统本身和日常日志增长,60GB是起步建议,给80GB也不嫌多。VMware的磁盘默认用动态扩展模式,实际占用按需增长,所以"提到80GB"不会真的马上占用你宿主机80GB,放心给。

网络模式这一项,新手先不用纠结太多,默认NAT模式就行,后面我专门有一节讲它的坑在哪。现在,创建虚拟机、挂载Ubuntu iso、装系统,一路默认操作,装完系统后先执行一遍sudo apt update && sudo apt upgrade -y,把系统基础包更新到最新,然后就可以进入Docker的安装环节了。

3. Docker安装:官方源、apt源、自动脚本,我选了哪条路

Ubuntu下装Docker的方式大致有三条:直接用apt装docker.io、配置Docker官方仓库后装docker-ce、或者用Docker官方的一键安装脚本。三条路我全都实际走过,下面直接说结论。

3.1 三种安装方式的对比

先看一张表,把三种方式的特点列清楚:

安装方式版本新鲜度与系统包管理的关系升级维护适合场景
apt install docker.io滞后,跟随Ubuntu发布节奏完全走系统apt体系随系统升级只想随便试试,不关心新特性
官方仓库安装docker-ce最新,Docker发布后同步更新需要额外配置源和GPG密钥独立升级,稳定可控学习、开发、生产都推荐
get.docker.com一键脚本最新自动配置源并完成安装升级仍需处理源快速初始化新机器

很多人会直接执行sudo apt install docker.io,图省事。这个命令确实能装上Docker,但装出来的是Ubuntu仓库里打包的版本,版本号往往比官方版本落后不少。这里特别叮嘱一下:生产环境或者长期学习环境,别用docker.io这个包。有一次我在一台Ubuntu 22.04上贪图省事用了docker.io,之后想用docker compose的新语法,发现Compose插件要么不存在要么版本太老,只能卸载重装,折腾的功夫比一开始配官方源多好几倍。

3.2 官方仓库安装的完整步骤

在Ubuntu上配置Docker官方仓库,核心是添加GPG密钥和软件源描述文件。我按下面这个顺序执行,每一步都验证过:

# 第一步:安装依赖工具 sudo apt update sudo apt install -y ca-certificates curl gnupg # 第二步:创建密钥管理目录(新版Debian/Ubuntu的规范做法) sudo install -m 0755 -d /etc/apt/keyrings # 第三步:下载Docker官方GPG密钥并转为apt使用的格式 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 # 第四步:写入软件源配置 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 第五步:更新软件源并安装 sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

这里解释几个容易困惑的点。第二步创建/etc/apt/keyrings目录,是为了把第三方软件源的GPG密钥统一存放,Ubuntu 22.04之后的版本都建议用这个路径。第三步里的gpg --dearmor作用是把下载的GPG密钥从ASCII格式转换为二进制格式,apt只认这种格式。第四步里的$(dpkg --print-architecture)会自动输出当前系统架构,比如amd64,$(. /etc/os-release && echo "$VERSION_CODENAME")会自动获取系统版本代号,像是jammy或noble,这样就不用手动改文件内容了。

安装的这几个包各有用处:docker-ce是Docker守护进程本体,docker-ce-cli是命令行工具,containerd.io是容器运行时(Docker依赖它来管理容器生命周期),docker-buildx-plugin是构建镜像用的插件,docker-compose-plugin就是现在官方推荐的新版Compose(命令是docker compose,中间有个空格,不是老版本的docker-compose)。

3.3 安装完成后根据系统状态做验证

装完先别急着跑容器,确认一下守护进程的状态。

# 查看docker服务状态 sudo systemctl status docker # 如果没启动,手动启动并设置开机自启 sudo systemctl enable --now docker # 查看版本信息 sudo docker version

systemctl status docker如果显示active (running),说明守护进程已经起来了。enable --now这条命令把开机自启动和立即启动一步做完,虚拟机关机再开机后Docker会自动运行,不需要每次手动启动。docker version会同时显示客户端和服务端版本,如果只显示Client没显示Server,多半是守护进程没起来,先回去看status。

如果你实在不想一步步配置源,可以用一行脚本安装:

curl -fsSL https://get.docker.com | bash

这个脚本会自动识别Ubuntu版本,配置Docker官方源并完成安装。我建议初次学习还是手动走一遍源配置流程,因为你能搞清楚每一层在干什么,出问题也知道去哪排查。脚本方式适合你已经懂了原理、但想在新环境快速重建的时候用。

4. 安装只算完成一半:镜像加速、免sudo、基础验证

Docker装好了,如果直接开始拉镜像,大概率会遇到镜像下载慢或者超时的问题。这也是为什么我说安装只算一半——后面这三件事不做,你的体验会非常劝退。

4.1 镜像加速源:安装后第一件事

Docker默认从官方仓库拉取镜像,在国内网络环境下速度很不稳定。解决方法是配置镜像加速源。编辑(如果没有就新建)/etc/docker/daemon.json文件:

sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker

配置完成后,docker pull就会走加速源拉取镜像。你也可以在阿里云容器镜像服务控制台里申请一个专属加速地址,格式类似https://<你的ID>.mirror.aliyuncs.com,把自己的地址填进registry-mirrors数组里也行。这个文件是JSON格式,多个加速地址用逗号分隔,格式错了Docker守护进程会启动失败,所以每次改完都要执行systemctl daemon-reload再restart docker。

4.2 sudo不用每次都敲:用户组和权限

默认情况下,执行docker ps、docker run这些命令需要root权限,每次都要敲sudo很烦。原因是Docker的守护进程监听在/var/run/docker.sock这个Unix套接字上,默认只有root和docker组的用户才能访问。

把自己加入docker组,重新登录后就不用再敲sudo了:

sudo usermod -aG docker $USER # 关键:需要重新登录或执行newgrp命令才能生效 newgrp docker

这里有个安全细节要提醒你:加入docker组等于拥有了和root等同的权限,因为你可以通过docker run -v /:/host ...把宿主机目录挂载进容器,从而以root身份读写宿主机文件。这在个人学习虚拟机里无所谓,但如果你在真实的多用户服务器上,给用户分配docker组权限要慎重。我是建议在虚拟机里直接加组,图省事,因为这台机器本身就是你的试验场。

4.3 开机自启和基础验证

再确认一遍开机自启已经设置好:

sudo systemctl enable docker

前面已经执行过enable --now的话,这里会提示已经存在,不用管。接下来用最经典的镜像做验证:

docker run hello-world

正常情况下会拉取镜像并打印一段欢迎信息,告诉你Docker已经能正常工作。如果这一步卡住很久,多数还是镜像加速的问题,回到4.1检查daemon.json配置和网络连通性。如果提示permission denied,说明当前用户不在docker组,回到4.2重新登录再试。

做完这一步,一套"能用的Docker环境"就算彻底就绪了。但虚拟机环境里跑容器,后面还有几个高频坑等着你踩。

5. 虚拟机里跑容器最常踩的三个坑:端口映射、挂载权限、防火墙

这一节的内容是我在虚拟机里跑容器反复踩过、花了大量时间排查才搞明白的地方。提前看完,你至少能少走两天弯路。

5.1 NAT模式下端口映射:外部访问不到容器的解法

VMware默认的网络模式是NAT,虚拟机通过共享宿主机IP来访问外网,但反过来,从宿主机或者局域网其他机器访问虚拟机里的服务,就没那么顺畅了。

场景是这样的:你在Ubuntu虚拟机的Docker里跑了一个Nginx容器,做了-p 8080:80端口映射。在虚拟机里用curl http://localhost:8080访问完全正常,但在宿主机的Windows浏览器里输入http://localhost:8080却连不上。

原因在于NAT模式下,宿主机访问虚拟机IP需要经过VMware的虚拟网卡转发,而容器端口映射到的是虚拟机的网络命名空间,外面的流量进不来。解决办法有三个:一是把虚拟机网络改成桥接模式,让虚拟机拿到和宿主机同一网段的独立IP,然后在Windows浏览器直接访问那个IP加端口;二是在VMware的"虚拟网络编辑器"里给NAT模式添加端口转发规则,把宿主机的某个端口转发到虚拟机的对应端口;三是用SSH端口转发,ssh -L 8080:localhost:8080 user@虚拟机IP,把宿主机端口映射到虚拟机本地端口。

我最常用的还是桥接模式。改桥接只需要在虚拟机设置里把网络连接从NAT改成桥接,然后进入Ubuntu重新获取IP即可。桥接模式的好处不仅是端口访问方便,虚拟机之间的通信也走真实局域网,更接近真实服务器环境。要注意的是,桥接模式下虚拟机的IP是局域网动态分配的,如果用固定IP习惯,建议在Ubuntu的网络配置里绑定静态IP,免得重启后IP变了还要到处找。

5.2 文件挂载权限错乱:宿主机目录和容器目录的所有权冲突

挂载目录是Docker的高频操作,出现问题也最高频。最常见的是你把宿主机的某个目录挂载进容器后,容器里读写这个目录时权限错乱。

举个例子,我在虚拟机里做了这样的挂载:

docker run -d -p 8080:80 \ -v /home/ubuntu/nginx-html:/usr/share/nginx/html \ nginx

然后在宿主机里往nginx-html目录放网页文件,发现Nginx显示403 Forbidden。排查后发现,宿主机的nginx-html目录属主是ubuntu用户(uid=1000),但容器里的Nginx以root身份运行,读取文件没问题,写入会有冲突;反过来如果容器里创建的文件的属主是root(uid=0),在宿主机上就会显示成root所有,普通用户想改文件还得加sudo。

解决办法是保持宿主机的目录权限和容器内进程的用户一致。Nginx容器提供了环境变量NGINX_UID和NGINX_GID,可以直接指定运行用户,不过我更喜欢简单粗暴的chown:

sudo chown -R 1000:1000 /home/ubuntu/nginx-html

这样容器和宿主机都用uid 1000的文件属主,冲突就没了。所以每次做目录挂载前,先想想:容器内进程以什么用户运行?宿主机的目录权限要让谁方便读写?想清楚这两点,权限问题基本不会出现。

5.3 防火墙和Docker的"私人恩怨"

在Ubuntu虚拟机里跑容器,如果发现端口映射怎么都不生效,检查一下是不是开启了防火墙。

Docker的端口映射原理是直接操作iptables规则,把宿主机端口转发到容器的IP。但如果你在Ubuntu里启用了ufw(Uncomplicated Firewall),ufw默认策略会挡住转发链的流量,Docker发布的端口就会从外部无法访问。这个问题在物理机和云服务器上很常见,在虚拟机里同样会遇到。

我的建议是在虚拟机学习环境里,直接不要开启ufw:

sudo systemctl disable --now ufw

如果你确实需要防火墙,那就得理解Docker和iptables的协作方式,不盲目禁用,但这属于进阶话题,新手阶段建议先把防火墙关掉,把环境跑通再考虑安全加固。这里特别提示:不要随便在daemon.json里加"iptables": false,那会导致容器网络彻底乱掉,我试过一次,最后重启Docker才恢复。

还有一个容易忽略的坑是容器时区。默认容器是UTC时间,date命令显示的时间和宿主机差了8小时。解决方式很简单,在docker run时加环境变量:

docker run -d -e TZ=Asia/Shanghai nginx

或者用docker-compose时在服务配置里写:

environment: - TZ=Asia/Shanghai

这些坑看着不大,但在实际使用中每一个都能让人排查半天。

6. 用docker compose把Nginx和MySQL跑起来:一次完整实践

光谈理论没意思,最后我用一个实际项目来收尾——用docker compose一次性启动Nginx和MySQL,这也是热搜词里出现频率很高的组合。

6.1 定义compose文件

在工作目录创建docker-compose.yml:

services: nginx: image: nginx:1.26 container_name: web-nginx ports: - "80:80" volumes: - ./html:/usr/share/nginx/html - ./nginx/conf.d:/etc/nginx/conf.d environment: - TZ=Asia/Shanghai restart: unless-stopped mysql: image: mysql:8.0 container_name: web-mysql ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: root123456 TZ: Asia/Shanghai volumes: - mysql-data:/var/lib/mysql restart: unless-stopped volumes: mysql-data:

这个文件有几个值得说明的设计。nginx服务的./html目录挂载进去,意味着你在宿主机上放网页文件,容器里立即生效。./nginx/conf.d目录挂载进去,可以在宿主机上添加站点配置文件,实现多站点自定义域名配置的效果,这正好对应热搜词里"本地+虚拟机多端口Nginx开发环境多站点自定义域名配置"的场景。mysql的数据卷用命名卷mysql-data,数据持久化在虚拟机磁盘上,容器删了重建数据还在。

restart: unless-stopped的意思是容器意外退出时自动重启,但手动stop掉的不会强行拉起。这个策略最适合开发环境。

6.2 启动、验证、清理

执行启动命令:

docker compose up -d

第一次启动会拉取Nginx和MySQL镜像,等待时间取决于网络和镜像加速效果。启动完成后:

docker compose ps docker ps

看到两个容器状态为Up,就说明跑起来了。验证服务:

curl http://localhost curl http://localhost:3306

第一个命令会返回Nginx的默认页面内容。第二个命令如果端口通,会收到MySQL协议的错误信息,这也算验证通过。需要看容器日志排查问题就用:

docker logs web-nginx docker logs web-mysql

MySQL容器第一次启动时,日志里有Temporary password is generated之类的提示。另外要提醒一句:MySQL 8.0在容器里的初始化和认证方式有些细节和5.7不同,如果遇到客户端连接不上,多半是认证插件问题,在创建用户时用mysql_native_password插件可以解决。

用完可以随时docker compose down,容器停了但数据卷还在;连数据一起清理才用docker compose down -v,这个命令会删掉mysql-data卷里所有数据,执行前一定确认没有重要数据。

最后说一个我一直沿用的实操心得:在虚拟机上装Docker,最值钱的功能就是"快照"和"克隆"。每次配置好一套干净环境后,拍一个快照再继续折腾,一旦把系统搞挂,恢复快照分分钟回到配置完美的状态。你可以把装上Docker的这台虚拟机保存为一个模板,以后想新开环境时直接克隆,几分钟就得到一台新机器,比从零安装Ubuntu再装Docker快得多。这套"虚拟机加Docker"的开发方式,我在本地用了很久,它最大的优势是:无论你怎么折腾,宿主机Windows永远安全,而且错了随时推倒重来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 18:30:15

Scala环境搭建实战:版本选择、JDK配置与IDEA集成指南

写这篇文章的起因很简单&#xff1a;最近帮两个同事分别配了 Scala 开发环境&#xff0c;一个卡在版本选择&#xff0c;一个卡在 IDEA 里怎么都识别不了 Scala SDK。这事看着不起眼&#xff0c;真踩起坑来能浪费一下午。所以我把这次的完整过程——从 scala-2.12.15 和 IDEA202…

作者头像 李华
网站建设 2026/10/5 18:28:59

计算机网络综合题怎么复习?从TCP/IP协议栈到子网划分的实战拆解

简介&#xff1a;这是一份面向计算机网络课程期末复习、考研备考及网络工程实践的《计算机网络综合题》文档资料&#xff0c;由作者oligaga整理。内容以典型综合应用题为主&#xff0c;系统覆盖IP地址二进制与十进制换算、IP地址类别判断、子网掩码计算、无子网划分时主机号求解…

作者头像 李华
网站建设 2026/10/5 18:01:27

HDMI 2.0切换芯片IT66341设计指南:HDCP 2.2与CEC调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/5 17:55:11

基于Node.js与React构建能思考与行动的AI智能体实战

1. 项目缘起&#xff1a;为什么我要用 paperclip 把 AI 智能体接到真实工作流里第一次看到paperclip这个词&#xff0c;很多人脑子里蹦出来的可能是办公桌上那枚弯弯的金属夹子。但在 Node.js 和 React 的圈子里&#xff0c;它指的是一类很具体的东西&#xff1a;一个把 AI age…

作者头像 李华
网站建设 2026/10/5 17:50:58

yolov5单目测距系统毕设拆解:从A4标定到误差量化

简介&#xff1a;这份资源是经导师指导并获98分认可的毕业设计项目&#xff0c;围绕YOLOv5实现单目测距系统&#xff0c;面向计算机相关专业正在做毕设、课程设计或期末大作业的学生&#xff0c;也适合需要项目实战练习的学习者。项目已通过严格调试&#xff0c;可直接作为毕设…

作者头像 李华