Docker Compose部署实战:从环境规划到服务编排与故障排查
2026/9/19 6:53:09 网站建设 项目流程

网上讲 Docker 部署的教程一抓一大把,但多数都只讲到“能装上、能启动”就没了。真正到了自己要部署项目的时候,才发现环境判断、目录规划、Compose 编排、报错排查这些环节全是坑。这套 Docker + Docker Compose 部署教程是我前后在几台机器上反复验证过的,从 Linux 服务器到 Windows 开发机都跑通了,今天完整整理出来,适合刚接触容器化的新手,也适合已经会 docker run 但还没系统用过 Compose 的朋友。

1. 部署前的判断题:这台机器适不适合跑 Docker

我不太建议拿到机器就急着敲安装命令。先花十分钟搞清楚三件事,能帮你后面少折腾两个小时。

1.1 先确认操作系统与内核要求

Docker Engine 对 Linux 内核版本有硬性要求,64 位系统、内核版本不低于 3.10,但这是很早以前的门槛了,现在主流发行版基本都远超这个标准。真正要注意的是系统是 systemd 还是 SysV init,虽然 Docker 官方安装脚本能自动处理,但如果你在旧系统上手动安装,init 系统的差异会让你多踩很多坑。

我在部署前通常用这几条命令快速摸底:

cat /etc/os-release # 查看发行版 uname -r # 查看内核版本 systemctl --version # 确认 systemd 可用

Ubuntu 22.04、Debian 12、Rocky Linux 9 这几代系统我都实测过,按官方源安装基本不会出问题。如果拿到的是 CentOS 7 这种比较老的系统,建议先确认内核在 3.10 以上再继续,同时注意旧版本 Docker 和容器运行时之间的兼容性。

1.2 端口与目录规划:最容易返工的一步

很多新手部署失败,不是 Docker 没装好,而是没想清楚服务和宿主机的端口映射、数据目录映射关系。我建议在装 Docker 之前就把两个问题写下来:这个项目要暴露哪些端口?哪些数据必须持久化?

规划项建议做法原因
端口避开 80/443 之外的常见占用,统一规划端口段MySQL、Redis、Nginx 等默认端口极易冲突
数据目录统一放到 /opt/apps 或 /data 下,按项目名分目录备份、迁移、排查都方便
日志容器日志重定向或配置 log rotation不限制的话日志能占满磁盘

举个例子,我习惯把所有 Compose 项目放在/opt/apps/<项目名>下面,每个项目内部再分dataconflogs三个子目录。这样整个机器的容器数据一目了然,出问题也能快速定位。

1.3 版本锁定思路:不要盲目追最新

Docker 的版本节奏其实不算激进,但 Docker Compose 插件的版本和 Docker Engine 之间偶尔会有兼容性问题。我的建议是:服务器上用稳定版,不要碰 nightly 或 rc 版本。生产环境锁定大版本,比如 Docker 24.x 或 25.x 系列,等当前版本运行稳定后再考虑升级。

通过 apt 或 dnf 安装时,可以显式指定版本号,避免自动拉取到预期之外的版本。这样做的深层原因是,容器部署本来就强调“环境一致”,如果 Docker 本身经常变,那“我的环境和生产一致”这个目标就很难保证。

2. Docker 与 Compose 安装:两条路线实测

Linux 服务器和 Windows 开发机走的是完全不同的安装路线,我都实测过,分开说。

2.1 Linux 服务器:用官方源装 Engine 和 Compose 插件

这里以 Ubuntu/Debian 和 Rocky/CentOS 为例。Ubuntu 系先装依赖并添加 Docker 官方 GPG 密钥和 apt 源:

