尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Windows Docker Desktop 安装与镜像构建全流程指南

Windows Docker Desktop 安装与镜像构建全流程指南 Windows 上想跑容器绕不开 Docker Desktop 这个桌面端工具而真正让人卡住的往往不是 Docker 本身而是从装不上到装上了但起不来再到起来了却不知道镜像怎么建。我自己从早期的虚拟化方案一路用到现在的 WSL2 后端前后在三四台不同配置的机器上反复装过踩的坑足够写满一页纸。这篇内容就是把这套流程完整摊开讲Docker Desktop 在 Windows 上到底怎么装、装完怎么验证、虚拟化相关的报错怎么修、镜像是什么以及怎么从零构建一个属于自己的镜像。不管你是刚接触容器的新手还是装过几次但每次都要重新查资料的老手都能从这里直接抄走可复现的步骤和参数。下面按装之前想清楚装的时候注意什么装完怎么用这条线往下走。1. 装之前先想清楚Windows 跑容器靠的是什么1.1 WSL2 和 Hyper-V 两条后端到底选哪条容器在 Linux 上是原生跑在内核的命名空间和资源控制机制之上的Windows 内核没有这两样东西所以必须有一层翻译把 Linux 的系统调用转过去。Docker Desktop 给出两条路一条是走 WSL2也就是 Windows 自带的 Linux 子系统第二版另一条是走 Hyper-V开一台轻量虚拟机把整个 Docker 引擎塞进去。这两条路我都完整跑过体感差异非常明显。WSL2 的优势在于启动快、内存占用可控、文件系统打通得比较好你在 Windows 的目录里改代码容器里几乎能立刻看到变化。它的代价是依赖 Windows 的虚拟化能力一旦主板层面的虚拟化没打开整条链路直接断掉这就是后面那个经典报错的来源。Hyper-V 方案的好处是隔离更彻底、行为更接近一台独立机器适合跑一些对内核参数有要求的中间件但内存是硬性预留的机器只有 8GB 内存的话开完虚拟机再开几个容器基本就动不了了。我现在的判断标准很简单日常开发、跑 Redis 或者数据库做本地调试、打包构建镜像一律用 WSL2只有当某个组件在 WSL2 下行为异常时才临时切到 Hyper-V 排查。这个判断不需要你去背参数装的时候就按这个选能省掉后面大量反复调优的时间。1.2 安装前的环境自检清单这一步千万别跳很多人装完才出问题其实问题早就躺在那了只是没提前看。我在动手之前会固定做这几件事你可以照着过一遍确认系统版本Windows 10 需要 64 位、版本 2004 及以上、内部版本 19041 以上Windows 11 全系都可以。低于这个线新版本的 Docker Desktop 会直接拒绝安装连报错都懒得给你详细的。确认 CPU 虚拟化已开启任务管理器切到性能标签看 CPU 那一栏右下角有没有虚拟化已启用。如果显示已禁用先别急着装去 BIOS 里把它打开这一步不做后面全是白费功夫。确认磁盘空间Docker Desktop 自身安装包不到 1GB但镜像层是要实打实占空间的。我建议 C 盘至少留出 40GB 空闲因为默认的镜像存储位置就在用户目录下C 盘爆掉会让 Docker 直接罢工。确认系统功能状态在启用或关闭 Windows 功能里虚拟机平台和适用于 Linux 的 Windows 子系统这两个勾一定要打上。Windows 11 家庭版没有 Hyper-V但你用 WSL2 后端的话根本不需要它这点别被网上的老教程带偏。提醒一句如果你的机器上装过其他虚拟化软件比如某些安卓模拟器、虚拟机软件它们可能会抢占虚拟化资源导致 Docker 启动时报虚拟化不可用。这种情况下先彻底退出这些软件再启动 Docker多数问题当场消失。2. Docker Desktop 下载与安装每一步都有讲究2.1 安装包怎么选别下错版本Docker Desktop 目前的安装包按 CPU 架构分为 x64 和 ARM64 两类绝大多数个人电脑是 x64选这个就对了。另外还有面向个人使用和面向企业使用的区分个人学习和小型团队用免费版本完全够功能上不受任何限制不要因为看到企业版就以为免费版少了什么。下载的时候我强烈建议直接去官方渠道拿最新稳定版别用第三方站点转存的包。原因很实际容器这套东西涉及系统内核层面的改动安装包被替换或捆绑的概率虽然不高但一旦中招排查起来极其麻烦。另外网上流传的很多离线安装包其实是老版本装上去之后各种功能对不上号反而增加困惑。如果你的网络环境下载速度很慢可以换个时间段再试或者用支持断点续传的下载工具挂着。但我不建议去用那些来路不明的加速通道安装包这种东西来源比速度重要得多。拿到安装包之后记一下文件大小和版本号后面出问题时这是重要线索。2.2 安装向导里的那几个勾逐个说清楚双击安装包之后界面上有两个默认勾选的选项很多人一路点下一步就过了其实这里值得停一下。第一个是Use WSL 2 instead of Hyper-V这个勾默认是选中的保持它。前面说过WSL2 后端在启动速度和资源占用上都更友好。第二个是Add shortcut to desktop可选看个人习惯。安装过程中它还会提示是否要让 Docker Desktop 随系统启动这个我会关掉因为容器引擎常驻会占几百兆内存需要用的时候手动开就行。安装完成后会要求你注销或者重启这一步别偷懒直接点重启因为 WSL2 的内核组件需要重启才能正确加载。重启之后首次打开 Docker Desktop会弹出一个服务条款确认窗口还有一段可选的登录引导。登录不是必须的跳过完全不影响本地使用只有需要拉取某些私有镜像或者用云构建功能时才需要账号。启动过程中底部会有个小鲸鱼图标在动等它变成稳定的绿色或者显示Engine running才算真正就绪。这个过程第一次会比较慢因为要初始化数据目录和网络配置属于正常现象耐心等两分钟。2.3 装完先做三件事验证别急着建项目很多人装完就迫不及待去跑项目结果一出错分不清是 Docker 的问题还是项目的问题。我固定会先做三次验证把基础层确认干净。第一件事打开 PowerShell 敲版本命令docker version docker infodocker version会分别列出客户端和服务端的版本两边都能正常输出才算通。如果服务端那一段是空的或者报错说明引擎没起来问题在 Docker Desktop 本身跟你的项目无关。docker info输出信息更长重点看它有没有报错以及末尾的存储驱动、容器数量等信息。第二件事跑一次官方的测试镜像docker run --rm hello-world这个命令会做三件事本地没有这个镜像就去拉取、创建容器运行、输出一段说明文字后自动删除容器。--rm参数是我每次跑一次性容器都会加的它会用完即删避免留下一堆停止状态的容器把列表塞满。看到Hello from Docker这行字说明从网络到存储到运行时整条链路都是通的。第三件事确认数据实际落在哪docker system df这个命令会列出镜像、容器、数据卷各自占了多少空间。第一次跑可能只有几十兆但你要知道这个数字以后会涨定期看一眼能避免 C 盘被悄悄吃干净。3. 启动失败专题虚拟化检测不到到底怎么修3.1 这个报错背后的三层原因Docker Desktop failed to start because virtualisation support wasnt detected这句话我见过太多次了它不指向某一个具体故障而是三种情况共用的一句提示得逐层排查。第一层在硬件和固件CPU 本身支持虚拟化但主板的 BIOS 或 UEFI 里这个开关是关的。这是最常见的原因尤其是自己组装或者刚重装系统的机器。第二层在操作系统功能BIOS 里开了但 Windows 的虚拟机平台功能没启用或者被系统更新重置过。第三层最隐蔽功能都开了但被别的软件占用或拦截了比如同时运行的虚拟机软件、某些安全软件的内核防护模块。排查顺序就按这三层来从下往上一层层排除。判断第一层最直接任务管理器性能标签页里那行虚拟化状态就是答案。这一层的问题解决后后面两层基本不需要动。3.2 BIOS 与系统功能开关的具体操作进 BIOS 的方式各家主板不一样常见的是开机时反复按 Del、F2、F10 或者 Esc具体看开机画面第一屏的提示。进去之后找的位置通常叫Advanced、CPU Configuration或者直接在Security里名字可能是Intel Virtualization Technology、Intel VT-x、AMD-V、SVM Mode这类。找到之后设为 Enabled按 F10 保存退出。这里有个新手常犯的错误改完设置直接关机重启结果发现没生效。原因是有些主板的保存和你按的键不是一回事一定要确认看到保存成功的提示再退出。另外如果你用的是笔记本某些型号的虚拟化选项藏在很深的子菜单里实在找不到就去官网查这款机型的手册。系统层面用命令行开启更稳妥以管理员身份打开 PowerShelldism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart两条命令分别启用虚拟机平台和 Linux 子系统功能/norestart表示先别自动重启你想一次改完再统一重启。跑完之后重启机器再启动 Docker Desktop。注意如果你的机器上还装着旧版本的 WSL建议顺手在命令行里执行一次内核更新把 WSL 升到最新版本否则 WSL2 后端有可能因为内核版本过旧而启动不完整。3.3 不报虚拟化错但同样起不来的几种情况有些失败根本不提虚拟化报的是别的错但结果一样是转圈转不动。第一种是端口被占用Docker 的守护进程要占用内部端口如果之前装过残留的组件没清干净会冲突。这种情况下彻底卸载旧版本、重启、再装新版本通常就好了。第二种是用户目录权限问题。Docker Desktop 的数据目录默认在用户文件夹下如果这个目录被某些同步工具锁定或者被安全软件实时扫描拖慢启动就会卡住。我遇到过装完杀毒软件之后 Docker 直接起不来的情况把 Docker 的数据目录加进扫描排除项之后恢复正常。第三种是磁盘空间不足。这个错误往往很隐晦界面上只显示启动失败不告诉你是磁盘满了。我的习惯是启动前先看任务栏右下角的磁盘剩余空间低于 5GB 就该清理了因为镜像解压过程本身也需要临时空间。4. 镜像从概念到落地手写一个并构建出来4.1 镜像、容器、Dockerfile 三者是什么关系这三个词是初学阶段最容易混的。我用一个比较贴切的类比镜像相当于一张系统安装盘的快照容器是按照这张快照装出来的一台正在运行的机器Dockerfile 则是描述这张快照该怎么刻的说明书。镜像是只读的、静态的、可以到处分发的容器是可写的、动态的、跑完就可以删的。你在一台机器上装好环境把它打包成镜像换台机器直接跑这个镜像环境一模一样这就是容器最核心的价值。理解了这个层次很多操作就顺了。docker pull拉的是镜像docker run是拿镜像创建容器docker commit是把容器的当前状态固化成新镜像而docker build是按 Dockerfile 从零构建镜像。日常开发里我们主要用最后一种因为它可追溯、可重复、能进版本控制而docker commit出来的镜像谁也不知道中间改了什么只适合临时实验。4.2 写一个能跑起来的最小 Dockerfile拿一个 Python 服务举例最直观因为它涉及依赖安装能体现分层的价值。我在项目根目录建一个文件名字就叫Dockerfile没有后缀FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . . EXPOSE 8000 CMD [python, main.py]逐行说清楚为什么这么写。第一行FROM指定基础镜像选slim后缀的版本是因为完整版镜像动辄一个多 G而 slim 版只保留了运行时的最基本内容体积能压到一百多兆。这不是抠门是构建速度和分发效率的实实在在的差别。WORKDIR是设定后续命令的工作目录如果目录不存在会自动创建。它的意义在于给后面的COPY和RUN一个确定的落脚点避免文件散落在根目录。第四行先复制requirements.txt第六行再复制全部代码这个顺序是刻意安排的。因为 Docker 构建是按层缓存的只要依赖文件没变你改业务代码重新构建时会直接复用已经装好依赖的那一层构建时间从几分钟降到几秒。如果反过来先复制全部代码再装依赖每次改一行代码都会触发重新安装所有依赖这个坑我踩过非常浪费时间。RUN那行里的--no-cache-dir是让 pip 不要在镜像里保留下载缓存能省下几十兆空间。后面那个-i参数指向的是 Python 包的镜像源这是国内环境下提升安装速度的关键写的时候注意用你自己能访问的源。EXPOSE是给使用者一个提示说明这个容器打算对外提供 8000 端口。它本质上只是文档性质不会真的做端口映射真正映射要在docker run的时候用-p参数指定。最后CMD是容器启动时的默认命令用数组形式写比用字符串形式更规范因为它不会经过 shell 解析信号传递更准确容器停止时进程能正确收到终止信号。4.3 docker build 的命令参数与构建缓存写好 Dockerfile 之后在它所在的目录执行docker build -t myapp:v1 .-t是给镜像打标签格式是名字:版本冒号后面的版本号如果不写会默认成 latest。我强烈建议每次都写明确的版本号因为 latest 是个移动的目标今天和明天拉到的可能不是同一个东西出问题时没法回溯。末尾那个点很多人会漏它表示构建上下文是当前目录Docker 会把这个目录下的文件传给构建引擎漏了这个点会直接报错。构建过程你会看到每一步输出一个Step每步后面有---跟着一串哈希值。如果某一步显示Using cache说明这一层命中了缓存直接复用。缓存失效的规则是一旦某一层的指令或它复制的文件发生变化这一层以及它后面的所有层都会重新构建。这就是前面强调先复制依赖文件再复制代码的根本原因。想验证镜像构建成功用docker images docker run -d -p 8000:8000 --name myapp-run myapp:v1第一行列出本地所有镜像能看到刚建的myapp和它的体积。第二行的-d让容器在后台运行-p把宿主机的 8000 端口映射到容器的 8000 端口--name给容器起个名字方便后续操作。跑完之后访问localhost:8000就能看到服务响应。实操心得容器起来之后如果立刻退出九成是启动命令有问题。先用docker logs 容器名看输出再用docker run -it myapp:v1 /bin/bash手动进到容器里执行一遍命令报错会直接显示在终端上比看日志猜快得多。5. 国内环境下镜像怎么拿得又快又稳5.1 镜像加速配置的位置与生效验证拉取镜像慢是绕不开的现实问题Docker Desktop 支持配置镜像加速地址。配置入口在设置界面里找到 Docker Engine 那一项编辑器里是一段 JSON加上registry-mirrors字段{ registry-mirrors: [ https://你的专属加速地址 ], builder: { gc: { defaultKeepStorage: 20GB, enabled: true } } }加速地址建议用你实际在用的云服务商提供的专属地址这类地址稳定性和速度都更有保障不要去网上随便找一个公开地址填进去因为公开地址经常失效或者有不可控的风险。改完之后点右下角的 Apply and restartDocker 会重启引擎。验证是否生效用docker info在输出里找Registry Mirrors这一段能看到你配置的地址就说明生效了。如果没看到多半是 JSON 格式写错了比如多了个逗号或者少了引号编辑器自身会对明显语法错误给出提示注意看。除了镜像加速构建过程中的包管理器速度也值得单独处理。Python 用 pip 源、Node 项目用 npm 源、Java 项目用 Maven 源这些都是独立的配置跟 Docker 的镜像加速不是一回事。我的习惯是在 Dockerfile 里把源直接写进对应的安装命令而不是在基础镜像里提前改配置文件这样镜像本身保持干净源只作用于构建过程。5.2 拉基础镜像时怎么挑、怎么省拉基础镜像有两个原则我一直坚持。第一是明确指定版本永远不要用latest。比如要用 Redis 做本地调试我会写redis:7.2-alpine而不是redis。alpine 后缀表示基于体积只有几兆的精简发行版对于只需要跑一个服务的场景完全够用拉取和启动都快得多。但如果你的应用依赖了一些本地编译的二进制库alpine 用的 musl 库可能不兼容这时候换成redis:7.2这种基于完整 Debian 的版本更稳妥。第二是区分开发用和生产用的镜像。开发阶段我倾向于用带完整工具链的镜像方便进容器里调试生产阶段则用精简到极致的版本减少体积也减少潜在风险。这个区分不是形式主义一个完整版本的镜像和一个精简版本可能差好几百兆在 CI 环境里每次构建都要传输累积起来的差距很可观。拉之前可以先看体积再决定用docker manifest inspect 镜像名可以查镜像的结构信息或者干脆在常用的镜像托管站点页面上看体积和层数。养成先看再拉的习惯能避免下了一个几百兆的镜像之后发现用不上。6. 实战问题排查与避坑清单6.1 高频问题速查表下面这些是我和同事在实际使用中遇到过频率最高的问题整理成对照表遇到类似现象可以直接对号入座现象可能原因处理方式启动时提示虚拟化支持未检测到BIOS 未开启虚拟化或系统功能未启用进 BIOS 开启 VT/SVM用命令行启用虚拟机平台功能引擎一直转圈起不来磁盘空间不足或数据目录被安全软件锁定清理磁盘保证 5GB 以上空闲把数据目录加入扫描排除项拉镜像卡住不动或超时未配置镜像加速或加速地址失效在 Docker Engine 配置里填入可用加速地址并重启容器启动后立刻退出启动命令执行失败或前台进程变成后台用 docker logs 看输出用交互模式进容器手动执行端口映射后访问不了宿主机端口被占用或服务监听地址不对换宿主机端口检查服务是否监听在 0.0.0.0构建时提示找不到文件构建上下文路径不对或文件被忽略规则排除确认命令末尾的点检查目录下的忽略文件配置镜像越积越多占满磁盘未清理旧镜像和悬空层用 docker system prune 定期清理注意它会删掉未使用的资源表里最后一条要特别注意docker system prune默认会清掉所有未被容器使用的镜像、网络和构建缓存如果你有只跑过一次的镜像会被一起删掉。想让容器和数据卷也一起清得加-a和--volumes参数但那样删得更狠执行前先跑一次docker system df看清楚会损失什么。6.2 存储、端口、网络三个最容易翻车的地方存储这块最大的隐性问题在 WSL2 模式下容器的数据实际存在 WSL 的虚拟磁盘文件里这个文件会随着时间只增不减。哪怕你在容器里删了文件虚拟磁盘占用的实际空间也不会立刻释放。我的做法是每隔一段时间检查一次数据目录大小必要时用官方提供的磁盘压缩方式回收空间或者重新梳理一下哪些数据该挂在数据卷里、哪些该直接丢掉。数据卷的用法很简单docker run -v mydata:/app/data就是给容器挂一个命名卷名字后面可以复用删容器不删卷这样数据能活着。端口这块的核心是理解映射方向。-p 8080:80意思是宿主机的 8080 对应容器的 80前面是外面、后面是里面这个顺序刚开始很容易搞反。还有一点宿主机端口如果已经被占用了容器会创建失败错误信息里会明确写端口被占用看到这个直接换个宿主机端口就行别去改容器内部的端口因为那要改服务配置麻烦得多。网络这块最常见的问题是容器之间互相访问。默认情况下容器在同一个自定义网络里可以用名字互相解析但如果你用的是默认的桥接网络就只能靠 IP 访问而 IP 是会变的。我的习惯是给一组需要互相访问的容器单独建一个网络docker network create mynet docker run -d --name redis --network mynet redis:7.2-alpine docker run -d --name app --network mynet -p 8000:8000 myapp:v1这样 app 容器里直接写redis这个主机名就能连上 Redis不用关心 IP 是多少。这个做法在本地搭建多服务环境时特别省事比手动查 IP 再改配置靠谱得多。7. 镜像还能怎么玩几个我常用的扩展场景7.1 把现有项目快速装进容器手上已经有一个跑得挺好的项目想容器化其实不需要大改。只要按前面说的方式写出 Dockerfile把依赖安装和应用启动两个环节固化下来剩下的交给构建命令。我通常会先在本地把命令跑通一遍确认每一步都是可重复的再写进 Dockerfile。这个顺序看起来很笨但能避免写完 Dockerfile 之后在构建日志里大海捞针地找错误。等构建稳定之后再考虑把镜像推到自己的私有仓库方便换机器的时候直接拉。7.2 用好数据卷和挂载调试效率翻倍开发阶段我几乎不会把代码真正复制进镜像而是用挂载的方式把本地目录映射到容器里docker run -d -p 8000:8000 -v ${PWD}:/app myapp:v1这样改了本地代码容器里立刻生效重启容器就能看到效果不需要每次重新构建镜像。等要发布的时候再用完整构建把代码固化进去。这套开发挂载、发布打包的流程是我用下来效率最高的组合两边的优势都吃到了。7.3 定期清理是个好习惯容器用得久了镜像、容器、构建缓存会越堆越多。我每个月会跑一次docker system df docker image prune -a docker builder prune第一条看占用情况第二条清理没有被任何容器引用的镜像第三条清理构建缓存。清理之前我会先确认没有正在用的东西被误伤因为-a参数会把所有没被引用的镜像都删掉包括那些你只跑过一次还在用的。我在不同机器上反复装过这套环境最有用的经验其实不是哪条命令而是养成先验证再推进的习惯。装完先跑 hello-world 确认链路通写完 Dockerfile 先在本地把命令跑一遍构建之前先看体积起容器之后先看日志。这些动作每个只花十几秒但能省下大量在报错信息里摸索的时间。真要说哪一步最值得反复琢磨我觉得是 Dockerfile 里的分层顺序因为它直接决定了你以后每次改代码要等多久这一点在项目变大之后感受会特别明显。
返回列表