ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows下用WSL2安装Ubuntu 24.04与Docker Engine的完整实战指南

Windows下用WSL2安装Ubuntu 24.04与Docker Engine的完整实战指南 最近被问得最多的问题之一是手头只有Windows电脑但开发的业务和服务都跑在Linux容器里到底怎么把Ubuntu和Docker这套环境装起来。我今天就把自己实际用下来的完整思路和操作记录整理成文覆盖方案选型、WSL2 Ubuntu 24.04环境搭建、Docker引擎安装、Compose编排验证以及我踩过的坑和排查命令。这套流程不只是能跑通更重要的是让你知道每一步为什么这么做后面遇到问题不会慌。我第一次在Windows上正经跑Linux容器是在一台配置很普通的笔记本上。当时本地要起MySQL、Redis和几个内部服务Windows原生跑起来风扇狂转Docker Desktop内存吃掉2GB数据库容器还碰到文件锁和IO性能问题。后来把Docker Engine装进WSL2的Ubuntu里内存占用降了一截容器启动和文件读写快了很多整个体验从“能用”变成“舒服”。如果你也是Windows用户又不想因为开发环境重装双系统这篇文章应该能帮你少走不少弯路。1. 需求拆解与方案选型Windows里跑Ubuntu Docker到底在解决什么问题很多人一开始不理解Windows上装个Docker Desktop不就行了为什么要绕一圈装Ubuntu我举个生活化的例子Docker容器里的应用就相当于打包好的货箱Linux是货箱“土生土长”的陆运系统而Windows本身是另一套物流网络。你可以在Windows这边硬扛着开叉车但效率、兼容性和稳定性都不如让货箱直接回到自己的运输体系里。1.1 三种主流方案对比我实际试过的方案有三类各有适用场景方案一Windows WSL2 Ubuntu Docker Engine。这是我在日常开发中最推荐的方式。WSL2本身是Windows官方提供的Linux子系统底层是轻量级虚拟机跟Windows宿主机共享内核调度资源开销小启动在秒级文件和端口都能双向互访。方案二VMware / VirtualBox 安装完整Ubuntu再在Ubuntu里装Docker。适合需要完整Linux图形界面、要跑多个独立虚拟机、或者做网络实验的场景。缺点是虚拟机占资源大硬盘文件动辄几十GB启动也慢一些。方案三直接装Docker Desktop for Windows用WSL2后端跑Linux容器。适合只想快速体验Docker、不想碰Linux终端的朋友。但Docker Desktop内存占用更高而且它会在Windows侧封装一层遇到网络栈和文件挂载问题时排查路径更长。真正把Linux容器作为生产级运行环境来用我认为方案一是最平衡的选择。特别是你以后还想在这台机器上部署一些依赖Linux特性的服务比如systemd管理的守护进程、Linux网络命名空间相关实验WSL2里的Ubuntu几乎可以当作一台真正的Linux服务器来对待。1.2 为什么我优先选择WSL2 Ubuntu而不是双系统双系统的优势是性能无损Windows和Ubuntu完全隔离。但你得接受一个事实切换系统需要重启电脑两边文件访问也比较麻烦。对绝大多数以Windows为日常主力、偶尔要跑Linux容器的开发者来说这个代价不值得。WSL2还有一个隐藏优势它支持从Windows侧直接执行Linux命令也可以反过来在Linux侧调用Windows的exe。日常操作文件、复制路径都方便。比如我在Windows的VS Code里直接连接WSL编辑代码、跑容器、看日志全在一个界面里完成体验非常接近远程开发服务器。WSL2的文件IO被人吐槽过尤其是用/mnt/c访问Windows磁盘时大量小文件操作会慢。解决方式很简单项目代码尽量放在Ubuntu自己的文件系统里也就是/home/xxx/下面。后面我在实操环节会再强调这一点。2. 环境准备先把Windows虚拟化基础打牢WSL2本质上是个轻量虚拟机虚拟化功能没开是跑不起来的。Windows 10/11只有专业版、企业版或教育版支持完整的WSL2体验家庭版也行但部分老版本需要手动开启一些组件。2.1 检查并开启虚拟化功能第一步打开任务管理器切到“性能”选项卡查看CPU下方的“虚拟化”状态。如果显示“已启用”直接跳到WSL安装如果显示“未启用”需要进BIOS/UEFI开启Intel VT-x或AMD-V。不同品牌电脑进BIOS的按键不太一样多数是开机时按Del或F2。进去之后找“CPU Configuration”或“Advanced”菜单把Intel Virtualization Technology / AMD SVM Mode设为Enabled保存退出。在Windows功能里还需要确认“虚拟机平台”和“适用于Linux的Windows子系统”两个组件是开启状态。以管理员身份打开PowerShell执行dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart执行完重启电脑。这一步很多朋友会漏掉结果WSL安装时报错其实问题不在WSL是底层组件没就位。2.2 安装WSL2与Ubuntu 24.04 LTSWindows 11或较新的Windows 10可以直接用一条命令完成WSL的默认安装wsl --install这条命令会帮你装好WSL2、虚拟机平台并默认安装Ubuntu。但我想指定Ubuntu版本更推荐这样的顺序# 先看当前WSL版本如果输出是1先升级到2 wsl --set-default-version 2 # 查看可以安装的Linux发行版 wsl --list --online # 安装指定版本 wsl --install -d Ubuntu-24.04如果你以前装过WSL1想把某个发行版转到WSL2用这条命令wsl --set-version Ubuntu-24.04 2第一次启动Ubuntu时终端会让你设置新的UNIX用户名和密码。这个用户名不必跟Windows用户名一致但它会作为你在Ubuntu里的主账号所有的家庭目录都挂在/home/你的用户名下面建议设置一个简单好记的。装完顺手更新WSL内核避免某些容器特性抽风wsl --update更新完后重新打开Ubuntu终端执行uname -a看一下内核版本。我看到5.15以上就基本满足主流容器需求了。注意不要直接关掉Ubuntu窗口就认为环境装好了。WSL里的Ubuntu默认是不用密码登录的sudo也很方便但系统自身的时间同步、后台服务等配置都需要你在首次启动后自己确认尤其是后面要跑Docker的时候建议把systemd打开否则部分服务不会自动启动。打开/etc/wsl.confsudo nano /etc/wsl.conf写入如下内容[boot] systemdtrue然后在Windows PowerShell里执行wsl --shutdown重新进入Ubuntu。验证systemd有没有生效systemctl is-system-running看到running或者degraded都算正常只要不是报错System has not been booted with systemd就行。这里再补充一个很小但很有用的经验WSL2默认内存占用没有硬上限如果你这台Windows机器内存只有16GB跑两三个容器再加一个IDE可能就紧张。可以在Windows用户目录下建一个.wslconfig文件内容这样写[wsl2] memory6GB processors4 swap2GB改完同样要wsl --shutdown重启WSL才会生效。这个文件不是必须的但我在低配机器上测试过提前限制内存能避免Windows和WSL互相抢资源导致的卡顿。3. 在Ubuntu里安装Docker引擎而不是Docker Desktop环境准备好之后就开始装今天的核心Docker。官方文档里推荐在Ubuntu上安装Docker时有docker.ioUbuntu仓库和docker-ceDocker官方仓库两条路我强烈建议用docker-ce。3.1 为什么不用Docker Desktop首先要明确Docker Desktop是给Windows/macOS用户的“集成开发包”它自带图形界面和虚拟机后端但对于已经在WSL2里跑Ubuntu的人来说是多余的。直接在Ubuntu里装Docker Engine更接近生产服务器的环境容器运行时不需要经过Docker Desktop那一层排障也简单。Docker Desktop还会注册Windows开机自启的服务后台常驻内存。我只跑几个轻量容器的时候它占的内存比容器本身都多。而且用Docker Desktop管理WSL2里的容器时系统经常在Windows和WSL之间做文件同步日志一多就卡。所以我的结论是如果你想在Windows里“运行Docker容器”Docker Desktop是最快的路如果你想在Windows里“拥有一个Linux服务器的体验并在这台服务器上运行容器”直接装Docker Engine更干净。3.2 使用官方apt源安装docker-ce先打开Ubuntu终端把基础依赖装好sudo apt update sudo apt install -y ca-certificates curl gnupg然后添加Docker官方GPG密钥和软件源。这里我拆开写方便你看每一步在干什么# 创建目录用于存放密钥 sudo install -m 0755 -d /etc/apt/keyrings # 下载官方GPG密钥文件 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 给密钥添加读权限 sudo chmod ar /etc/apt/keyrings/docker.gpg # 自动识别Ubuntu版本并写入docker的官方软件源 echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo ${UBUNTU_CODENAME:-$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这里我额外装了docker-buildx-plugin和docker-compose-plugin前者用于现代的多平台镜像构建后者让你直接使用docker compose命令不用再单独装Python的docker-compose。现在新项目基本都建议用v2版本的Compose语法和旧版稍有差异但更强大。检查Docker是否装好docker --version docker compose version sudo systemctl enable --now docker docker infodocker info能正常输出一大堆信息就说明daemon起来了。注意国内网络环境下直接拉取Docker Hub官方镜像经常很慢这是网络环境客观因素。解决办法是在/etc/docker/daemon.json里配置镜像加速器。我先给你一个可用的模板具体地址以你自己服务商提供的最新地址为准比如你在阿里云容器镜像服务的控制台里能看到专属加速地址配置自己账号专属的地址是最稳的。在Ubuntu里执行sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json EOF { registry-mirrors: [https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com] } EOF sudo systemctl restart docker不同镜像加速地址的稳定性和速率会随时间变化如果你发现某个地址失效直接编辑daemon.json替换即可。要是公司或团队有私有镜像仓库也可以把它填进去优先级高于默认Docker Hub。3.3 免sudo运行docker与开机自启Docker默认只有root用户能操作每次敲sudo docker很麻烦尤其是我这种懒人。把当前用户加入docker组就能解决sudo usermod -aG docker $USER newgrp docker重新打开终端直接执行docker ps如果不报权限错误说明免sudo生效。关于开机自启因为前面已经在/etc/wsl.conf里开启了systemd所以只要执行过sudo systemctl enable docker每次启动WSL里的UbuntuDocker服务都会自动跑起来。如果没有启用systemd就需要每次手动执行sudo service docker start非常容易忘。如果你发现WSL重启后Docker还是没起来可以先执行sudo systemctl status docker看日志常见原因就是systemd没启用或者是内存不足导致daemon崩溃。4. 用Nginx MySQL实例验证整个环境是否可用只把Docker装好不算完最好实际跑两个容器验证一下。我每次在新环境里都会起一个Nginx和一个MySQL这两个服务几乎覆盖了日常最常用的端口映射、数据卷、环境变量、容器网络等配置点。4.1 准备docker-compose.yml在Ubuntu的home目录下建一个实验目录mkdir -p ~/docker-test cd ~/docker-test创建一个docker-compose.yml文件services: mysql: image: mysql:8.0 container_name: my-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: testdb ports: - 3306:3306 volumes: - mysql_data:/var/lib/mysql command: --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci nginx: image: nginx:1.27-alpine container_name: my-nginx restart: unless-stopped ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html volumes: mysql_data:解释一下几个关键设计mysql容器用了命名数据卷mysql_data这样删容器不会丢数据。你可以用docker volume inspect mysql_data看到它实际存放在Ubuntu宿主机的哪个目录。指定了--character-set-serverutf8mb4和--collation-serverutf8mb4_unicode_ci避免中文乱码。很多人数据库容器跑起来后连接报“Unknown collation”多半是没指定这个。nginx的端口映射是8080:80意思是宿主机的8080端口转发到容器内部的80端口。如果8080被占用改成8081:80即可。挂载./html目录到容器内我可以在Windows里编辑网页文件容器里立刻生效。4.2 启动并验证服务执行docker compose up -d-d是后台运行。第一次启动会拉取镜像如果配置了加速器速度会明显提升。等看到两个容器状态是Up执行docker ps docker compose logs -f然后验证MySQL能否登录docker exec -it my-mysql mysql -uroot -proot123456进去后执行show databases;能看到testdb库说明MySQL没问题。退出MySQL终端用exit。Nginx验证更简单回到Windows浏览器输入http://localhost:8080如果看到Nginx欢迎页说明端口转发链路是通的。4.3 宿主机Windows如何访问Ubuntu里的容器服务这是很多人最困惑的地方。WSL2和Windows共享网络端口理论上Windows的localhost:8080就能访问Ubuntu里监听8080的容器服务。但我实测发现偶尔有延迟或不通的情况原因多半是Windows防火墙拦截了WSL的vEthernet网卡。如果你遇到Windows浏览器访问不了但Ubuntu里curl localhost:8080正常可以先在Windows PowerShell里看监听端口netstat -ano | findstr 8080如果看到0.0.0.0:8080监听但是浏览器打不开执行netsh advfirewall firewall add rule nameWSL2_8080 dirin actionallow protocolTCP localport8080这个命令给Windows防火墙加一条入站规则。如果你只是本机访问一般不会触发要是同一局域网内别的设备想访问这台Windows上的容器就必须放行对应端口。另外容器服务如果监听的是IPv6地址也可能出现访问不到的情况。此时在Ubuntu里查看一下ip addr show eth0确认IP和监听地址是否对得上。容器里Nginx默认监听的是0.0.0.0:80映射出来后通常没问题。5. 常见问题与排查技巧实录我在这套环境上踩过的坑不少挑几个高频的整理成速查表方便你直接对照。现象可能原因排查与解决WSL启动报错WslRegisterDistribution failed虚拟化未开启或WSL版本过旧检查BIOS虚拟化设置执行wsl --update重启Docker服务无法启动日志提示Failed to start Docker Application Container Engine内存不足或者daemon.json配置错误free -h查看内存先删掉daemon.json测试再逐步排查拉取镜像非常慢网络到Docker Hub不稳定配置registry-mirrors加速器或使用团队内部镜像仓库容器内服务Windows访问不到端口未监听、Windows防火墙拦截docker ps确认映射端口Windows防火墙放行对应端口挂载Windows目录后容器内写入很慢WSL2跨系统文件IO性能差把工程文件放到Ubuntu的/home目录不要放在/mnt/c下MySQL容器中文乱码数据库字符集设置不对启动命令增加--character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_cidocker compose命令找不到没有安装docker-compose-plugin执行sudo apt install docker-compose-plugin除了这些我再分享几个定位问题的固定套路。第一看日志永远是第一步不要瞎猜。容器起不来先执行docker logs 容器名比如MySQL启动失败大概率能在日志里看到缺少权限、端口占用或数据目录损坏的信息。第二确认端口是否真的被容器监听。在Ubuntu里执行ss -tlnp | grep 端口号如果看不到监听说明容器端口映射或服务本身有问题可以先排查容器内部docker exec -it 容器名 bash curl localhost:端口号第三养成清理僵尸容器的习惯。WSL2环境本身资源有限docker ps -a如果堆积了大量Exited状态的容器既占空间又可能造成端口冲突。定期执行docker system prune -a这条会把所有未被使用中的容器、镜像、网络和构建缓存全部清理执行前确认好哪些是要保留的。第四尽量不要用--privileged模式跑普通容器。很多教程为了方便给容器加特权模式但这会绕过Linux的权限隔离一旦容器被攻击宿主机的安全边界基本就没了。我在本地测试Nginx都不需要privileged除非你明确知道要操作内核模块否则不要用。6. 日常开发工作流把体验整得更顺一点环境稳定之后我慢慢把整个工作流从“Windows原生开发”迁到了“WSL2 Ubuntu Docker”这套结构里。现在分享几个让日常使用更顺手的小经验。6.1 用VS Code连接WSL在Windows的VS Code里装上“WSL”扩展然后点击左下角绿色符号选择“Connect to WSL”VS Code就会以远程模式打开Ubuntu里的文件系统。这意味着终端默认就是Ubuntu的bash代码补全和调试器都运行在Linux侧文件保存后直接进入Linux磁盘容器挂载同一个目录时不会有跨系统同步的延迟感。这个体验对我而言是决定性优势。以前我用VMware跑Ubuntu时还得在虚拟机里单独装一套图形界面和编辑器现在所有编辑工作留在Windows侧执行工作扔给Ubuntu侧。6.2 将文件按容器来规划存放位置我给自己的团队定了一个简单的目录规范~/projects/放代码工程每个工程一个子目录~/data/mysql/专门放MySQL初始化脚本和备份文件~/logs/放容器挂载出来的日志文件。这样的好处是备份、迁移时很清晰。比如想把整个环境搬到新电脑可以只备份~/projects和/var/lib/docker/volumes里的数据卷目录没必要把整个Ubuntu文件系统都拷走。如果你在Windows侧单独买了一块SSD专门放Docker数据可以通过修改/etc/docker/daemon.json的>sudo apt install -y net-tools curl wget git unzip htop中文输入法如果在Ubuntu图形界面里需要用到可以装fcitx5然后把搜狗输入法装进去。但因为我们走的是WSL2默认没有图形桌面如果你没有通过WSLg打开Linux GUI程序的需求输入法其实可以完全不用管。从这个角度也能看出这套环境更适合“以命令行和Docker服务为主”的使用方式。6.4 备份与迁移WSL发行版WSL2里跑久了Ubuntu根文件系统会越来越大。如果你想迁移到新电脑或者想在迁移前做一次快照可以用Windows这边导出功能wsl --shutdown wsl --export Ubuntu-24.04 D:\backup\ubuntu-24.04.tar以后在新机器上导入wsl --import Ubuntu-24.04 D:\WSL\Ubuntu-24.04 D:\backup\ubuntu-24.04.tar --version 2注意用wsl --import导入后默认登录用户会变成root你可以在Ubuntu里执行下面命令把默认用户改回来echo -e [user]\ndefault你的用户名 | sudo tee /etc/wsl.conf然后wsl --shutdown再进。这个细节很多人不知道导入完发现home目录不对还以为是迁移出了问题。6.5 多项目隔离的一点建议当你要跑的容器越来越多一台机器全塞在一起会变得混乱。Docker Compose本身带有项目隔离能力只要你在不同的目录里放不同的docker-compose.yml容器就会自动带上目录名前缀不会互相重名。比如我同时跑“日志采集”和“Web后台”两个项目时目录分别叫logs-service和web-admin容器名自动变成logs-service-logstash-1和web-admin-api-1一眼就能看出属于哪个项目。Docker Compose还会为每个项目创建独立的网络所以不同项目的容器即使使用相同的内部端口也不会冲突。我个人在实际操作中比较喜欢把“临时验证”和“长期服务”分开。临时验证用docker run --rm跑完自动删容器不污染环境长期服务用docker compose up -d配置固化在文件里重装系统后只需要把Compose文件拿过来就能恢复。这套习惯帮我避免了很多“明明容器在跑但找不到它属于哪个项目”的混乱。最后再提醒一句WSL2虽然好用但它毕竟还是虚拟机如果你要跑生产级高并发的Docker集群我的建议仍然是把服务部署到真正的Linux服务器上而在这之前Windows上的一套Ubuntu Docker环境已经足够撑起你百分之九十的日常开发、学习和demo验证了。
返回列表