sudo apt update sudo apt install -y ca-certificates curl gnupg 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 \ $(. /etc/os-release && echo $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

Rocky / CentOS 用 yum 源:

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

注意,这里安装的是docker-compose-plugin,安装后命令是docker compose(带空格),不是老的docker-compose(带连字符)。很多人在这里迷糊,其实新版 Docker 已经内置了 Compose v2,直接用docker compose就好。

装完先启动并验证:

sudo systemctl enable docker --now docker --version docker compose version

2.2 配置镜像加速器让拉取速度恢复正常

这一步虽然不是必需的,但在国内服务器上不配的话,拉官方镜像经常慢到怀疑人生。Docker 的镜像加速本质上是通过配置registry-mirrors让守护进程从公共镜像站拉取。修改/etc/docker/daemon.json

{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.1panel.live", "https://hub.rat.dev" ] }

保存后重启 Docker:

sudo systemctl restart docker

这类公共加速地址存在不定期变动的可能,失效了换一个即可。如果你有阿里云或腾讯云账号,到容器镜像服务控制台拿到专属加速地址,稳定性更好。配置完可以用docker info查看 Registry Mirrors 是否生效。

2.3 Windows 环境:Docker Desktop 的虚拟化前提

Windows 上通常通过 Docker Desktop 使用 Docker,但它依赖 WSL2 或 Hyper-V。安装前先确认两件事:BIOS 里虚拟化有没有开启,Windows 功能里“虚拟机平台”和“适用于 Linux 的 Windows 子系统”有没有启用。

如果安装后启动报 “Docker Desktop failed to start because virtualisation support wasn't detected”,十有八九是虚拟化没开全。此时需要:

  1. 进入 BIOS,开启 Intel VT-x 或 AMD-V。
  2. 以管理员身份运行 PowerShell,启用 WSL2 相关功能后重启:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
  1. 重启后运行wsl --set-default-version 2

Docker Desktop 启动成功后,Settings → Docker Engine 里同样可以配置镜像加速地址,JSON 格式和 Linux 上一样。Windows 版最大的优势是可以直接映射本机端口访问容器服务,对本地开发很友好。

3. 一个能直接照抄的 docker-compose.yml:前后端 + 数据库 + 缓存

这一节我带你完整跑通一个典型服务栈,包含一个简单的后端 API、Nginx 反向代理、MySQL 8.0 和 Redis 7。这套结构基本涵盖了大多数中小型项目的部署形态。

3.1 为什么用 Compose 而不是一长串 docker run

直接用docker run部署多个容器,最直观的问题是命令太长、依赖关系靠脑子记。比如你要先启动 MySQL,等它初始化完,再启动 API,还要把网络打通、数据卷挂载对上,这些全靠手工操作,非常容易出错。

Compose 的价值在于把“我要跑哪几个服务、它们之间怎么连接、数据放哪里、挂了怎么重启”这些声明式地写在一个 YAML 文件里。一条docker compose up -d就能拉起整个服务栈,一条docker compose down就能清理干净。它把部署变成了可版本化的配置,团队协作时 git 里放一个 compose 文件,任何人拉下来都能复现环境。

3.2 先写一个最简单的后端镜像

为了让教程完整,我先准备一个极简 Node.js API 的Dockerfile

FROM node:20-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm install --registry=https://registry.npmmirror.com COPY . . FROM node:20-alpine WORKDIR /app ENV NODE_ENV=production COPY --from=build /app ./ EXPOSE 3000 CMD ["node", "index.js"]

这个 Dockerfile 用了多阶段构建,第一阶段装依赖,第二阶段只拷贝产物,镜像体积会小很多。实际项目中你可能还需要非 root 用户运行和 HEALTHCHECK,这里为了篇幅先简化。package.json里指定express依赖,index.js写一个返回当前时间的接口,这部分我就不贴全了,大家都会写。

3.3 compose 文件逐段拆解

下面是完整的docker-compose.yml,以myapp项目为例:

services: mysql: image: mysql:8.0 container_name: myapp-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: root_pass_123 MYSQL_DATABASE: myapp MYSQL_USER: myapp_user MYSQL_PASSWORD: user_pass_123 volumes: - ./data/mysql:/var/lib/mysql ports: - "3306:3306" healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot_pass_123"] interval: 10s timeout: 3s retries: 5 redis: image: redis:7-alpine container_name: myapp-redis restart: unless-stopped volumes: - ./data/redis:/data ports: - "6379:6379" command: redis-server --appendonly yes api: build: ./api container_name: myapp-api restart: unless-stopped environment: DB_HOST: mysql DB_PORT: 3306 DB_NAME: myapp DB_USER: myapp_user DB_PASSWORD: user_pass_123 REDIS_HOST: redis REDIS_PORT: 6379 ports: - "3000:3000" depends_on: mysql: condition: service_healthy redis: condition: service_started nginx: image: nginx:1.27-alpine container_name: myapp-nginx restart: unless-stopped ports: - "8080:80" volumes: - ./conf/nginx.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - api

几个关键点值得展开解释:

services 下的每个服务名,本身就是容器网络内的 DNS 名称。API 容器里连接数据库时,DB_HOSTmysql就行,不需要填 localhost 或 IP。这是 Compose 默认创建的网络自动提供的,各服务通过服务名互相访问,和宿主机网络隔离但互通映射端口。

depends_on配合condition: service_healthy是我强烈推荐的做法。单纯用depends_on只能保证 MySQL 容器先启动,但 MySQL 容器启动过程有初始化阶段,如果 API 在数据库就绪前就开始连接,会报连接失败然后退出。加上 healthcheck 之后,Compose 会等 MySQL 健康检查通过才启动 API,从机制上解决启动顺序问题。

./data/mysql:/var/lib/mysql这种相对路径挂载很直观。宿主机上的data/mysql目录会存数据库文件,删掉容器数据还在。这是容器部署和传统部署最大的思维差异:容器是“有状态进程的宿主”,数据必须外置。

3.4 启动、验证、滚动更新的完整命令流

/opt/apps/myapp目录下执行:

docker compose up -d docker compose ps

第一次启动会自动拉取镜像、构建 api 镜像,然后把四个服务按依赖顺序带起来。docker compose ps能看到每个服务是否 healthy:

NAME IMAGE STATUS myapp-mysql mysql:8.0 Up (healthy) myapp-redis redis:7-alpine Up myapp-api myapp-api:latest Up myapp-nginx nginx:1.27-alpine Up

验证接口:

curl http://localhost:8080/api/ping

日常更新代码后,只需要重新构建并滚动替换 API 容器:

docker compose build api docker compose up -d api

Compose 会对配置和镜像做 diff,只重建变化的部分,不会把数据库和 Redis 容器一起重启,这对线上服务非常友好。

4. 亲测中踩过的坑:从报错到恢复的完整排查链路

这一节应该是很多人最需要的。我在不同机器上反复部署,踩过的坑五花八门,挑几个最有代表性的完整讲一遍排查链路。

4.1 Windows 上 Docker Desktop 起不来:虚拟化报错

这是 Windows 部署最典型的报错,现象是启动 Docker Desktop 后弹窗提示 “Virtualisation support wasn't detected” 然后退出。我见过三种原因:

现象根因处理方法
Docker Desktop 启动弹虚拟化错误BIOS 里 VT-x/AMD-V 关闭进 BIOS 开启虚拟化
Windows 功能缺“虚拟机平台”WSL2 依赖项未启用dism 命令启用并重启
装完 WSL 但仍报错WSL 版本是 1wsl --set-default-version 2

一个容易忽略的细节是,Windows 的“Hyper-V”和“虚拟机平台”是两个独立功能,Docker Desktop 新版对“虚拟机平台”更依赖。如果开了 Hyper-V 但没开虚拟机平台,同样可能报错。检查时两条命令都跑一遍,别漏。

4.2 连不上 Docker API:npipe 报错

另一个 Windows 高频报错是:

Failed to connect to the Docker API at npipe:////./pipe/docker-desktop-linux

这个报错字面意思是连不上 Docker Engine 的命名管道。通常不是 Docker Desktop 没装好,而是 Engine 没真正起来。我建议按顺序排查:

  1. 看系统托盘里 Docker Desktop 图标,如果是红色或黄色,等它转完。
  2. wsl --list --verbose看 docker-desktop 发行版是不是 Running,如果 Stopped 就wsl --shutdown再重开 Docker Desktop。
  3. 还没有的话,以管理员身份运行net stop com.docker.service再启动 Docker Desktop。

最坏情况下,把 Docker Desktop 退出,删掉%LOCALAPPDATA%\Docker下的缓存目录再启动。这个目录是引擎的临时状态,删了不影响已有的镜像和容器(镜像在docker-desktop-data发行版里)。

4.3 容器启动后马上退出:别猜,先看日志

我见过最多的情况是docker compose up -dps一看容器 Exited。这时候最忌讳盲目重启,正确姿势是看日志:

docker compose logs api

日志会直接告诉你真实原因。比如 API 连不上 MySQL,日志里会有一堆ECONNREFUSED之类的网络错误;也可能是环境变量名拼错,导致连接了不存在的数据库名。

如果日志显示端口被占用,用下面的命令定位:

sudo lsof -i :3306

常见坑是宿主机本来就有 MySQL,把 3306 占了。解决方案很简单,宿主机 MySQL 换成 3307,或者 compose 里把映射端口改成3307:3306。我不建议把宿主机自带的 MySQL 直接停掉,除非你确定不再需要它。

4.4 数据卷权限与容器内 UID 的错位

这个坑非常隐蔽。MySQL 容器里的mysql用户 UID 是999,如果你在宿主机上创建了./data/mysql目录但它的 owner 是 root,MySQL 容器首次初始化时会因为无法写目录而失败。更恶心的是,这种错误有时不在初次报,而是容器重启后才暴露。

排查命令是看目录权限:

ls -ln data/mysql

如果属主信息不对,直接改成容器内用户的 UID:

sudo chown -R 999:999 data/mysql

相同的问题在 Redis、GitLab 这些镜像里也可能出现,GitLab 镜像内部用户 UID 是1000。遇到容器启动后马上退出,先看日志,再看挂载目录权限,两个方向排查基本能解决 80% 的问题。

5. 部署技能如何延伸到更多场景:从 Harbor 到 Dify 的思路

学 Comple 不只是为了部署自己的小项目。现在大量开源项目都提供官方 compose 文件,学会读 compose 文件,你会发现部署一个复杂系统从“天方夜谭”变成“照葫芦画瓢”。

5.1 通用三步走:找文件、改配置、启动

不管部署的是 Harbor、Dify、GitLab、Jellyfin 还是青龙面板,流程高度统一。以 Dify 为例,它是一个比较复杂的 LLM 应用开发平台,包含 API server、Worker、Web、PostgreSQL、Redis、Sandbox、Nginx 等多个服务,官方已经提供了完整的docker-compose.yaml

第一步,把项目代码拉到服务器:

git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env

第二步,修改.env里的关键配置。Dify 这类项目把几乎所有可调参数都放进.env文件,compose 文件里通过${VARIABLE}方式引用。你需要关注的是端口、密钥、存储路径,其他保持默认即可。

第三步,启动:

docker compose up -d

Dify 首次启动会非常久,因为要构建多个镜像、下载模型依赖。这时候别慌,用docker compose logs -f nginx观察启动进度。

5.2 Harbor 的特殊之处:证书和 HTTPS 不能跳过

Harbor 是另一个典型代表,它作为企业级镜像仓库,启动前必须配置hostname和 HTTPS 证书。如果你贪图省事直接用 HTTP,Harbor 会在客户端配置上给你留个大坑,因为 Docker 客户端默认不允许推送到非 HTTPS 的 registry。

至少你需要在harbor.yml里正确填写 hostname,并生成自签名证书或配置受信证书。之后运行./install.sh安装。Harbor 的核心价值是镜像管理,它帮你把仓库、用户、权限、复制规则都集成在一个 Web 界面里,内部用起来非常顺手。

5.3 常用运维命令速查与 docker 服务自启

部署完成只是开始,后面维护才是长期工作。我把平时用得最多的命令整理一张速查表:

场景命令
查看所有容器状态docker compose ps
看某个服务实时日志docker compose logs -f api
进入容器内部调试docker compose exec api sh
重启某个服务docker compose restart nginx
停掉并删除整个服务栈docker compose down
停掉并删除数据卷(谨慎)docker compose down -v
清理悬空镜像和构建缓存docker system prune -a

开机自启这块有两个层次。第一层是 Docker 服务本身开机启动,安装时systemctl enable docker已经处理了。第二层是容器随 Docker 启动而恢复,靠的是 compose 文件里的restart: unless-stopped,我强烈建议每个服务都加上,这样服务器重启后容器能自动恢复,不用手动一个个拉起来。

最后再分享一个我个人的习惯:每次改动 compose 文件或.env之前,先备份一份,并把当前的数据卷目录打个快照。比如 MySQL 数据目录,直接cp -r data/mysql data/mysql_bak_$(date +%F)。容器部署最大的便利就是环境可重建,但数据是不可再生资源,备份这一步花不了几分钟,能在出问题时把你从绝望边缘拉回来。部署这事,跑起来不算本事,能稳定运行、随时备份、出了问题快速恢复,才是真正有用的能力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询