1. 先搞清楚 Docker 到底是个什么东西每次有朋友问我“Docker 包括哪些内容”我都会先反问一句你手上这台电脑装系统是不是也得先分区、再装驱动、再装软件Docker 干的事情本质上就是把这个过程彻底工业化——你写好一张“配方”不管换哪台机器照着配方就能把应用环境原样“烹饪”出来。Docker 本身不是一个单一软件而是一整套容器化技术体系的统称。我最早接触它的时候也以为“装个 docker 命令就完事了”后来踩了几次坑才发现这套东西至少包含四块引擎Engine、对象Objects、仓库Registry、编排工具Orchestration。如果只用其中最基础的一块你也能跑起来但只有理解全貌才能处理那些“为什么我的容器连不上网”“为什么重启后数据全没了”这类疑难杂症。所以这篇内容我打算从这几个维度把 Docker 拆开讲核心组件、常用操作对象、各类命令的实际用途以及从热搜里刷屏最多的安装、镜像、网络、权限那些高频问题。看完你至少能明白Docker 的“内容”不只是一条docker run而是一整套可以支撑开发、测试、生产部署的容器化解决方案。2. Docker 的体系架构引擎、客户端、仓库三件套2.1 Docker Engine真正干活的“后台工人”Docker Engine 是整套体系的心脏。它本身是一个后台服务进程在 Linux 上一般叫dockerd在 Windows 和 macOS 上由 Docker Desktop 代为管理。这个进程负责几件事拉取镜像、创建容器、管理网络、分配存储、隔离资源。你可以把它想象成一个酒店的厨房总管。你客户端递过去一份菜单docker run命令总管不会自己亲自炒菜而是指挥一个个厨师容器运行时完成具体的操作。这里的“厨师”是containerd——它是 Docker 目前默认的底层容器运行时负责真正启动和销毁容器进程。如果你在排查问题的时候看到containerd进程别慌那不是在“抢活”那本来就是 Docker 的“首席厨师长”。很多新手会混淆“Docker”和“VMware/VirtualBox”这类虚拟机。虚拟机是把整台电脑模拟出来里面要装完整操作系统Docker 是利用 Linux 内核的 Namespace 和 Cgroup 特性在同一个内核上隔离进程、文件系统、网络栈和资源配额。类比一下就明白了虚拟机是“新的房子”每个房子要自带水电煤容器是“同一栋楼里隔出来的房间”水电煤用大楼的但房间之间墙是实的、门是锁的。2.2 Docker CLI 和 Docker Desktop你手里的“点菜单”Docker CLI 是命令行客户端它不干重活只负责把你的意图传给 Engine。比如你敲docker pull nginxCLI 就把“拉取 nginx 镜像”这个请求发给dockerddockerd再去仓库拉镜像。在 Windows 和 macOS 上Docker 官方提供了 Docker Desktop。这个东西我在热搜里看到频率极高评论区问得最多的就是“Virtualization support not detected”和“Docker Desktop 启动失败”。我后文会专门讲这个问题这里先强调一点Docker Desktop 在 Windows 上依赖 WSL2 或 Hyper-V你得先在 BIOS 里打开 CPU 虚拟化再装好 WSL 内核更新包否则它连启动都过不去。如果你更追求轻量Linux 上根本不需要 Docker Desktop装好docker-ce和docker-compose-plugin就够了。Docker Desktop 是给桌面系统准备的便利工具不是 Docker 的必需组成。2.3 Registry 镜像仓库所有镜像的“超市”镜像仓库是 Docker 体系里容易被忽略、但绝对不可缺的组件。官方公开仓库叫 Docker Hub你在上面能拉到nginx、mysql、redis、ubuntu这些基础镜像。企业内部大多会用 Harbor、Nexus 或阿里云容器镜像服务搭私有仓库。从热搜词里看“docker 镜像下载慢”这个坑几乎人人踩过。原因很简单Docker Hub 服务器在海外国内直连延迟高、速度慢。解决方案也成熟在/etc.docker/daemon.json里配置国内镜像加速器或者在拉取时通过--pull指定私有源。这块细节我放到第 5 章讲安装部署时再展开。2.4 编排工具从“管一个容器”到“管一窝容器”单机跑两三个容器命令手动敲就行。但当你部署微服务项目前后端、数据库、消息队列加起来几十个容器靠手动敲命令就是噩梦。这时候你需要编排工具最常见的是 Docker Compose 和 Kubernetes。Docker Compose 是 Docker 官方自带的轻量编排工具通过一个docker-compose.yml文件定义多个服务、网络、卷的关系然后docker compose up -d一键启动整套环境。我前面提到的“docker 部署微服务项目”“docker dify”“gitlab 社区版 docker 部署”这些场景全部可以用 Compose 一把梭。Kubernetes简称 K8s属于更高一层的集群编排它管的不只是“启动哪个容器”还包括自动化伸缩、故障转移、服务发现。我这篇内容主要讲 Docker 本身所以 K8s 就点到为止但你要记住Docker 和 K8s 不是替代关系K8s 是站在 Docker 肩膀上加了一层“自动调度经理”。3. 核心对象逐个拆解镜像、容器、网络、数据卷3.1 镜像只读的“模板”镜像Image是容器的模板它是一层层只读文件系统的集合。每一条 Dockerfile 指令比如FROM、RUN、COPY都会生成一个新层。这种方式的好处是多个镜像可以共享底层比如mysql和redis都可能基于debian或alpine的底层公共层只存一份节省磁盘空间也加速拉取。实际操作中镜像的“分层”特性会带来一个反直觉的坑你删除镜像文件不代表释放全部空间因为其他镜像可能还在引用同一层。很多人用docker system prune -a想清理磁盘发现空间没回多少就是因为公共层还在被引用。看镜像层信息用docker history 镜像名只看列表用docker images。镜像的命名要特意说一句完整镜像名一般是仓库地址/命名空间/镜像名:标签。比如mysql:8.08.0是标签默认不写标签时拉取latest。生产环境千万别用latest因为同一个标签每次拉到的内容可能不同今天就部署没问题明天再pull可能就升级成不兼容版本了。我吃过这个亏一台服务器上mysql:latest某天从 8.0 悄悄变成了 8.4字段兼容性出问题排查了一下午。3.2 容器镜像的“运行时实例”容器Container是镜像运行起来之后的状态。每启动一个容器Docker 会在镜像之上加一个可写层你把文件写进去、安装软件都发生在这一层。容器可以start、stop、restart、rm但注意容器停止后它的可写层数据仍然存在只有docker rm删掉容器数据才会跟着没。怎么理解“容器和镜像的关系”我用一个做饭的类比镜像就是菜谱模板容器就是照着菜谱做出来摆上桌的一道菜实例。你可以拿同一本菜谱做一百盘一模一样的菜就像同一个镜像可以启动很多个互不影响的容器。实际操作里容器是用来“跑进程”的不是用来“装系统”的。很多新手习惯像用虚拟机一样docker run -it ubuntu bash进容器然后手动装 MySQL、改配置。这完全用反了。容器的正确用法应该是用docker run指定一个镜像让它在里面直接执行你定义的启动命令比如mysqld、redis-server配置通过环境变量、挂载文件传入而不是进容器里手动改。一旦你开始“手动进容器改东西”下一步就应该考虑把这些改动固化到 Dockerfile 里否则容器一删一切白搭。3.3 网络容器怎么“互相找得到”Docker 的网络模式是很多人的知识盲区。“docker 网络不通”这个热搜词我太熟悉了十个网络问题里八个是网络模式没搞明白。Docker 默认提供几种网络bridge默认模式容器通过一个虚拟网桥和一个私有子网互连外部访问需要做端口映射-p 宿主机端口:容器端口。host容器直接使用宿主机的网络栈性能好但端口容易冲突、隔离性差。none容器没有网络。overlay用于跨主机的 Swarm 或其他集群网络场景单机一般不用。同一台机器上多个容器要互相访问最推荐的做法是把它们都挂到同一个自定义 bridge 网络里docker network create mynet然后用容器名互相解析而不是靠 IP。这是我在部署微服务项目时领悟最深刻的一点容器重启后 IP 会变但容器名不会变用service-name做通信地址比写死 IP 稳健得多。还有一个高频问题我在搜“docker desktop 使用教程”时总能看到有人问为什么容器里能上网宿主机访问容器端口不通这通常不是防火墙问题而是端口映射写错了。比如docker run -p 8080:80 nginx你要访问的是宿主机IP:8080不是8080:80里的那个 80。方向反了、要么防火墙拦了、要么绑定地址写了127.0.0.1这三板斧能解决绝大多数端口访问问题。3.4 数据卷让“临时”变“持久”镜像是只读的容器一删可写层就没了。但生产环境的数据数据库文件、日志、配置文件不能跟着容器一起消失。Docker 的解决方案是数据卷Volume和绑定挂载Bind Mount。数据卷是由 Docker 管理的持久化目录用-v volume_name:/容器内路径挂载绑定挂载则是把宿主机某个目录直接映射进去用-v /宿主机路径:/容器内路径。两者的本质区别就一句话卷的位置 Docker 帮你管绑定的位置你自己定。我实际部署 MySQL 时一般这样写docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDYourPassword \ -v mysql-data:/var/lib/mysql \ mysql:8.0这里把 MySQL 的数据目录/var/lib/mysql挂载到名为mysql-data的卷里。以后升级镜像、重建容器数据都还在。反过来如果你偷懒不挂卷容器一删数据库文件全没MySQL 启动要求必须有datadir下次重建时你再挂也会因为“目录非空且无权限”遇到麻烦。这是新人最惨烈的事故现场之一。4. Dockerfile 和 docker-compose把“过程”固化成“内容”4.1 Dockerfile用代码描述“镜像怎么建”Docker 的内容不仅仅是“用别人做好的镜像”更包括“自己制作镜像”。制作镜像的核心文件就是 Dockerfile。它的语法不难但有几个关键点值得展开。一份典型 DockerfileFROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [python, app.py]每一条指令的含义FROM指定基础镜像是构建的起点。WORKDIR切换工作目录等同于cd。COPY从宿主机复制文件进镜像。RUN在构建时执行命令比如装依赖、改权限。CMD定义容器启动后执行的主命令。这里给你几条经验之谈。第一RUN指令会生成永久层所以尽量把多个命令合并成一行用连接避免生成太多没用的中间层。第二COPY的时机要注意缓存Docker 构建时每一层如果有缓存就会复用所以把“变化快的文件”放到最后复制能让构建速度明显提升。第三生产用的镜像尽量选-slim、-alpine这类精简版本体积小、攻击面少。我之前在ubuntu全量镜像里装 Python 环境镜像 1.2GB换成python:3.11-slim后只有 400MB差距非常大。4.2 docker-compose.yml一键拉起整套项目如果说 Dockerfile 解决的是“镜像怎么做”那 docker-compose 解决的就是“整套项目怎么一键跑起来”。尤其是部署微服务、GitLab、青龙面板这类多容器场景Compose 几乎是标配。一个很常见的 MySQL Redis 应用服务的 compose 示例version: 3.8 services: mysql: image: mysql:8.0 container_name: mysql8 restart: always environment: MYSQL_ROOT_PASSWORD: root123 ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql redis: image: redis:7-alpine container_name: redis7 ports: - 6379:6379 command: redis-server --appendonly yes volumes: - redis-data:/data app: build: . ports: - 8080:8080 depends_on: - mysql - redis volumes: mysql-data: redis-data:depends_on只保证启动顺序不保证服务“可用”。比如 MySQL 容器启动了但不代表它能立刻接受连接。你真要等数据库就绪要么在应用代码里做重试要么用healthcheck加上condition: service_healthy。这个坑在小公司线上非常常见depends_on后面 app 一启动就连数据库连不上就崩误以为 compose 写错了。另外restart: always是生产部署必加的选项否则宿主机一重启容器不会自动拉起。我见过一台服务器重启后线上支付服务“凭空消失”连监控都没报警就是因为启动容器时没加--restart参数。5. 安装部署全记录从 Linux 到 Windows Desktop5.1 Linux 安装 Docker 的正确姿势Linux 装 Docker我推荐直接用官方脚本但前提是你理解它在做什么。在 Ubuntu 或 CentOS 上curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh这个脚本会帮你配置软件源、安装 Docker Engine、CLI 和 containerd。装完以后验证一下sudo docker run hello-world能打印出 “Hello from Docker!” 就说明引擎正常。这里有一个新手的常见误区为什么docker命令要加sudo因为 Docker 引擎默认以 root 权限运行而 CLI 要跟引擎通信需要相应的权限。你不想每次敲命令都带sudo可以把自己加入 docker 用户组sudo usermod -aG docker $USER newgrp docker之后重新登录docker命令就不需要sudo了。但注意能执行 docker 命令基本等同于能控制宿主机别在生产环境的机器上随便加人。5.2 Windows 安装 Docker DesktopVirtualization 问题排查Windows 上安装 Docker Desktop最常见的报错就是“virtualization support not detected in BIOS”。这个报错的意思是CPU 虚拟化没开或者 Hyper-V/WSL2 没启用。排查顺序是这样的重启进 BIOS/UEFI找 “Intel VT-x” 或 “AMD SVM”设为 Enabled。Windows 功能里开启 “Virtual Machine Platform” 和 “Windows Subsystem for Linux”。安装 WSL2 并更新内核命令是wsl --update。下载 Docker Desktop 安装包安装后重启如果还报错去“控制面板 - 程序 - 启用或关闭 Windows 功能”确认 Hyper-V 勾选Win11 家庭版可能没有 Hyper-V那就确保 VMP 和 WSL 两个已开。还有一个非常容易忽略的点如果你之前装过 VM 软件如 VMware、VirtualBox它可能锁定了虚拟化资源导致 Docker Desktop 检测不到 VT-x。我处理过一例卸载或者关闭 VM 软件后Docker Desktop 马上就正常启动了。Docker Desktop 安装完成后还要考虑镜像存储位置。默认镜像和容器数据在 C 盘用久了 C 盘会爆。设置里可以改 Disk image location 到 D 盘这就是热搜里“docker安装到d盘”的由来。改动方法是Docker Desktop - Settings - Resources - Advanced - Disk image location。注意这个操作会把现有镜像和容器搬走建议先导出你需要的镜像docker save再做迁移。5.3 配置镜像加速解决 pull 慢daemon.json是 Docker 引擎的核心配置文件一般位于/etc/docker/daemon.json。你要配加速器就在里面加这样一段{ registry-mirrors: [ https://docker.m.daocloud.io, https://docker.mirrors.ustc.edu.cn ] }改完执行sudo systemctl daemon-reload sudo systemctl restart docker。加速器地址选哪个效果因地区和运营商而异我建议你每个都实测一下选拉取速度最快的那个而不是照抄别人的配置。极端情况下如果内网无法访问外网镜像仓库你就得搭一个内网代理或者用docker save/docker load离线迁移镜像。5.4 升级 Docker 版本从旧版本到新版本CentOS 7 上的 Docker 版本太旧想升级到新版本一般要先把旧包禁用或卸载sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine然后重新配置 Docker 官方源并安装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-compose-plugin sudo systemctl start docker sudo systemctl enable docker升级前一定记得备份正在运行的容器配置和数据。升级 Docker 本质上是替换引擎不一定会保留你旧的容器状态配置。我建议升级前用docker ps -a记录下所有容器用docker commit把重要的容器固化为镜像。6. 高频场景实战MySQL、Redis、GitLab、青龙6.1 MySQL 8.0 部署环境变量、数据卷、字符集一起搞定热搜里有“docker安装mysql8.0并使用”这是 Docker 最常见的实战需求之一。部署 MySQL 的完整命令我上面已经给过一版这里再补充几个必须关注的细节MYSQL_ROOT_PASSWORD是设置 root 密码的环境变量别在命令行里直接写生产密码最好用--env-file指定一个权限受限的文件。MySQL 8.0 默认字符集是utf8mb4但你最好在容器启动命令里显式加--character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci避免有些连接工具查出奇怪的行为。数据持久化用卷日志持久化也一样重要。建议把/var/log/mysql也挂出来排查慢查询和错误日志会方便很多。如果安装 MySQL 失败先看日志docker logs mysql8。最常见的失败原因是端口冲突、数据目录权限不对、密码策略问题。数据目录权限问题尤其常见因为 MySQL 容器要求/var/lib/mysql目录属主是mysql用户UID 是 999。直接绑定宿主机的空目录进去时目录属主是 rootMySQL 会拒绝启动。解决方法是先chown -R 999:999 /宿主机/mysql-data或者用 Docker 卷而不是绑定目录。6.2 Redis 主从与持久化Redis 主从的 Docker 部署本质是启动多个 Redis 容器在从节点的配置里指定slaveof 主节点容器名 6379。用 Compose 更清楚services: redis-master: image: redis:7-alpine command: redis-server --appendonly yes redis-slave: image: redis:7-alpine command: redis-server --slaveof redis-master 6379 depends_on: - redis-master注意 Redis 新版已经用replicaof代替了slaveof两者的含义相同但如果你用的是 Redis 5 以下版本还是只能写slaveof。主从本身不解决高可用问题主节点挂了从节点不会自动顶上生产环境更推荐 Sentinal 或 Redis Cluster这些也能用 Docker 跑但配置复杂度就上来了。Redis 持久化选 AOF 还是 RDB取决于业务对数据丢失的容忍度。AOF 更安全但文件大RDB 性能好但会丢最近几分钟数据。我这里一般--appendonly yes开关 AOF配合appendfsync everysec能接受最多丢一秒数据。6.3 GitLab 社区版 Docker 部署GitLab 的 Docker 部署我建议直接看官方文档但这里把最容易踩的“最小配置”先给你。services: gitlab: image: gitlab/gitlab-ee:latest container_name: gitlab restart: always hostname: gitlab.example.com environment: GITLAB_OMNIBUS_CONFIG: | external_url http://gitlab.example.com ports: - 80:80 - 443:443 - 22:22 volumes: - gitlab-config:/etc/gitlab - gitlab-logs:/var/log/gitlab - gitlab-data:/var/opt/gitlabGitLab 容器内存占用很高我以前 4GB 内存的机器跑不动一启动就 OOM。最低建议 8GB尤其是开了 CI Runner 之后。另外external_url一定要在启动前想好改成 IP 或域名。因为 GitLab 会把external_url写进内部配置和仓库的 clone 地址之后改很麻烦要去改配置再gitlab-ctl reconfigure容易出各种诡异问题。还有一个很隐蔽的坑端口 22 是 SSH 默认端口如果宿主机自己也开了 SSH就会冲突。解决办法是映射到另一个端口比如2222:22用户在 clone 远程仓库时就要用ssh://githost:2222/group/project.git。6.4 青龙面板、Kodbox、Photopea 这类“热门镜像”场景热搜词里出现了“docker青龙 依赖管理”“docker部署kodbox”“photoea docker”这些相对年轻的项目。这些项目本质上就是把一个 Web 应用打包成镜像通过 Docker 部署简化安装。我拿青龙面板简单说一句它是一个定时任务管理面板依赖管理这一块它是在容器里内置了一些 Node/Python 依赖库你可以通过面板的“依赖管理”功能选择安装依赖而不是 SSH 进容器手动装。对于这类“别人封装好的镜像”我的看法是优先用官方镜像标签选固定版本不要latest。用 Compose 文件声明端口、卷、环境变量方便日后重建。注意镜像来源是否可信。第三方镜像经常有人往里面塞挖矿程序。拉取前先看 Docker Hub 页面的下载量、描述、标签变动记录能不去第三方源就别去。6.5 特殊场景人大会金仓数据库、Hadoop、vLLM 镜像热搜词里还有“人大金仓数据库docker”“hadoop的docker镜像”“docker vllm/vllm-openai 加载 qwen3-embedding”。这些属于“把复杂软件容器化”的典型场景。人大会金仓数据库一般有官方 Docker 镜像启动后默认端口、用户名口令在文档里都有按文档跑就行。这里我想提醒的是国产数据库的镜像经常很大拉取时注意磁盘空间。Hadoop 的镜像我一般不用 Docker 跑完整集群因为 Hadoop 要跑至少三个角色NameNode、DataNode、ResourceManager而且依赖 SSH 打通Docker 里跑起来状态管理很麻烦。我更推荐用docker-compose定义多服务或者干脆用一套脚本在裸机/虚拟机上跑集群。vLLM 这个就更有意思了。它是大模型推理加速框架vllm/vllm-openai镜像用于加载本地大模型并提供一个兼容 OpenAI API 的推理服务。部署时要注意 GPU 直通的问题——容器里要能用 GPU宿主机必须装好 NVIDIA 驱动和 NVIDIA Container Toolkit。安装 Toolkit 的命令Ubuntudistribution$(. /etc/os-release;echo $ID$VERSION_ID) curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed s#deb https://#deb [signed-by/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtimedocker sudo systemctl restart docker验证 GPU 是否真的被容器识别docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi如果这条命令能打印出显卡信息说明 GPU 直通正常。跑 vLLM 这类推理镜像我最后再说一句模型权重文件较大几个 GB 到几十 GB建议用卷挂载而不是打进镜像否则镜像会变得极其臃肿。7. 常见问题与排查技巧实录7.1 权限相关“Got permission denied”这个报错基本是因为当前用户不在docker用户组。按上面说的sudo usermod -aG docker $USER加组然后重新登录。还有另一种情况是dockerd没启动。先查服务状态systemctl status docker journalctl -xeu docker.service如果是 CentOS 7 上出现了iptables相关的权限报错通常是新内核和 Docker 的 iptables 兼容问题可能需要重启服务或者升级 Docker 版本。7.2 网络不通跨主机、容器间、端口映射我把网络问题按“不通的对象”分成三类排查起来最顺容器访问外网不通优先看 DNS/etc/resolv.conf和宿主机防火墙。很多内网环境默认封锁 DNS 出站容器一般靠宿主机转发检查net.ipv4.ip_forward是否开启。容器间互访不通检查它们是不是在同一个 bridge 网络里不同自定义网络的容器默认不互通。用docker network connect 网络名 容器名把容器加进去。宿主机外部访问容器端口不通先curl 127.0.0.1:端口看本机通不通不通就是端口映射问题通了就是防火墙或安全组问题。7.3 镜像下载慢或超时这个前面讲过了配置镜像加速器和registry-mirrors。如果你是拉取 k8s.gcr.io、quay.io 这类源加速器不一定有用那就需要docker pull手动从代理地址拉取再docker tag改名。这部分涉及网络工具的使用不在展开范围内但我提一句优先从可用源拉比反复试超时强太多。7.4 容器启动后立即退出我见过最多的一种情况是docker run一条命令启动容器几秒钟后docker ps -a看到状态是Exited (0)。这不是崩了是容器的主进程执行完自己退出了。比如你跑docker run ubuntu echo hello容器做完echo后没有更多事可干就正常退出。要让容器常驻主命令必须是一个长期运行的进程比如nginx -g daemon off;、mysqld、redis-server。如果你启动某个服务容器后它很快退出先看代码里有没有死循环、有没有监听端口以及CMD是否写错。这是 Docker 里“表象是崩溃实质是设计”的典型例子。7.5 磁盘占满怎么办容器日志无限增长是磁盘占满的第一大元凶。Docker 默认不限制日志文件大小一个容器跑几个月日志能涨到几十 GB。想根治在daemon.json里配置{ log-driver: json-file, log-opts: { max-size: 20m, max-file: 5 } }然后重启 Docker。对新容器生效。已经产生的日志可以清空truncate -s 0 /var/lib/docker/containers/*/*-json.log小心别把正在写的日志文件直接删掉用truncate而不是rm更安全。7.6 Docker Desktop 启动失败汇总启动失败的原因按概率排序没有开启虚拟化BIOS。WSL2 没有安装或没有更新。Docker Desktop 和某个 VM 软件冲突。Windows 版本不满足最低要求Win10 21H2 以上或 Win11。镜像存储路径所在磁盘空间不足。排查时建议直接看 Docker Desktop 的日志一般它在%AppData%\Docker里的log目录或者点系统托盘图标选择 Troubleshoot。日志比界面上那两行英文报错有用得多。8. 生产经验总结避坑清单和最终建议最后这部分我不做“展望”就分享一些直接能帮到你的实操心得。第一永远不要在生产用latest标签。我前文多次提到但值得再重点强调一遍。镜像标签最好是固定版本比如mysql:8.0.36要升级时手动修改 tag 并测试后再上。用latest等于放弃可追溯性谁用谁知道苦。第二所有持久化数据必须挂卷。不管是 MySQL 的 datadir、Redis 的 appendonly 文件还是应用的 upload 目录只要不是“没了也无所谓”的数据全部挂载到卷或宿主机目录。第三给每个容器写清restart: always策略。容器化部署天然是“服务器重启后要自动恢复”不加重启策略的话一台宿主机重启就能让你线上服务全体静默。第四定期docker system df查看磁盘占用。镜像、容器、卷、构建缓存每项都可能悄悄占空间。我一般每月跑一次docker system df docker system prune -f这只会清理悬空镜像和没在用的缓存不会动正在运行的容器。想彻底清理已经停掉的容器用docker container prune注意这两条命令也会把“已停止但可能还要用”的容器或镜像清掉执行前先确认。第五学会看日志胜过猜配置。容器起不来、网络不通、数据不对第一件事永远是docker logs 容器名。日志里十有八九已经说了“为什么”你只需要翻译它。第六不要什么事都往一个容器里塞。很多人喜欢“一个 ubuntu 容器装全所有服务”这是把 Docker 当虚拟机用属于典型反模式。Docker 的哲学是“一个进程一个容器”每个容器职责单一扩容、替换、监控都方便。你要是觉得容器多了管理麻烦就用 Compose 定义那才是正路。我这几年做项目部署从最早“docker 命令照着抄”到后来能快速定位网络、权限、数据持久化问题中间踩过的坑基本都是上面列的这些。Docker 的“内容”看起来庞大底层原理其实很清晰镜像定义模板、容器承载运行时、网络打通连接、数据卷保证持久化再加上镜像仓库和编排工具整套体系就完整了。最后再分享一个我自己的习惯每部署一个项目我会顺手写一份 README里面记录镜像版本、端口映射、数据卷目录、环境变量、常用的排查命令。这份文档比任何教程都好用因为它是你这套环境的“唯一事实来源”。下次你再遇到“Docker 包括哪些内容”类似的问题答案就不只是技术名词堆砌而是你真正用过、踩过、调整过的那一套完整工作流。