
在VMware虚拟机里装Ubuntu 22.04然后把这个环境配置成Docker的运行温床是我这些年折腾开发环境时走得最顺的一条路。别急着直接apt install docker中间有不少坑——VMware服务连不上、镜像拉取慢到怀疑人生、用户组权限没配好导致每条命令都要sudo这些我都踩过。这篇博文把我从零到能跑起MySQL 8.0和Redis主从的完整过程梳理一遍尽量把每个选择背后的原因也讲清楚方便你直接照着走也能理解为什么这么配。1. 环境准备VMware与Ubuntu 22.04系统的搭建要点1.1 为什么坚持用VMware跑Docker而不是直接装双系统或WSL2首先想聊聊方案选型。2025年的当下在Windows上跑Linux环境的选择其实不少很多人会直接推荐WSL2但我个人建议如果打算长期用Docker做开发或学习集群编排VMware Workstation Pro仍然是最稳的选择。原因有三点。第一WSL2虽然启动快、集成好但它的网络模式、systemd支持和磁盘IO在某些场景下跟完整虚拟机有差异。尤其是Docker里要跑一些需要复杂端口映射、多容器互通甚至挂载物理磁盘的场景WSL2偶尔会出现docker desktop和wsl2之间的资源争抢问题。而VMware的虚拟机是一个完整的、隔离的Linux环境出现网络问题更容易排查。第二VMware Workstation Pro对个人用户已经是免费使用的状态VMware 17的许可证密钥在官网登记后即可获取不存在版权风险。相比之下一些第三方精简版虚拟机工具反而可能捆绑广告或后门。第三虚拟机最大的优势是可以随时打快照。我一般在装完系统、配好Docker之后立刻拍一个快照之后不管容器怎么折腾、数据怎么污染一条命令就能回到干净状态。WSL2虽然也能导出tar包但恢复流程远不如快照来得直接。1.2 VMware Workstation创建虚拟机时的几个关键参数创建虚拟机是第一步很多新手在这一步就埋下了后续性能问题的隐患。我通常按以下参数来配置配置项推荐值说明操作系统类型Ubuntu 64位必须选64位32位不支持新版本内核内存最少4GB推荐8GBDocker跑多个容器时内存吃紧8GB比较舒服处理器2核起步推荐4核编译镜像时多核优势明显磁盘40GB以上建议60GBDocker镜像和容器日志会快速占满磁盘网络模式NAT模式最稳虚拟机可上网且不占用局域网IP虚拟化引擎勾选VT-x/AMD-V在“虚拟化Intel VT-x/EPT”前打勾否则Docker性能很差这里要特别说明一下虚拟化引擎的坑。如果在处理器设置里没有勾选“虚拟化Intel VT-x/EPT”选项Docker虽然能装但在运行时会频繁报出性能警告部分依赖硬件虚拟化的容器可能直接启动失败。出现这种情况时需要进入物理机的BIOS把Intel Virtualization Technology开关打开然后重启VMware才能看到这个选项。1.3 VMware无法连接到虚拟机的常见原因处理热搜词里有“vmware workstation 无法连接到虚拟机。请确保您有权运行该程序、访问该程序使用”这一条这几乎是我见过最多的VMware报错尤其发生在新建虚拟机后启动的瞬间。这个报错的根源绝大多数情况是Windows的Hyper-V与VMware冲突。因为Windows自带的Hyper-V和内核隔离功能会占用VT-x虚拟化资源导致VMware无法正常启动虚拟机。解决方案有三种按推荐顺序来第一种关闭Windows功能里的Hyper-V。打开“控制面板 - 程序 - 启用或关闭Windows功能”取消勾选Hyper-V、Windows虚拟机监控程序平台、虚拟机平台这三项然后重启。注意这个操作会影响WSL2的正常使用如果你同时依赖WSL2就先别用这个方法。第二种以管理员身份运行VMware。右键VMware Workstation图标选择“以管理员身份运行”能解决一部分权限不足导致的连接失败问题。第三种禁用内核隔离内存完整性。打开Windows安全中心 - 设备安全性 - 内核隔离关闭“内存完整性”然后重启。这个功能有时会干扰VMware的驱动加载尤其是安装了较老版本VMware时更容易出现。还有一个偏门但常见的情况VMware服务没有启动。按下WinR输入services.msc找到所有包含VMware字样的服务确认它们都在运行状态。我有一次就是清理系统时误禁用了某个VMware服务折腾了一个小时才反应过来。2. Docker安装前的系统初始化与基础配置2.1 更换apt软件源决定后续安装速度的关键一步系统装好后进入Ubuntu 22.04图形界面或直接打开终端第一件事就是更新软件源。如果你用的是默认源apt install的时候会有明显的卡顿几十KB/s的速度拖到崩溃。修改源之前先执行一次系统更新同时安装几个后续要用到的基础工具sudo apt update sudo apt upgrade -y sudo apt install -y curl wget apt-transport-https ca-certificates software-properties-common gnupg lsb-release这几个包的作用分别是curl和wget用于下载文件apt-transport-https和ca-certificates是让apt支持HTTPS源software-properties-common提供add-apt-repository命令gnupg用于验证密钥lsb-release可以查看系统版本信息。如果你使用的是国内网络环境建议把apt源替换为国内镜像源。在这个步骤的描述上我保持中立。实际操作是这样先备份原始源文件然后编辑/etc/apt/sources.list把其中的archive.ubuntu.com和security.ubuntu.com替换为可用的镜像域名再执行sudo apt update。替换后apt下载速度会有质的提升尤其是后续安装docker依赖包时会明显感受到差别。还有一个容易被忽略的点Ubuntu 22.04的apt源配置其实不在/etc/apt/sources.list单一文件中而是分布在/etc/apt/sources.list.d/目录下的ubuntu.sources文件。所以修改前先ls一下这个目录看看到底是哪种结构不要傻乎乎地只盯着一个文件改。2.2 关闭交换分区与防火墙预留Docker容器对内存的要求很高尤其是运行Elasticsearch这类吃内存的应用时。如果系统启用了swap分区容器在内存不足时会使用swap导致IO性能断崖式下降。对于虚拟机上运行的Docker我建议直接关闭swapsudo swapoff -a sudo sed -i / swap / s/^/#/ /etc/fstab第一条命令立即关闭交换分区第二条注释掉fstab中的swap条目确保重启后不会自动挂载。这个操作对于内存足够8GB以上的开发机来没什么影响但能避免很多容器运行时的诡异问题。防火墙方面Ubuntu默认自带ufw防火墙。如果你对Docker的端口映射不熟悉建议先不要折腾防火墙规则因为Docker的iptables管理机制有时候会跟ufw产生微妙冲突。可以等到后续对容器网络有了认知再配置。如果确实需要开启防火墙注意要允许Docker的网桥流量sudo ufw allow in on docker0不过这句话在执行顺序上有讲究不能在Docker安装之前就设置否则ufw会拒绝转发容器流量。最佳实践是先装Docker再配ufw规则。2.3 Docker运行时的内核参数调校Ubuntu 22.04默认内核已经足够支撑Docker运行但有两个参数建议调整一个是为了性能一个是为了兼容性。第一个是net.bridge.bridge-nf-call-iptablesDocker会用到br_netfilter模块来管理容器之间的网络流量。加载模块并设置内核参数sudo modprobe br_netfilter sudo sysctl -w net.bridge.bridge-nf-call-iptables1为了永久生效把这些写入/etc/sysctl.d/docker.conf文件里。第二个是vm.max_map_count这个参数直接影响Elasticsearch、Grafana这类依赖内存映射的容器。默认值是65530建议调整为262144sudo sysctl -w vm.max_map_count262144同样写入sysctl配置。这个参数不调整的话高版本Elasticsearch容器起不来报错信息往往还很不直观。3. Docker引擎安装与镜像加速配置3.1 官方apt仓库安装Docker的正确姿势Docker的安装方式有几种直接apt install docker.io、使用Docker官方脚本、通过Docker官方apt仓库安装。我推荐最后一种理由是它能让你用上最新稳定版本且后续升级方便。前提是你要先添加Docker的GPG密钥和软件源。这一步注意Ubuntu 22.04的源地址要根据系统架构来选择x86_64机器使用以下路径curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg然后添加源echo deb [archamd64 signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null这里有两处细节需要留意。第一signed-by参数指定的keyring路径必须和前面gpg命令的输出路径一致否则apt会报错提示缺少公钥。第二$(lsb_release -cs)会自动解析为你的系统版本代号。Ubuntu 22.04对应的代号是jammy如果这个命令没有输出或者输出了奇怪内容需要先确保lsb-release包已安装。接下来更新源并安装sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin最后一个docker-compose-plugin是Docker Compose的官方实现安装后就无需单独装docker-compose了。安装完成后启动服务并设置开机自启sudo systemctl start docker sudo systemctl enable docker systemctl status docker如果看到Active: active (running)标识说明Docker已经跑起来了。这时候可以跑一下hello-world验证sudo docker run hello-world但实际在上面的步骤中大几率会卡在拉取镜像这一步因为hello-world镜像也托管在Docker Hub上。这就引出了下一个关键环节——镜像加速。3.2 镜像加速配置解决docker拉取镜像慢的痛点热搜词里有“docker镜像下载慢”这几乎是国内Docker使用者都会遇到的问题。Docker Hub的服务器在海外默认连接下拉取一个几百MB的镜像可能要等十分钟甚至更久而且经常中途断流。解决方案是配置镜像加速器。Docker的配置文件在/etc/docker/daemon.json大部分情况下这个文件是不存在的需要手动创建sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.nju.edu.cn ] } EOF然后重启Docker使配置生效sudo systemctl daemon-reload sudo systemctl restart docker配置之后可以使用sudo docker info命令查看Registry Mirrors字段确认镜像加速器是否生效。需要坦白说的是镜像加速器并不保证每次都能成功因为这类公共加速服务本身也存在不稳定性和访问失效的可能。所以我的建议是把多个加速地址都配上Docker会按顺序尝试。如果遇到某个镜像拉取特别慢还可以考虑直接拉取其他镜像仓库的镜像再打标签使用。3.3 免sudo运行Docker用户组配置与权限管理每次使用docker命令都要加sudo时间长了绝对是一种折磨。解决办法很简单把当前用户加入docker组sudo usermod -aG docker $USER然后重新登录系统或者执行以下命令让用户组变更立即生效newgrp docker之后直接执行docker version如果不再提示permission denied说明配置成功。这里要特别提醒一个安全原则把用户加入docker组等同于授予该用户root级别的系统权限。Docker的守护进程是以root身份运行的能操作docker组就意味着能通过挂载宿主机目录的方式访问主机上的任意文件。所以这只适合在个人开发机上操作在多人共享的服务器上要谨慎。还有一个小坑需要说明。如果命令 sudousermod -aG docker $USER 执行时报错提示useradd或usermod找不到用户要确认你当前登录的用户名是否正确。Ubuntu 22.04安装时创建的默认用户往往就是你的主用户但如果你是用root登录的执行useradd时并不会自动创建名为root的docker组。4. Docker基础使用与实战从MySQL到Redis4.1 用MySQL 8.0容器打通数据持久化与端口映射环境装好接下来用一个真正的应用来验证Docker是否真的能干活。MySQL 8.0是最经典的选择因为它的配置涉及端口映射、数据卷挂载、环境变量设置和容器自启动策略几乎涵盖了日常使用中的全部核心知识。先创建数据目录然后运行容器mkdir -p ~/docker/mysql/data sudo docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -e TZAsia/Shanghai \ --restartalways \ -v ~/docker/mysql/data:/var/lib/mysql \ mysql:8.0拆解一下这条命令的参数。-d表示后台运行。-p 3306:3306做了端口映射宿主机3306端口收到的流量会转发给容器的3306端口。这个映射关系是Docker网络的核心机制默认情况下每个容器有自己的虚拟IP宿主机要访问容器要么通过IP直连要么就靠映射。-e用于设置环境变量MYSQL_ROOT_PASSWORD指定root密码TZ设置时区。--restartalways表示容器退出后自动重启这个参数对生产环境的稳定性很关键。-v把宿主机目录挂载到容器的数据目录这样容器删除后数据还能保留。运行完成后用以下命令验证容器状态和数据目录docker ps ls -l ~/docker/mysql/data如果数据目录下出现了mysql、binlog等文件说明数据持久化已经生效。此时在宿主机上执行sudo netstat -tlnp | grep 3306也能看到3306端口正在监听。这里有个很典型的坑需要提醒如果你的系统上已经装了本地的MySQL或者别的服务占用了3306端口docker run会直接报错退出。解决办法是改用其他宿主端口比如-p 3307:3306但容器内部仍然监听3306外部通过宿主机3307端口访问即可。4.2 Docker Compose编排Redis主从集群单容器跑起来不难难的是一组容器如何协作。Redis主从结构是docker compose最经典的教学案例原因在于它涉及多个服务之间的依赖关系。在~/docker/redis/目录下创建docker-compose.yml文件services: redis-master: image: redis:7.0 container_name: redis-master command: [redis-server, --appendonly, yes] ports: - 6379:6379 volumes: - ./master-data:/data restart: always redis-slave: image: redis:7.0 container_name: redis-slave command: [redis-server, --slaveof, redis-master, 6379] depends_on: - redis-master ports: - 6380:6379 volumes: - ./slave-data:/data restart: always然后在目录下执行sudo docker compose up -d等镜像拉取完成后用sudo docker ps就能看到两个容器在运行。验证主从同步状态sudo docker exec -it redis-master redis-cli info replication看到role:master以及connected_slaves:1说明主从同步正常。这里有一个特别值得说的点是depends_on这个配置。它确保redis-slave容器会在redis-master之后启动避免从库在启动时找不到主库而报错退出。但depends_on只控制了启动顺序不保证主库已经完全就绪。如果主库启动慢从库可能会重试几次Redis的slaveof机制本身支持自动重连所以问题不大。如果遇到从库一直标着down可以在从库容器内手动执行slaveof no one再slaveof redis-master 6379来重新触发同步。4.3 Docker网络模式的选择心得使用docker compose创建的多容器服务默认会加入同一个自定义bridge网络。在这个网络里容器之间可以通过服务名互相访问不需要知道彼此的IP地址。这也是为什么上面的redis-slave配置里直接使用redis-master作为主机名而不是写一个具体的IP。Docker的网络模式有四种分别是bridge、host、none和container。日常使用最多的是bridge也是默认模式。每一个docker run创建的容器如果不指定网络都会加入docker0这个默认的bridge网络。但如果你是通过docker run而非compose创建多个需要通信的容器建议创建一个自定义网络docker network create myapp docker run -d --name redis-master --network myapp redis docker run -d --name redis-slave --network myapp redis redis-server --slaveof redis-master 6379默认bridge网络不支持基于容器名的DNS解析只有自定义网络才提供这个能力。实践中最常见的问题是新手用默认bridge网络创建两个容器然后在容器A里尝试通过容器名访问容器B结果发现ping不通。这不是Docker故障而是默认网络的机制限制。host模式一般在性能要求极高的场景使用容器直接使用宿主机的网络栈没有额外的NAT开销但代价是容器和宿主机共享端口空间不同容器不能使用相同的端口。5. 常见问题与排查技巧实录5.1 Docker安装失败与启动报错的排查Docker环境配置过程中最让人头疼的不是Docker本身的命令复杂而是各种环境层面的报错。根据我最近一段时间在VMware Ubuntu 22.04上的装机经历把遇到频率最高的几个问题整理成速查表报错现象根因分析解决思路apt update时报NO_PUBKEYDocker源密钥未正确导入用curl获取gpg密钥后以dearmor方式保存注意signed-by路径与文件路径一致docker: Cannot connect to the Docker daemon守护进程未启动执行systemctl start docker再执行systemctl enable docker设置开机自启Failed to start docker.service: Unit docker.service not foundDocker安装不完整确认docker-ce安装成功必要时重新安装docker-ce并执行systemctl daemon-reload容器启动提示permission denied用户未加入docker组usermod -aG docker $USER后重新登录镜像拉取超时Docker Hub连接不稳定配置镜像加速器或者重试拉取5.2 容器网络不通的第一排查步骤容器能启动但网络不通这个问题非常诡异因为它在宿主机层面看不出任何异常。我和朋友们在测试中反复遇到总结出下面几条独立的排查逻辑第一确认容器是否真的在运行。docker ps只显示运行中的容器如果容器已经退出启动时可能因为某个初始化失败导致网络配置没有完整应用。使用docker ps -a查看所有容器状态再用docker logs容器名查看日志。第二确认端口映射是否正确。docker port容器名可以查看当前容器的端口映射情况。如果显示空结果说明docker run时没有指定-p参数或者指定的关联不对。第三确认宿主机防火墙没有阻断流量。ufw status如果显示active先临时关闭ufw再测试连通性。注意这只是在排除问题不推荐长期关闭防火墙。第四用docker exec进容器内部做网络诊断。比如测试宿主机到容器的连通性可以先进入容器安装ping工具部分精简镜像没有然后ping宿主机IP或网关地址定位是哪个环节断了。5.3 迁移与备份Docker环境失效后的快速恢复虚拟机的一个优势就是随时可以还原。但如果你不想走快照恢复这条路日常的容器数据备份也值得掌握。最直接的方式是导出容器的镜像和卷数据。镜像可以用docker save导出为tar包卷数据直接打包对应的宿主机目录。对于MySQL这类应用直接打包数据目录比docker export容器要可靠得多。docker save -o mysql80.tar mysql:8.0 tar -czf mysql-data.tar.gz ~/docker/mysql/data恢复时先docker load导入镜像再解压数据目录最后重新docker run挂载即可。另外如果你创建了很多自定义网络或数据卷迁移后记得检查 docker network ls 和 docker volume ls。数据卷是Docker中的独立生命周期单元容器删除了数据卷依然存在。在新环境里重新创建容器并挂载旧数据卷数据就恢复了。但有一点要留意使用docker compose创建的项目其数据卷命名往往包含目录名恢复时保持同样的目录结构可以减少很多不必要的调整。6. 后续扩展这台Docker虚拟机还能怎么用环境稳定、容器跑起来之后我在日常使用中发现它还能做不少实用的事情。第一部署个人开发用的代码托管服务。Gitea是一个轻量级的Git服务官方提供了Docker镜像一条docker compose就能起来。配合MySQL容器可以构建一张完整的开发服务网。资源占用非常低在VMware分配4GB内存的Ubuntu 22.04上同时跑Gitea和MySQL完全不会卡顿。第二使用Portainer做可视化管理界面。Portainer的容器管理界面能让你用鼠标完成镜像拉取、容器销毁、日志查看等操作对不习惯命令行的人非常友好。sudo docker run -d --name portainer \ -p 9000:9000 \ -v /var/run/docker.sock:/var/run/docker.sock \ portainer/portainer-ce然后浏览器访问http://虚拟机IP:9000设置管理员密码后就可以在网页上管理整套Docker环境。第三搭建本地的CI测试环境。使用Jenkins或者Gitea Actions的runner容器在虚拟机里做自动化测试尤其适合前端、Python后端项目的持续集成验证。虚拟机的快照能力在这种场景里特别好用——测试环境搞坏了恢复快照就回到起点。我自己的使用习惯是把VMware里的这台Ubuntu 22.04当做一个可以随意折腾的沙盒。需要验证一个新中间件先在这里面起一个容器练手确认没问题后再部署到更强力的服务器上。这种流程让风险控制变得非常轻松。回到整个安装配置的过程我个人最大的体会是VMware、Ubuntu 22.04、Docker这个组合本身已经非常成熟了教程遍地都是但真正决定装机成败的往往是一些看起来很不起眼的细节——有没有勾选VT-x、apt源换没换、docker组有没有加入、镜像加速器配没配。把这些细节处理好剩下的也就是照着命令敲一遍的事。如果你在配置过程中碰到其他奇怪的问题不妨回头检查一下这几个基础环节大概率能找到突破口。