1. 装 Docker 前先花十分钟理解:为什么同一个安装包,在不同系统上差别这么大
上周帮一个朋友远程排查 Docker Desktop 的启动问题,报错提示是“Docker Desktop failed to start because virtualisation support wasn't detected”。这台电脑是刚买的 Win11 笔记本,配置完全够用,偏偏卡在这一步上不去了。我让他去 BIOS 里打开虚拟化开关,重启后一切正常。事后他问我:Docker 的安装步骤里为什么不写这些?我一时不知道该怎么回答,因为安装 Docker 看起来确实就是下载、点击、下一步,但真正决定你能不能跑起来的,往往是下载之前没几个人看的“环境前提”。
Docker 的安装并不难,难的是理解你正在装的到底是个什么东西。这台机器上跑的是 Windows 还是 Linux,用的是 WSL2 还是 Hyper-V,BIOS 里的虚拟化开关有没有开,当前系统版本是不是太老,镜像下载为什么慢,这些问题的答案才真正决定安装过程是否顺利。这篇内容适合两类人看:一类是刚接触 Docker、想在 Windows 或 Linux 上装环境跑 MySQL、Redis 的新手;另一类是已经照着教程装过但频繁踩坑,想系统搞清楚原因的老读者。我会从环境检查、安装动作、启动报错排查,一直讲到用 MySQL 8.0 和 Redis 做一轮真实部署验证,把整个链路完整走一遍。
1.1 Docker Desktop、Docker Engine、镜像和容器到底是什么关系
很多报错问题都源于概念没对齐。先理清几个最常见词的关系。
Docker Engine 是真正干活的程序,它负责管理容器生命周期、镜像、网络和存储,在 Linux 上通常通过 dockerd 这个守护进程运行。Docker Desktop 则是一个带图形界面的壳,把 Docker Engine 打包进去,并额外处理了虚拟机、网络、文件挂载等兼容层,目的是让你在 Windows 和 macOS 上也能用 Docker。可以说 Docker Desktop 是“打包好的全家桶”,Docker Engine 是底层引擎。服务器上装 Docker 通常只装 Engine,不装 Desktop。
镜像和容器的关系则可以类比成“程序安装包”和“运行中的程序”。镜像是一个只读的模板,里面包含了程序代码、系统库、环境变量等一切运行所需的文件。容器是由镜像创建出来的运行实例,你可以在里面改文件、跑命令,甚至删除再重新创建一个一模一样的容器。安装 Docker 只是第一步,真正日常打交道最多的是拉取镜像和创建容器。
这个概念如果没有建立起来,后面很容易出现两类误解:一类人以为 Docker Desktop 没打开就是 Docker 没装好,另一类人在 Linux 上明明启动了 dockerd 却到处找图形界面。先搞清楚你在哪一层操作,后面所有命令才有意义。
1.2 为什么 Windows 不能像 Linux 一样直接原生跑 Docker
Docker 容器之所以轻量,核心在于 Linux 内核提供的命名空间(Namespace)和控制组(Cgroups)。命名空间让每个容器以为自己拥有独立的主机名、网络栈、进程表和文件系统,控制组则限制容器能使用的 CPU、内存和磁盘资源。同一个内核被逻辑隔离成多个互不干扰的“小空间”,这就是容器比虚拟机轻量得多的原因。
问题在于,Windows 内核不是 Linux 内核,它没有原生提供同一套命名空间机制。Windows 上的 Docker 必须借助虚拟化层帮它创建一个 Linux 虚拟机,然后在虚拟机里跑 Docker Engine。Docker Desktop 在 Windows 上默认使用 WSL2(Windows Subsystem for Linux Version 2)后端,WSL2 本身就是一个轻量虚拟机,里面运行着真正的 Linux 内核,Docker 再从这个虚拟 Linux 环境里跑起来。
这也是你为什么会看到那么多关于“虚拟化支持未检测到”的报错。因为整个链路的第一环就是 CPU 的虚拟化功能,如果 BIOS 里没开虚拟化,WSL2 无法创建虚拟机,Docker Desktop 自然启动失败。在拿到一篇安装教程之前,先确认你的硬件和系统满足了这个前提,比任何命令都重要。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Windows 装 Docker Desktop 的正确顺序:环境检查、安装、启动报错排查
先说 Windows 上的安装。这件事的难点集中在两个地方:环境检查和启动报错。安装包本身没有太多技术含量,点击下载后不断下一步即可,但如果环境不对,下一步完大概率在第一次启动时看到花式报错。
2.1 装之前必须确认的三件事
第一,确认 Windows 版本符合要求。Docker Desktop 当前版本对系统有明确要求,比如 Windows 10 64 位专业版/企业版/教育版要求 21H2 或更高,Windows 11 则要求 21H2 或更高。家庭版也能装,但要靠 WSL2 后端完成。如果你装完直接看到“we've detected that you have an incompatible version of Windows”之类的提示,说明系统版本不在官方支持列表里,这种情况下先升级系统,不要手动绕过检测,绕过之后会遇到更多奇怪问题。
第二,确认 CPU 虚拟化已开启。打开任务管理器,切到“性能”选项卡,点“CPU”,看右下角的“虚拟化”一栏是不是“已启用”。如果是“已禁用”,那就需要重启电脑,在开机时按 Del 或 F2 进入 BIOS/UEFI,找到 Intel Virtualization Technology(Intel VT-x)或 AMD SVM Mode 选项,设置为 Enabled。笔记本厂商不同,这个选项的位置差异很大,但搜索关键字基本能定位。改完保存重启,再回任务管理器确认。
第三,确认 WSL2 相关功能已启用。以管理员身份打开 PowerShell,执行两条命令:
powershell复制dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
执行完成后重启系统,然后运行 wsl --set-default-version 2。如果你的系统之前装过 WSL1 发行版,或者内核组件较旧,还需要执行 wsl --update 把内核更新到新版本。这一步很多人会忽略,结果 Docker Desktop 安装了却一直起不来。
下面用表格把这几个检查项整理成清单,方便对照:
| 检查项 | 查看位置/命令 | 期望状态 |
|---|---|---|
| Windows 版本 | 设置-系统-关于 | Win10 21H2+ 或 Win11 21H2+ |
| CPU 虚拟化 | 任务管理器-性能-CPU | 虚拟化:已启用 |
| WSL 功能 | 管理员 PowerShell 执行上述 dism 命令 | 执行成功,无报错 |
| WSL 默认版本 | wsl --set-default-version 2 |
命令执行成功 |
| 系统重启 | 操作完成后 | 必须重启一次 |
这些检查看起来琐碎,但每一条都能单独卡住安装。我见过太多人跳过检查直接装 Docker Desktop,装完启动报错后才发现是虚拟化没开,白折腾半小时。
2.2 一键安装之外:Docker Desktop 安装向导里的那些选项都意味着什么
环境检查通过后,去官网下载 Docker Desktop 安装包。下载的是 exe 文件,双击启动后基本可以直接点 OK。有一个选项需要留意:安装向导会询问是否使用 WSL 2 而不是 Hyper-V,保持默认勾选即可。WSL2 在现代 Windows 上资源占用更低、启动速度更快,Docker 官方也已经把 WSL2 作为默认后端。
安装完成后通常需要注销并重新登录一次系统,让 Docker Desktop 能以正确用户权限启动。第一次启动时,Docker Desktop 会弹出一个服务协议确认框,点 Accept 后它会自动启动 WSL 下的 Docker Engine。这一步在首次启动时耗时较长,因为要初始化虚拟磁盘和 Linux 子系统的内部组件,耐心等待即可。
启动成功后,Windows 右下角任务栏会出现 Docker 图标,状态显示为 Docker Desktop is running。这时打开终端,运行 docker version,能看到 Client 和 Server 两段信息。注意很多人只看 Client 有输出就以为成功了,其实只有 Server 段也正常返回,才说明 Engine 真的在运行。如果 Server 段提示 Cannot connect to the Docker daemon,说明 Desktop 还没完全启动,或者后端虚拟机有问题,等一会儿再试。
2.3 “Virtualization support wasn’t detected”这类启动报错的排查顺序
Docker Desktop 最常见的启动失败报错就是“Docker Desktop failed to start because virtualisation support wasn't detected”。这个英文提示的字面意思是“没有检测到虚拟化支持”,但它实际可能来自四个层面的问题:
第一层是 BIOS 虚拟化开关未开启,这是最常见的原因。按上面说的,重启进 BIOS 打开 VT-x 或 SVM,操作门槛不高,但很多人卡在找不到选项上。不同主板厂商的菜单层级差异较大,有些藏在 Advanced 菜单里,有些在 Configuration 菜单里。如果实在找不到,直接搜“主板型号 + Virtualization”通常能找到具体路径。
第二层是相关 Windows 功能没有启用。WSL 功能、虚拟机平台功能没有启用,导致 Docker Desktop 无法创建虚拟化后端。回到管理员 PowerShell,运行 systeminfo 命令,看输出的最后部分,Hyper-V 相关要求是否都显示为“是”。如果有“否”,回到上一小节的 dism 命令操作一遍,重启即可。
第三层是 WSL2 内核版本问题。运行 wsl --status 查看当前默认版本,如果输出提示 WSL2 需要更新内核,执行 wsl --update。更新后最好重启一次 Docker Desktop。
第四层比较隐蔽,一般出现在虚拟机里再装 Docker Desktop 的场景。如果你是在 VirtualBox 或 VMware 创建的 Windows 虚拟机里安装,需要在虚拟机软件设置中开启嵌套虚拟化。VirtualBox 对应“启用 VT-x/AMD-V 嵌套虚拟化”选项,VMware Workstation 则在虚拟机 CPU 设置中勾选“虚拟化 Intel VT-x/EPT 或 AMD-V/RVI”。物理机上不会遇到这个问题,但如果是在云桌面、虚拟机环境里装,排到这一步才可能解决。
还有一个相对少见但真实存在的情况:部分老版本 Windows 上 Docker Desktop 的检测逻辑会误判。如果你的系统版本偏低,比如 Windows 10 1909 之前,就算虚拟化已开启也可能会报错。这时的主线是升级系统,而不是折腾 Docker 配置。我的建议是,遇到启动报错先按 BIOS -> Windows 功能 -> WSL2 内核 -> 嵌套虚拟化这个顺序排查,大概率能定位到根因。
3. Linux 服务器安装 Docker Engine:从换源到权限坑,再到服务起不来怎么查
Windows 上折腾的是 Docker Desktop,Linux 服务器上则是安装 Docker Engine。这里没有图形界面,命令就是全部。相比 Windows,Linux 安装过程的报错通常更明确,但也更考验对基础命令的熟悉程度。
3.1 Ubuntu/Debian 系:apt 安装的标准流程
以 Ubuntu 为例,最稳妥的方式是通过 Docker 官方 apt 仓库安装,这样可以获得后续的自动更新支持。先安装依赖包,再添加 Docker 的 GPG 密钥和软件源。完整命令如下:
bash复制sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
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
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/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
这套流程里很多人会卡在第二步和第三步之间。GPG 密钥下载成功不代表软件源文件写入成功,如果你发现 apt update 后看不到 docker-ce 的候选版本,先检查 /etc/apt/sources.list.d/docker.list 文件是否存在、内容里的系统代号是否和 lsb_release -cs 输出一致。
安装完成后执行:
bash复制sudo systemctl enable docker --now
sudo systemctl status docker
第一行命令把 Docker 服务设为开机自启并立即启动,第二行查看运行状态。看到 active (running) 字样就说明安装成功。
3.2 CentOS/RHEL 系:yum 安装的差异点
CentOS 7 虽然已经停止维护,但在存量服务器里仍然大量存在。CentOS 的安装流程类似,只是包管理器从 apt 换成了 yum:
bash复制sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable docker --now
有两个细节值得注意。CentOS 7 默认的防火墙规则可能阻止容器流量,如果你在 CentOS 上跑容器后外部无法访问,检查 firewalld 是否放行了对应端口。另外 CentOS 的内核版本相对陈旧,如果后续遇到奇怪的网络问题或容器启动失败,先确认 uname -r 的内核版本是否在 3.10 以上,过老的内核会影响 Docker 的 overlay2 存储驱动支持。
3.3 国内服务器换源和官方脚本之间的选择
很多国内云服务器上直接访问 Docker 官方源可能速度很慢,这时有两种替代方案。
一种方式是使用国内云厂商提供的 Docker 镜像源。比较通用的是阿里云、腾讯云等云平台提供的开源软件源,它们都有对应的 Docker 安装源配置方法。在 /etc/apt/sources.list.d/docker.list 文件里把 https://download.docker.com 替换成你所用云厂商的镜像源地址即可。不同平台有各自的文档和专用地址,搜索“Docker CE 镜像 + 平台名”能找到对应的配置内容。
另一种方式是使用 Docker 官方提供的自动安装脚本:
bash复制curl -fsSL https://get.docker.com | bash
这个脚本会自动检测系统、配置源并安装 Docker Engine,非常省事。但它有两个问题:一是脚本默认安装官方源,在你网络环境不理想时反而更慢;二是脚本执行方式是把远程内容直接通过管道交给 bash 执行,虽然这是 Docker 官方提供的合法脚本,但对于严谨的服务器操作来说不够透明。我在自己的服务器上更倾向手动执行仓库配置的流程,虽然敲的命令多,但每一步发生了什么都很清楚。
3.4 非 root 用户免 sudo 使用 Docker,以及服务启动失败的排查思路
安装完成后,每次执行 docker 命令都带 sudo 是一件非常痛苦的事。Docker 守护进程默认以 root 身份运行,并且只会给 root 用户和 docker 用户组内的成员开放 socket 访问权限。你可以把当前用户加入 docker 组来免去 sudo:
bash复制sudo usermod -aG docker $USER
newgrp docker
执行完上面两行后,当前终端会话里 docker 命令就不需要 sudo 了。这里有一个重要的安全提醒:docker 组权限等同于 root 权限,因为用户可以通过挂载宿主机目录进入容器,进而访问宿主机任意文件。如果不是单用户开发机,不要在多人共用的生产服务器上把所有账号都加进 docker 组。
Docker 服务启动失败是 Linux 安装过程中另一类高频问题。执行 sudo systemctl status docker 如果看到 failed 状态,先用下面的命令查看详细信息:
bash复制journalctl -u docker --no-pager -n 50
日志里最常见的有几类信息:磁盘空间不足导致无法初始化、iptables 配置冲突、SELinux 阻止等。磁盘问题可以用 df -h 快速确认;iptables 冲突通常出现在你用 Docker 之前已经配置了大量自定义防火墙规则的环境里;SELinux 问题则多见于 CentOS 环境,如果确认是 SELinux 导致的容器启动受限,可以先将 SELinux 设置为 permissive 模式观察验证,再决定是否长期调整。
我的建议是不要一上来就关 SELinux 或 firewalld,而应该先看日志定位是哪种类型的失败。盲目关闭系统安全机制短期内能解决问题,但会在后续运行中埋下更大的安全隐患。
4. 镜像下载慢的根因和加速器配置实操
装好 Docker 之后的第一个感知差异,往往发生在拉取镜像的那一刻。一条 docker pull mysql:8.0 命令可能要等上十几分钟,进度条走一步退两步。这个问题的核心不在 Docker 本身,而在于 Docker Hub 的服务器部署位置与你的网络之间存在较高的延迟和带宽限制。
4.1 镜像下载慢到底慢在哪
镜像仓库本质上是一个静态文件服务器,Docker 客户端把镜像分成多个层(Layer)并行下载。每层都是一堆压缩文件,大的镜像如 MySQL、Redis 可能只有几十到几百 MB,但像带完整系统的镜像或者机器学习相关的镜像动辄几个 GB。跨地域拉取大文件时,限制通常来自两台机器之间的实际传输速度,而不是 Docker 的并发能力。
这类问题在云服务器上有一个明显规律:同样是国内服务器,不同云厂商可能差异不大,因为出口线路都受整体网络环境影响。解决方案不是去调整 Docker 的并发参数,而是配置一个网络路径更短的镜像加速器。
4.2 配置 registry mirror:原理和操作方式
Docker 支持配置 registry mirror(镜像加速器)。当 Docker 尝试拉取镜像时,会先访问这个镜像加速器,加速器会代为请求 Docker Hub 并把镜像内容缓存下来。你不需要改变任何已有的使用习惯,docker pull mysql:8.0 还是这条命令,流量会自动走加速器。
配置文件是 /etc/docker/daemon.json。用编辑器打开或新建这个文件,内容如下:
json复制{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
具体使用哪些加速地址,需要结合你所在网络环境测试。很多云厂商也提供容器镜像加速器服务,比如阿里云容器镜像服务控制台会给每个用户分配一个专属加速地址,格式类似 https://xxxx.mirror.aliyuncs.com,登录控制台即可查看。这类专属地址通常比公共地址更稳定,但需要你先注册并开通对应服务。
配置完成后,重启 Docker 服务使配置生效:
bash复制sudo systemctl daemon-reload
sudo systemctl restart docker
验证是否生效可以执行:
bash复制docker info
在输出里找 Registry Mirrors 一段,看到你配置的地址就代表生效了。我建议在配置文件中多写两三个可用的加速地址,这样一旦某个加速器不可用,Docker 会自动尝试下一个,避免所有镜像拉取全部卡死。
4.3 除了加速器,还有哪些影响拉取速度的因素
镜像加速器不是万能的。第一,它只对 Docker Hub 官方仓库的镜像有效。如果你拉取的是 ghcr.io、quay.io 这类第三方仓库里的镜像,加速器帮不上忙,需要走其他方式,比如将镜像下载到本地后用 docker load 导入服务器,或者在更合适的网络环境下先拉取再导出。第二,镜像本身没有下载完成前,进度条卡住也可能是网络断流导致的,可以反复按 Ctrl+C 取消再重新执行 docker pull,Docker 会从断点继续下载已完成的层。第三,DNS 解析问题也会导致拉取超时,如果提示 EOF 之类的错误,可以检查 /etc/resolv.conf 配置是否正常。
还有一个容易被忽略的点:docker pull 默认从 latest 标签拉取镜像时,Docker 需要先去 Docker Hub 查询该标签对应的确切版本号,这个查询过程如果网络不通,镜像层数据还没开始传输就已经报错了。所以遇到拉取失败不要只盯着进度条,把完整报错信息拿到手,先判断是 DNS、连接超时还是权限问题,再对症处理。
5. 装完之后用 MySQL 8.0 和 Redis 主从做一轮真实部署验证
环境装好、镜像能拉了,下一步就是用实际服务来验证整套环境是否真的可用。这里没有比数据库更适合的测试对象了。很多人的第一个 Docker 需求就是装 MySQL 或 Redis,因为这类服务在宿主机上直接安装需要处理依赖、系统服务、目录权限等一堆琐事,而 Docker 容器化之后往往几条命令就能跑起来。
5.1 MySQL 8.0 单机部署:端口、密码和数据卷
执行下面的命令创建 MySQL 8.0 容器:
bash复制docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=Root@123456 \
-e TZ=Asia/Shanghai \
-v mysql-data:/var/lib/mysql \
mysql:8.0
逐个解释一下每个参数:
-d让容器在后台运行。--name mysql8给容器起名,方便后续执行 docker exec 或 docker stop 时引用。-p 3306:3306把宿主机的 3306 端口映射到容器内的 3306 端口。容器有自己的网络栈,外部访问需要经过这个映射。如果宿主机 3306 端口已被占用,可以把左边改成 33061,比如-p 33061:3306。-e MYSQL_ROOT_PASSWORD=Root@123456设置 MySQL root 用户密码。这是 MySQL 官方镜像规定的初始化环境变量,第一次启动容器时会读取它完成数据库初始化。密码需要足够强度,生产环境尤其不要把弱密码写在命令行里,更推荐使用 Docker Secret 或环境变量文件的方式传入。-e TZ=Asia/Shanghai设置容器时区,避免容器内默认 UTC 时间和宿主机时间相差 8 小时,导致日志时间对不上。-v mysql-data:/var/lib/mysql创建命名卷并挂载到容器内的数据目录。这是整个命令里最关键的一项,MySQL 所有数据文件都存在这个目录,即使容器被删除,数据仍保留在命名卷中。mysql:8.0是镜像名称和标签。建议显式指定小版本标签,比如mysql:8.0.32,避免之后latest指向的大版本变化带来不兼容问题。
启动后等待十几秒,让 MySQL 完成初始化。检查容器状态:
bash复制docker ps
状态是 Up 之后,进入容器内部连接 MySQL:
bash复制docker exec -it mysql8 mysql -uroot -p
输入之前设置的密码,看到 mysql> 提示符就说明部署成功了。如果想从宿主机连接容器内的 MySQL,需要在启动命令里额外确认端口映射是否正常,并注意 MySQL 8.0 默认 root 用户只允许 localhost 登录。如果你需要通过外部客户端远程连接,需要在初始化时指定 -e MYSQL_ROOT_HOST=%,表示允许任意主机使用 root 登录,但生产环境我更推荐单独创建应用账号来连接,而不是开放 root 远程权限。
5.2 Redis 主从部署:用 docker compose 管理多个容器
Redis 的部署和 MySQL 类似,但如果要搭一组主从结构,单个 docker run 命令就会变得冗长且难维护。这时候更适合用 Docker Compose,它能把多个容器的启动配置写进一个 YAML 文件,之后一条命令全部拉起。
先确保 docker compose 插件已安装,执行 docker compose version 验证。然后在一个目录下创建 docker-compose.yml,内容如下:
yaml复制services:
redis-master:
image: redis:7
container_name: redis-master
command: ["redis-server", "--appendonly", "yes"]
ports:
- "6379:6379"
volumes:
- master-data:/data
redis-slave:
image: redis:7
container_name: redis-slave
command: ["redis-server", "--replicaof", "redis-master", "6379"]
ports:
- "6380:6379"
depends_on:
- redis-master
volumes:
- slave-data:/data
volumes:
master-data:
slave-data:
说明两个关键点:slave 容器的启动命令里 --replicaof redis-master 6379 就是让它作为 master 的从库,这里的 redis-master 不是 IP,而是 compose 内部网络中另一个容器的服务名,Compose 会自动完成 DNS 解析;depends_on 保证 master 先启动再启动 slave,避免从库在第一次启动时找不到主库。
进入这个目录,执行:
bash复制docker compose up -d
再执行 docker compose ps 查看两个容器的状态。然后进入 slave 容器检查主从关系:
bash复制docker exec -it redis-slave redis-cli info replication
输出中 role:slave 且 master_link_status:up 就说明主从同步正常。可以在 master 里写入一条数据,再到 slave 里读取验证:
bash复制docker exec -it redis-master redis-cli set site docker-install
docker exec -it redis-slave redis-cli get site
能读到值,主从链路就完全通了。这套配置同时解决了端口映射、持久化、服务依赖和网络互联的问题,比手敲三四个 docker run 命令可靠得多。
5.3 重启后数据还在吗:验证持久化和 Docker Desktop 的资源占用
部署完成后的第一轮验证只是看服务能不能跑起来,更重要的一轮是验证数据在容器重建后是否还在。MySQL 的命名卷挂在 /var/lib/mysql 下,Redis 的 appendonly 文件放在 /data 下。如果我把容器删掉再重新创建,数据不会丢,因为命名卷的生命周期独立于容器。
你可以动手演示一次:先执行 docker rm -f mysql8 删除 MySQL 容器,再重新执行第一条 docker run 命令。启动完成后重新连接 MySQL,之前创建的数据库和表依然存在。这个特点与直接在宿主机上安装软件有本质区别,也是很多人选择用 Docker 跑数据库的重要原因。
这里额外补充一个 Windows 用户关心的问题:Docker Desktop 默认把所有虚拟磁盘文件放在 C 盘用户目录下,随着你拉取的镜像越来越多,C 盘空间会肉眼可见地缩减。如果发现 C 盘吃紧,打开 Docker Desktop 的 Settings,在 Resources -> Advanced 页面里,可以把 Disk image location 改成其他盘符,然后点 Apply & Restart。改完之后,之前的镜像和数据卷并不会自动迁移,需要你提前用 docker system df 检查一下当前占用情况,再决定是保留重置还是合理清理。
如果只是想把旧的 docker-desktop-data 发行版迁移到 D 盘,可以在关闭 Docker Desktop 后用 wsl 命令导出再导入,但整个操作链路比较长,不是每次都需要。对大多数人来说,尽早去 Settings 里把存储路径改掉,比等 C 盘满了再处理要省事得多。
6. 容器日常维护的核心命令,和安装完成后才会浮现的真实教训
到了这一步,你的 Docker 环境已经能正常拉镜像、跑容器、部署 Redis 主从。但安装完成只是起点,后面的日常使用才是真正检验你对 Docker 理解程度的环节。很多人在部署成功后的第二天就遇到了“容器怎么又没了”“镜像怎么占了这么多空间”“日志怎么把磁盘写满了”等问题。掌握下面这些维护命令和相关意识,能省掉大量重复踩坑的时间。
6.1 常用命令速查
日常最常用的 Docker 命令集中在下面这几类:
| 用途 | 命令 |
|---|---|
| 查看正在运行的容器 | docker ps |
| 查看所有容器(含已退出) | docker ps -a |
| 停止容器 | docker stop 容器名 |
| 启动已停止的容器 | docker start 容器名 |
| 删除容器 | docker rm 容器名 |
| 查看容器日志 | docker logs -f --tail 200 容器名 |
| 进入容器终端 | docker exec -it 容器名 bash |
| 查看本地镜像 | docker images |
| 删除镜像 | docker rmi 镜像ID |
| 查看磁盘占用 | docker system df |
| 一键清理悬空资源 | docker system prune |
值得专门提醒的是,docker exec -it 容器名 bash 进入的是容器内部的 shell,而不是宿主机的 shell。很多人在容器里装软件、改配置,然后发现容器一旦被删除,所有修改全部丢失。容器本身的文件系统是可写层,但它依赖于创建它的镜像,正确的做法是把需要持久化的数据写到挂在卷里,或者把自定义配置通过环境变量和配置文件挂载的方式传进去。
关于日志,建议养成启动容器时就加上日志大小限制的习惯。在 docker run 命令里加 --log-opt max-size=10m --log-opt max-file=3,或者在使用 compose 时为每个服务配置 logging 相关参数。如果一开始不限制,日志文件会不断增长,最终占满磁盘,轻则容器写不了日志,重则整个服务器磁盘满载,后果在数据库容器上尤其严重。
6.2 清理镜像和容器的正确顺序,避免误删数据卷
镜像、容器、命名卷之间的关系容易让人在清理时犯迷糊。容器依赖镜像,命名卷的数据则独立存在。执行 docker system prune -a 会删除所有未被容器使用的镜像和网络,但不会动命名卷,这是相对安全的一键清理方式。
如果你需要彻底释放空间,连命名卷一起清理,需要显式执行 docker system prune -a --volumes。这个命令会删掉所有没有被容器引用的命名卷,意味着之前 MySQL 容器挂载的数据卷也会被删,没有备份的话数据就彻底没了。我的建议是:数据卷的清理永远用手动方式确认,不要用带 --volumes 的一键命令。先执行 docker volume ls 看清单,再逐个 docker volume rm 删除,虽然动作慢了,但每一删都在自己的掌控里。
6.3 安装成功只是起点:我踩过的几个“看似无关”的坑
最后分享几个我自己在实际操作中反复遇到的问题,希望能帮你少走弯路。
第一个坑是容器时区问题。第一次用 Docker 跑 MySQL 时,我创建完容器没有加 -e TZ=Asia/Shanghai,程序里记录的时间比北京时间慢了 8 个小时。排查了很久才发现是容器默认 UTC 时区的缘故。解决方案也很简单,在创建容器的环境变量里再加上 TZ 配置,或者在 compose 文件里指定 environment: - TZ=Asia/Shanghai。看起来是一行参数的差别,实际影响却非常隐蔽。
第二个坑是镜像标签变化。mysql:8.0 这个标签会跟着 8.0 系列的小版本更新走,比如你三个月前拉的是 8.0.32,三个月后再拉 mysql:8.0 时拿到的是 8.0.36。小版本升级通常伴随行为变化,如果你对版本有严格管控需求,必须在镜像标签上写明具体小版本号。一个可靠的生产习惯是创建容器前先确认镜像 digest,并锁定到具体版本。
第三个坑和端口占用有关。之前在服务器上启动一个 MySQL 容器,提示 port is already allocated,排查后发现是系统里残留的另一个容器占用着 3306 端口。Docker 的端口分配错误提示往往不会直接告诉你是哪个进程占用的,需要自己用 docker ps -a 把所有容器翻一遍,或者用系统命令检查端口占用。知道这个方向,排查会快很多。
这些坑都有一个共同特点:单看 Docker 官方文档不会让你注意到,它们全发生在“环境已经装好、命令能跑”的真实场景里。从安装到部署再到维护,Docker 的价值在于帮你把应用和环境解耦,但前提是你对容器的数据、网络和资源管理有足够掌控。装得好只是开始,用得稳才是真功夫。之后如果再遇到 Docker 相关的奇怪现象,记住先看日志、再查配置、最后动手清理,这个顺序永远不会错。
