容器化技术彻底改变了应用交付的方式,但当业务规模从单机扩展到集群时,容器编排(Container Orchestration) 便成为决定运维效率与系统稳定性的关键分水岭。本文将深入剖析 Docker 生态下的编排框架选型逻辑,并对核心指令进行系统性详解,帮助你从"会跑容器"进阶到"精通编排"。
一、Docker 核心指令详解(按使用频率排序)
Docker CLI 是容器操作的入口。以下指令按生产环境使用频率从高到低排列,每个指令附带详细解释和生产级用法。
1. 高频必会(每日使用)
1.1 docker run --- 创建并启动容器
这是 Docker 最常用的指令,用于从镜像创建并启动新容器。
bash
# 基础用法:后台运行 Nginx
docker run -d --name web -p 80:80 nginx:alpine
# 生产级用法:完整参数
docker run -d \
--name api-gateway \
--hostname api-01 \
--restart unless-stopped \
-p 8080:8080 \
-p 8443:8443 \
-v /host/data:/app/data:rw \
-v /host/config:/app/config:ro \
-e DB_HOST=db.internal \
-e LOG_LEVEL=info \
--network app-network \
--memory=512m \
--cpus=1.0 \
--health-cmd="curl -f http://localhost:8080/health || exit 1" \
--health-interval=30s \
--health-retries=3 \
--health-timeout=10s \
myapp/api-gateway:v2.1.0
关键参数详解:
| 参数 | 作用 | 生产建议 |
|---|---|---|
-d / --detach |
后台运行 | 生产环境必加,避免占用终端 |
--name |
容器命名 | 使用语义化命名,如 api-gateway-prod-01 |
-p |
端口映射 | 宿主机端口:容器端口,建议宿主机端口 > 1024 |
-v |
数据卷挂载 | 配置文件用 :ro 只读挂载,防止容器内篡改 |
-e |
环境变量 | 敏感信息改用 --env-file 或 Docker Secrets |
--restart |
重启策略 | unless-stopped 最常用,手动停止后不自动重启 |
--memory / --cpus |
资源限制 | 必须设置,防止单个容器耗尽宿主机资源 |
--health-cmd |
健康检查 | 生产必备,配合负载均衡实现自动故障转移 |
生产案例:部署高可用 Web 服务
bash
# 1. 创建自定义网络(容器间通信更安全)
docker network create --driver bridge --subnet 172.20.0.0/16 app-network
# 2. 启动数据库容器(带持久化卷和健康检查)
docker run -d \
--name postgres-prod \
--network app-network \
-v postgres-data:/var/lib/postgresql/data \
-e POSTGRES_USER=admin \
-e POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
--secret db_password \
--memory=1g \
--restart unless-stopped \
postgres:15-alpine
# 3. 启动应用容器(依赖数据库)
docker run -d \
--name webapp-prod \
--network app-network \
-p 8080:8080 \
-e DB_HOST=postgres-prod \
-e DB_PORT=5432 \
--memory=512m \
--cpus=1.0 \
--restart unless-stopped \
--health-cmd="curl -sf http://localhost:8080/health || exit 1" \
--health-interval=10s \
--health-retries=5 \
mycompany/webapp:v1.2.3
# 4. 验证运行状态
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
1.2 docker ps --- 查看容器状态
bash
# 基础用法
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(含已停止)
# 生产级用法:自定义输出格式
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}\t{{.RunningFor}}"
# 查找特定状态的容器
docker ps -a -f status=exited # 查找已退出容器
docker ps -a -f status=dead # 查找死亡容器(需清理)
# 按标签过滤
docker ps -a -f label=app=tier1
输出字段说明:
| 字段 | 含义 | 排查场景 |
|---|---|---|
CONTAINER ID |
容器唯一标识 | docker exec -it <ID> bash 进入容器 |
IMAGE |
使用的镜像 | 确认版本是否正确 |
STATUS |
运行状态 | Up 2 hours 正常,Exited (1) 异常退出 |
PORTS |
端口映射 | 确认服务暴露是否正确 |
NAMES |
容器名称 | 用于日志查询和容器操作 |
1.3 docker exec --- 在运行容器中执行命令
bash
# 基础用法:进入容器 Shell
docker exec -it webapp bash
# 生产级用法:不进入容器执行一次性命令
docker exec webapp python manage.py migrate
docker exec -u postgres postgres-prod pg_dump -U admin mydb > backup.sql
# 以 root 权限进入(排查权限问题)
docker exec -u root -it webapp sh
# 在多个容器并行执行(配合 xargs)
docker ps -q -f name=webapp | xargs -I {} docker exec {} curl -s localhost:8080/health
参数详解:
| 参数 | 作用 | 使用场景 |
|---|---|---|
-i / --interactive |
保持 STDIN 打开 | 需要交互输入时使用 |
-t / --tty |
分配伪终端 | 获得彩色输出和命令行体验 |
-u / --user |
指定执行用户 | 数据库操作指定 postgres 用户 |
-e |
设置环境变量 | 临时覆盖容器内环境变量 |
1.4 docker logs --- 查看容器日志
bash
# 基础用法
docker logs webapp
# 生产级用法:实时追踪 + 时间戳 + 行数限制
docker logs -f --tail=100 --timestamps webapp 2>&1 | grep ERROR
# 查看特定时间段的日志
docker logs --since=2026-05-12T10:00:00 --until=2026-05-12T12:00:00 webapp
# 导出日志到文件(配合日志分析工具)
docker logs --since=24h webapp > /var/log/webapp-$(date +%Y%m%d).log
参数详解:
| 参数 | 作用 | 生产建议 |
|---|---|---|
-f / --follow |
实时追踪 | 排查线上问题时必加,类似 tail -f |
--tail |
查看最后 N 行 | 避免加载全部日志导致卡顿 |
--timestamps |
显示时间戳 | 便于定位问题发生时间 |
--since / --until |
时间范围过滤 | 排查特定时段的故障 |
-t |
显示时间戳(简写) | 与 --timestamps 等效 |
生产案例:线上故障排查
bash
# 场景:用户反馈 API 响应慢,排查步骤
# 1. 查看应用日志中的错误
docker logs -f --tail=500 api-gateway | grep -E "(ERROR|WARN|timeout)"
# 2. 同时查看数据库连接情况
docker exec postgres-prod psql -U admin -c "SELECT count(*) FROM pg_stat_activity;"
# 3. 查看容器资源是否耗尽
docker stats api-gateway --no-stream
# 4. 如果容器已崩溃,查看退出前的最后日志
docker logs --tail=100 $(docker ps -aq -f name=api-gateway -f status=exited)
2. 进阶常用(每周使用)
2.1 docker stop / start / rm --- 容器生命周期管理
bash
# 优雅停止(发送 SIGTERM,等待 10 秒后强制 SIGKILL)
docker stop -t 30 webapp
# 强制停止(直接 SIGKILL,数据可能丢失)
docker kill webapp
# 启动已停止的容器
docker start webapp
# 删除容器(必须先停止)
docker rm webapp
# 强制删除运行中的容器
docker rm -f webapp
# 批量清理已停止容器
docker container prune -f
docker rm $(docker ps -aq -f status=exited)
生产建议: 停止容器时使用 -t 给予足够的优雅停机时间,让应用完成正在处理的请求。
2.2 docker images --- 镜像管理
bash
# 查看本地镜像
docker images
# 过滤 dangling(悬空)镜像
docker images -f dangling=true
# 查看特定仓库的镜像
docker images myapp/*
# 按大小排序
docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" | sort -k2 -h
2.3 docker pull / push --- 镜像仓库操作
bash
# 拉取特定标签(生产环境必须指定版本,禁止 latest)
docker pull nginx:1.25.3-alpine
# 推送到私有仓库
docker tag myapp:v1.2.3 registry.mycompany.com/myapp:v1.2.3
docker push registry.mycompany.com/myapp:v1.2.3
# 验证镜像摘要(确保未被篡改)
docker pull nginx@sha256:abc123...
3. 运维必备(故障排查)
3.1 docker inspect --- 查看详细元数据
bash
# 查看容器完整信息(JSON 格式)
docker inspect webapp
# 提取特定字段(Go 模板语法)
docker inspect -f '{{.State.Status}}' webapp # 运行状态
docker inspect -f '{{.NetworkSettings.IPAddress}}' webapp # IP 地址
docker inspect -f '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println}}{{end}}' webapp # 挂载点
# 查看镜像构建历史
docker inspect -f '{{.Config.Env}}' myapp:v1.2.3
3.2 docker stats --- 实时监控资源
bash
# 查看所有容器资源
docker stats
# 只看特定容器,不持续刷新
docker stats webapp postgres-prod --no-stream
# 格式化输出(便于脚本处理)
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
3.3 docker top --- 查看容器内进程
bash
# 查看容器内运行的进程(类似宿主机 ps)
docker top webapp
# 查看特定用户的进程
docker top webapp -u appuser
4. 镜像管理(构建发布)
4.1 docker build --- 构建镜像
bash
# 基础构建
docker build -t myapp:v1.0.0 .
# 生产级构建:多阶段 + BuildKit + 缓存优化
DOCKER_BUILDKIT=1 docker build \
--platform linux/amd64,linux/arm64 \
--build-arg BUILD_ENV=production \
--cache-from registry.mycompany.com/myapp:cache \
--tag myapp:v1.2.3 \
--tag myapp:latest \
--push \
-f Dockerfile.prod .
# 使用 Buildx 构建多平台镜像
docker buildx create --use --name multiplatform
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:v1.2.3 --push .
4.2 docker tag --- 镜像标记
bash
# 为现有镜像添加新标签
docker tag myapp:v1.2.3 registry.mycompany.com/myapp:v1.2.3
docker tag myapp:v1.2.3 registry.mycompany.com/myapp:stable
4.3 docker rmi --- 删除镜像
bash
# 删除特定镜像
docker rmi myapp:v1.0.0
# 清理悬空镜像(无标签、无容器引用)
docker image prune -f
# 清理未使用的所有镜像
docker image prune -a -f
5. 网络与存储(基础设施)
5.1 docker network --- 网络管理
bash
# 创建自定义桥接网络
docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 app-network
# 查看网络详情
docker network inspect app-network
# 连接容器到网络
docker network connect app-network webapp
# 断开容器网络
docker network disconnect app-network webapp
5.2 docker volume --- 数据卷管理
bash
# 创建命名卷
docker volume create --driver local --opt type=none --opt o=bind --opt device=/data/postgres postgres-data
# 查看卷详情
docker volume inspect postgres-data
# 清理未使用的卷(⚠️ 数据会丢失!)
docker volume prune -f
6. 安全与清理(维护必备)
6.1 docker system prune --- 系统清理
bash
# 清理停止的容器、悬空镜像、未使用的网络和构建缓存
docker system prune -f
# 深度清理:包含所有未使用的镜像和卷(⚠️ 慎用!)
docker system prune -a --volumes -f
6.2 docker scan --- 镜像安全扫描
bash
# 扫描镜像漏洞
docker scan myapp:latest
# 扫描并输出 JSON 报告
docker scan --json myapp:latest > scan-report.json
7. Swarm 集群(生产编排)
7.1 docker swarm init --- 初始化集群
bash
# 初始化 Manager 节点
docker swarm init --advertise-addr 192.168.1.100 --listen-addr 0.0.0.0:2377
# 获取 Worker 加入令牌
docker swarm join-token worker
# 获取 Manager 加入令牌(高可用场景)
docker swarm join-token manager
7.2 docker service --- 服务管理
bash
# 查看服务列表
docker service ls
# 查看服务详情
docker service ps myapp_web
# 扩缩容
docker service scale myapp_web=5
# 滚动更新镜像
docker service update --image myapp:v2.0.0 myapp_web
# 添加环境变量
docker service update --env-add DEBUG=false myapp_web
# 回滚到上一个版本
docker service update --rollback myapp_web
7.3 docker stack deploy --- 部署服务栈
bash
# 使用 Compose 文件部署到 Swarm
docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml myapp
# 查看栈状态
docker stack ls
docker stack ps myapp
docker stack services myapp
# 删除栈
docker stack rm myapp
8. Compose 编排(开发必备)
8.1 docker compose up --- 启动服务
bash
# 开发环境:前台运行,查看日志
docker compose up
# 生产环境:后台运行
docker compose up -d
# 强制重新构建镜像
docker compose up -d --build
# 只启动特定服务
docker compose up -d web db
8.2 docker compose down --- 停止并清理
bash
# 停止并删除容器、网络
docker compose down
# 同时删除数据卷
docker compose down -v
# 清理孤儿容器
docker compose down --remove-orphans
8.3 docker compose logs --- 查看服务日志
bash
# 查看所有服务日志
docker compose logs -f
# 查看特定服务
docker compose logs -f --tail=100 web
8.4 docker compose exec --- 进入服务容器
bash
# 进入 Web 服务容器
docker compose exec web bash
# 运行数据库迁移
docker compose exec web python manage.py migrate
# 以 root 用户进入
docker compose exec -u root db psql -U postgres
9. 镜像导入导出(离线环境 / 跨主机迁移)
在生产环境中,经常会遇到内网隔离环境 (如金融、政府、军工)无法直接访问 Docker Hub 的情况,或者需要在跨机房、跨云迁移镜像。Docker 提供了两组导入导出指令,但它们的适用场景和效果截然不同。
9.1 docker save --- 导出镜像(保留完整历史和元数据)
docker save 将一个或多个镜像 导出为 tar 归档文件,保留镜像的所有层历史、标签、构建元数据。这是最推荐的镜像迁移方式。
bash
# 基础用法:导出单个镜像
docker save -o myapp-v1.2.3.tar myapp:v1.2.3
# 导出多个镜像到一个文件(推荐,减少传输次数)
docker save -o production-images.tar myapp:v1.2.3 nginx:1.25-alpine postgres:15-alpine redis:7-alpine
# 使用 gzip 压缩(文件体积减少 60-80%)
docker save myapp:v1.2.3 | gzip > myapp-v1.2.3.tar.gz
# 查看 tar 包内容(不解压)
tar -tf myapp-v1.2.3.tar | head -20
关键特性:
| 特性 | 说明 |
|---|---|
| 保留层历史 | ✅ 完整保留,可以追溯每一层的构建指令 |
| 保留标签 | ✅ 镜像的 REPOSITORY:TAG 信息不会丢失 |
| 支持多镜像 | ✅ 一次导出多个镜像到一个 tar 包 |
| 文件体积 | 较大(包含所有历史层),建议配合 gzip 压缩 |
| 适用场景 | 离线部署、镜像备份、跨环境迁移 |
9.2 docker load --- 导入镜像(恢复 save 的文件)
bash
# 基础导入
docker load -i myapp-v1.2.3.tar
# 导入 gzip 压缩的文件
gunzip -c myapp-v1.2.3.tar.gz | docker load
# 导入后验证
docker images | grep myapp
# 导入后重新打标签(如果需要)
docker tag myapp:v1.2.3 registry.local/myapp:v1.2.3
9.3 docker export --- 导出容器文件系统(扁平化)
docker export 将运行中或已停止的容器 导出为 tar 包,但它是扁平化的------只包含容器当前的文件系统状态,不包含镜像层历史和元数据。
bash
# 导出运行中的容器
docker export -o webapp-filesystem.tar webapp
# 导出已停止的容器
docker export -o backup-$(date +%Y%m%d).tar $(docker ps -aq -f name=webapp -f status=exited)
# 查看导出内容
tar -tf webapp-filesystem.tar | head -20
关键特性:
| 特性 | 说明 |
|---|---|
| 保留层历史 | ❌ 不保留,所有层合并为一个扁平文件系统 |
| 保留标签 | ❌ 不保留,导入后需要重新指定 |
| 保留 CMD/ENTRYPOINT | ❌ 丢失,导入后容器启动命令为空 |
| 文件体积 | 较小(仅当前状态,无历史层) |
| 适用场景 | 容器快照备份、取证分析、最小化镜像制作 |
9.4 docker import --- 从容器文件系统创建镜像
bash
# 从 export 的 tar 包创建新镜像
docker import webapp-filesystem.tar myapp:snapshot-20260513
# 导入时指定启动命令(因为 export 会丢失 CMD)
docker import --change 'CMD [\"nginx\", \"-g\", \"daemon off;\"]' \
webapp-filesystem.tar myapp:snapshot-20260513
# 导入时指定多个元数据
docker import \
--change 'ENV PATH=/usr/local/bin:$PATH' \
--change 'WORKDIR /app' \
--change 'EXPOSE 8080' \
--change 'CMD [\"node\", \"server.js\"]' \
webapp-filesystem.tar myapp:imported
9.5 save/export 核心差异对比
| 维度 | docker save + docker load |
docker export + docker import |
|---|---|---|
| 操作对象 | 镜像 | 容器 |
| 层历史 | ✅ 完整保留 | ❌ 扁平化丢失 |
| 镜像标签 | ✅ 自动恢复 | ❌ 需手动重新打标签 |
| 启动命令 | ✅ 保留 | ❌ 丢失,需 --change 重新指定 |
| 文件体积 | 较大 | 较小 |
| 适用场景 | 镜像迁移、备份归档 | 容器快照、最小化镜像、取证 |
| 推荐度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
9.6生产级案例:内网离线环境部署
场景:某银行核心系统部署在完全隔离的内网环境,无法访问外网,需要将镜像从开发环境迁移到生产环境。
Step 1:开发环境导出镜像
bash
# 1. 确认所有需要的镜像
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep -E "(myapp|nginx|postgres|redis)"
# 2. 导出所有镜像到一个压缩包
docker save \
mycompany/banking-api:v3.2.1 \
mycompany/banking-web:v2.1.0 \
nginx:1.25.3-alpine \
postgres:15.4-alpine \
redis:7.2.0-alpine \
prom/prometheus:v2.47.0 \
grafana/grafana:10.1.0 \
| gzip > banking-platform-images-v3.2.1.tar.gz
# 3. 计算校验和(确保传输过程中未被篡改)
sha256sum banking-platform-images-v3.2.1.tar.gz > banking-platform-images-v3.2.1.tar.gz.sha256
# 4. 验证文件完整性
sha256sum -c banking-platform-images-v3.2.1.tar.gz.sha256
Step 2:通过安全通道传输到生产环境
bash
# 使用 scp 或物理介质传输
scp banking-platform-images-v3.2.1.tar.gz \
banking-platform-images-v3.2.1.tar.gz.sha256 \
prod-admin@bank-prod-01:/data/docker-images/
Step 3:生产环境导入镜像
bash
# 1. 验证校验和
cd /data/docker-images
sha256sum -c banking-platform-images-v3.2.1.tar.gz.sha256
# 2. 导入镜像
gunzip -c banking-platform-images-v3.2.1.tar.gz | docker load
# 3. 验证导入结果
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep -E "(banking|nginx|postgres|redis)"
# 4. 为镜像添加私有仓库标签(如果后续需要推送到内部 Harbor)
docker tag mycompany/banking-api:v3.2.1 harbor.bank.local/core/banking-api:v3.2.1
docker tag mycompany/banking-web:v2.1.0 harbor.bank.local/core/banking-web:v2.1.0
# 5. 推送到内部 Harbor(如果配置了)
docker push harbor.bank.local/core/banking-api:v3.2.1
docker push harbor.bank.local/core/banking-web:v2.1.0
Step 4:部署服务
bash
# 使用 Swarm 或 Compose 部署
docker stack deploy -c compose.prod.yml banking-platform
# 验证部署
docker stack ps banking-platform
docker service ls
10. 生产环境版本升级流程
生产环境的版本升级是运维的高风险操作,必须遵循零停机、可回滚、可验证的原则。Docker 生态支持三种主流升级策略。
10.1 蓝绿部署(Blue-Green Deployment)
蓝绿部署同时运行两套完全独立的环境(蓝色=当前版本,绿色=新版本),通过负载均衡器切换流量。
bash
# === 蓝色环境(当前运行 v1.2.3)===
docker service create \
--name banking-api-blue \
--replicas 3 \
--network banking-network \
--label version=blue \
--label active=true \
-p 8080:8080 \
harbor.bank.local/core/banking-api:v1.2.3
# === 绿色环境(部署新版本 v1.2.4)===
docker service create \
--name banking-api-green \
--replicas 3 \
--network banking-network \
--label version=green \
--label active=false \
-p 8081:8080 \ # 使用不同端口,不对外暴露
harbor.bank.local/core/banking-api:v1.2.4
# === 验证绿色环境 ===
# 内部测试绿色环境
curl -s http://localhost:8081/health
curl -s http://localhost:8081/api/v1/accounts | jq .
# === 切换流量(负载均衡器层面)===
# 将 Nginx/HAProxy 配置从 8080 切换到 8081
# 或者使用 Docker Service 的 Label 路由
# === 回滚(如果绿色环境有问题)===
# 立即切回蓝色环境,无需等待容器重建
# 只需修改负载均衡器配置指向 8080
# === 清理蓝色环境(确认绿色稳定后)===
docker service rm banking-api-blue
docker service update --label-rm active banking-api-green
docker service update --label-add active=true banking-api-green
蓝绿部署优缺点:
| 优点 | 缺点 |
|---|---|
| 切换瞬间完成,零停机 | 需要双倍资源(同时运行两套环境) |
| 回滚极快(只需切流量) | 数据库 schema 变更需要特殊处理 |
| 可以在绿色环境充分验证 | 不适合有状态服务 |
10.2 滚动更新(Rolling Update)
滚动更新是 Docker Swarm 和 Kubernetes 的默认策略,逐个替换容器实例,确保始终有一定数量的实例在提供服务。
bash
# === Swarm 滚动更新 ===
docker service update \
--image harbor.bank.local/core/banking-api:v1.2.4 \
--update-parallelism 1 \ # 每次更新 1 个实例
--update-delay 30s \ # 每次更新间隔 30 秒
--update-failure-action rollback \ # 失败自动回滚
--update-order start-first \ # 先启动新容器再停旧容器
--stop-grace-period 60s \ # 优雅停机时间
banking-api
# === 监控滚动更新状态 ===
docker service ps banking-api --filter "desired-state=running"
watch -n 1 'docker service ps banking-api'
# === 如果更新失败,手动回滚 ===
docker service update --rollback banking-api
# === 查看更新历史 ===
docker service inspect --format '{{json .UpdateStatus}}' banking-api | jq .
关键参数详解:
| 参数 | 作用 | 生产建议 |
|---|---|---|
--update-parallelism |
同时更新的实例数 | 有状态服务设为 1,无状态可设为 2-3 |
--update-delay |
更新间隔时间 | 至少 30 秒,确保健康检查通过 |
--update-failure-action |
失败时的动作 | 必须设为 rollback,避免故障扩大 |
--update-order |
更新顺序 | start-first 可实现零停机 |
--stop-grace-period |
优雅停机时间 | 根据应用处理时间设置,默认 10 秒太短 |
10.3 金丝雀发布(Canary Release)
金丝雀发布将一小部分流量导入新版本,观察指标后再逐步扩大比例。
bash
# === 阶段 1:部署 1 个金丝雀实例(5% 流量)===
docker service scale banking-api=20 # 当前 20 个实例运行 v1.2.3
docker service update \
--image harbor.bank.local/core/banking-api:v1.2.4 \
--update-parallelism 1 \
banking-api-canary # 单独的服务
# 或者使用 Traefik/Nginx 权重路由
# 配置 95% 流量到 banking-api,5% 到 banking-api-canary
# === 阶段 2:监控金丝雀指标(持续 15 分钟)===
# 错误率
curl -s http://prometheus:9090/api/v1/query?query='rate(http_requests_total{job=\"banking-api-canary\",status=~\"5..\"}[5m])'
# 响应时间 P99
curl -s http://prometheus:9090/api/v1/query?query='histogram_quantile(0.99,rate(http_request_duration_seconds_bucket{job=\"banking-api-canary\"}[5m]))'
# 业务指标(交易成功率)
curl -s http://prometheus:9090/api/v1/query?query='rate(transaction_success_total{version=\"v1.2.4\"}[5m])'
# === 阶段 3:如果指标正常,扩大比例 ===
# 25% 流量
docker service scale banking-api-canary=5 banking-api=15
# 50% 流量
docker service scale banking-api-canary=10 banking-api=10
# === 阶段 4:全量发布 ===
docker service update \
--image harbor.bank.local/core/banking-api:v1.2.4 \
banking-api
docker service rm banking-api-canary
# === 阶段 5:如果指标异常,立即回滚 ===
docker service rm banking-api-canary
# 流量自动全部回到旧版本
10.4 生产级案例:金融系统零停机版本升级
场景:银行核心交易系统的 API 网关需要从 v3.2.1 升级到 v3.2.2,要求 99.99% 可用性,升级窗口仅 30 分钟。
升级前检查清单:
bash
#!/bin/bash
# pre-upgrade-check.sh
echo "=== 升级前检查 ==="
# 1. 确认当前版本
CURRENT_VERSION=$(docker service inspect --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}' banking-api | cut -d: -f2)
echo "当前版本: $CURRENT_VERSION"
# 2. 确认新镜像存在
docker pull harbor.bank.local/core/banking-api:v3.2.2
if [ $? -ne 0 ]; then
echo "错误:新镜像拉取失败"
exit 1
fi
# 3. 确认集群健康
UNHEALTHY=$(docker node ls -q | xargs docker node inspect --format '{{.Status.State}}' | grep -v ready | wc -l)
if [ $UNHEALTHY -gt 0 ]; then
echo "错误:有 $UNHEALTHY 个节点不健康"
exit 1
fi
# 4. 确认备份完成
echo "确认数据库备份已完成 (Y/n)?"
read confirm
if [ "$confirm" != "Y" ]; then
echo "取消升级"
exit 1
fi
# 5. 确认回滚镜像保留
docker images | grep banking-api | grep v3.2.1
if [ $? -ne 0 ]; then
echo "错误:回滚镜像 v3.2.1 不存在"
exit 1
fi
echo "检查通过,可以开始升级"
滚动更新执行:
bash
#!/bin/bash
# upgrade.sh
VERSION="v3.2.2"
IMAGE="harbor.bank.local/core/banking-api:$VERSION"
SERVICE="banking-api"
echo "=== 开始升级 $SERVICE 到 $VERSION ==="
# 1. 记录开始时间
START_TIME=$(date +%s)
# 2. 执行滚动更新
docker service update \
--image $IMAGE \
--update-parallelism 1 \
--update-delay 45s \
--update-failure-action rollback \
--update-order start-first \
--stop-grace-period 90s \
--health-cmd "curl -sf http://localhost:8080/health || exit 1" \
--health-interval 10s \
--health-timeout 5s \
--health-retries 3 \
$SERVICE
# 3. 监控更新进度
echo "监控更新进度..."
while true; do
STATUS=$(docker service inspect --format '{{.UpdateStatus.State}}' $SERVICE)
if [ "$STATUS" = "completed" ]; then
echo "更新完成"
break
elif [ "$STATUS" = "rollback_completed" ]; then
echo "错误:更新失败并已回滚"
exit 1
elif [ "$STATUS" = "paused" ]; then
echo "警告:更新已暂停,需要人工干预"
exit 1
fi
# 显示当前进度
RUNNING=$(docker service ps $SERVICE --filter "desired-state=running" | grep $VERSION | wc -l)
TOTAL=$(docker service ps $SERVICE --filter "desired-state=running" | wc -l)
echo "进度: $RUNNING / $TOTAL 实例已更新"
sleep 10
done
# 4. 验证新版本
ENDPOINT="http://localhost:8080"
HEALTH=$(curl -sf $ENDPOINT/health | jq -r '.status')
VERSION_CHECK=$(curl -sf $ENDPOINT/version | jq -r '.version')
if [ "$HEALTH" != "ok" ] || [ "$VERSION_CHECK" != "$VERSION" ]; then
echo "错误:新版本验证失败,执行回滚"
docker service update --rollback $SERVICE
exit 1
fi
# 5. 运行冒烟测试
echo "执行冒烟测试..."
./smoke-test.sh
if [ $? -ne 0 ]; then
echo "错误:冒烟测试失败,执行回滚"
docker service update --rollback $SERVICE
exit 1
fi
# 6. 记录升级完成
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "升级完成,耗时 $DURATION 秒"
# 7. 保留旧版本镜像(至少保留 2 个历史版本)
docker tag harbor.bank.local/core/banking-api:v3.2.1 harbor.bank.local/core/banking-api:v3.2.1-backup-$(date +%Y%m%d)
回滚脚本:
bash
#!/bin/bash
# rollback.sh
SERVICE="banking-api"
PREVIOUS_VERSION="v3.2.1"
echo "=== 执行紧急回滚 ==="
# 1. 立即停止当前更新
docker service update --detach=false $SERVICE
# 2. 执行回滚
docker service update \
--image harbor.bank.local/core/banking-api:$PREVIOUS_VERSION \
--update-parallelism 2 \
--update-delay 20s \
$SERVICE
# 3. 验证回滚
sleep 30
VERSION_CHECK=$(curl -sf http://localhost:8080/version | jq -r '.version')
if [ "$VERSION_CHECK" != "$PREVIOUS_VERSION" ]; then
echo "错误:回滚验证失败!"
exit 1
fi
echo "回滚完成"
11. 私有镜像仓库(Registry)镜像更新
在生产环境中,绝大多数团队使用私有镜像仓库(Harbor、Nexus、AWS ECR、阿里云 ACR 等)来管理镜像。以下是完整的镜像更新工作流。
11.1 配置私有仓库认证
bash
# 方式 1:docker login(临时,24小时有效)
docker login harbor.mycompany.com -u admin -p MySecurePassword123
# 方式 2:使用凭证文件(推荐 CI/CD 使用)
cat > ~/.docker/config.json <<EOF
{
"auths": {
"harbor.mycompany.com": {
"auth": "$(echo -n 'admin:MySecurePassword123' | base64)"
}
}
}
EOF
# 方式 3:使用 Docker Credential Helpers(最安全)
# 安装 pass 或 osxkeychain,配置 credsStore
11.2 镜像推送与拉取
bash
# === 推送镜像到私有仓库 ===
# 1. 构建镜像
docker build -t myapp:v1.2.3 .
# 2. 打标签(必须包含仓库地址)
docker tag myapp:v1.2.3 harbor.mycompany.com/project/myapp:v1.2.3
# 3. 推送镜像
docker push harbor.mycompany.com/project/myapp:v1.2.3
# 4. 推送多个标签
docker tag myapp:v1.2.3 harbor.mycompany.com/project/myapp:latest
docker tag myapp:v1.2.3 harbor.mycompany.com/project/myapp:stable
docker push harbor.mycompany.com/project/myapp:v1.2.3
docker push harbor.mycompany.com/project/myapp:latest
docker push harbor.mycompany.com/project/myapp:stable
# === 拉取镜像 ===
docker pull harbor.mycompany.com/project/myapp:v1.2.3
# === 使用摘要(digest)拉取(防止标签被篡改)===
docker pull harbor.mycompany.com/project/myapp@sha256:abc123...
11.3 镜像清理策略
私有仓库会不断膨胀,必须配置自动清理策略:
bash
# Harbor API 清理未使用的镜像
curl -X POST \
-u admin:password \
-H "Content-Type: application/json" \
"https://harbor.mycompany.com/api/v2.0/system/gc/schedule" \
-d '{
"schedule": {
"type": "Custom",
"cron": "0 0 * * 0"
},
"parameters": {
"delete_untagged": true,
"dry_run": false
}
}'
# 本地清理未使用的镜像(节省磁盘)
docker image prune -a -f --filter "until=168h" # 清理 7 天前的未使用镜像
11.4 镜像签名与验证(内容信任)
bash
# 启用 Docker Content Trust
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://notary.mycompany.com
# 推送签名镜像
docker trust sign harbor.mycompany.com/project/myapp:v1.2.3
# 验证签名
docker trust inspect --pretty harbor.mycompany.com/project/myapp:v1.2.3
# 在 Swarm 中强制使用签名镜像
docker service create \
--image harbor.mycompany.com/project/myapp:v1.2.3 \
--with-registry-auth \
--detach=false \
myapp
11.5 生产级案例:CI/CD 流水线中的镜像更新
场景:GitLab CI 流水线自动构建、扫描、推送镜像,并触发 Swarm 滚动更新。
.gitlab-ci.yml:
yaml
stages:
- build
- scan
- push
- deploy-staging
- deploy-production
variables:
DOCKER_REGISTRY: harbor.mycompany.com
IMAGE_NAME: $DOCKER_REGISTRY/core/banking-api
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
# 构建阶段
build:
stage: build
image: docker:24.0
services:
- docker:24.0-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $DOCKER_REGISTRY
script:
# 使用 BuildKit 多阶段构建
- export DOCKER_BUILDKIT=1
- docker build
--build-arg BUILD_ENV=production
--cache-from $IMAGE_NAME:latest
--tag $IMAGE_NAME:$CI_COMMIT_SHA
--tag $IMAGE_NAME:$CI_COMMIT_REF_SLUG
.
# 保存镜像供后续阶段使用
- docker save $IMAGE_NAME:$CI_COMMIT_SHA | gzip > image.tar.gz
artifacts:
paths:
- image.tar.gz
expire_in: 1 hour
# 安全扫描
scan:
stage: scan
image: aquasec/trivy:latest
script:
- gunzip -c image.tar.gz | docker load
- trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE_NAME:$CI_COMMIT_SHA
- trivy image --format template --template "@contrib/sarif.tpl" -o report.sarif $IMAGE_NAME:$CI_COMMIT_SHA
artifacts:
reports:
sast: report.sarif
# 推送到私有仓库
push:
stage: push
image: docker:24.0
services:
- docker:24.0-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $DOCKER_REGISTRY
script:
- gunzip -c image.tar.gz | docker load
# 推送版本标签
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
# 如果是主分支,推送 latest 和版本标签
- |
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
VERSION=$(cat VERSION)
docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:$VERSION
docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
docker push $IMAGE_NAME:$VERSION
docker push $IMAGE_NAME:latest
echo "VERSION=$VERSION" >> build.env
fi
artifacts:
reports:
dotenv: build.env
# 部署到 Staging
deploy-staging:
stage: deploy-staging
image: docker:24.0
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$STAGING_SSH_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
script:
- |
ssh -o StrictHostKeyChecking=no deploy@staging-server <<EOF
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $DOCKER_REGISTRY
docker pull $IMAGE_NAME:$CI_COMMIT_SHA
docker service update
--image $IMAGE_NAME:$CI_COMMIT_SHA
--with-registry-auth
staging_banking-api
EOF
environment:
name: staging
url: https://staging.bank.com
only:
- main
# 部署到 Production(需要手动审批)
deploy-production:
stage: deploy-production
image: docker:24.0
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$PRODUCTION_SSH_KEY" | tr -d '\r' | ssh-add -
script:
- |
ssh -o StrictHostKeyChecking=no deploy@prod-manager-01 <<EOF
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $DOCKER_REGISTRY
docker pull $IMAGE_NAME:$VERSION
docker service update
--image $IMAGE_NAME:$VERSION
--update-parallelism 1
--update-delay 30s
--update-failure-action rollback
--with-registry-auth
production_banking-api
EOF
environment:
name: production
url: https://bank.com
when: manual # 需要手动触发
only:
- main
生产环境部署后的验证脚本:
bash
#!/bin/bash
# post-deploy-verify.sh
VERSION=$1
ENDPOINT="https://bank.com"
echo "=== 生产环境部署验证 ==="
# 1. 验证版本号
DEPLOYED_VERSION=$(curl -sf $ENDPOINT/version | jq -r '.version')
if [ "$DEPLOYED_VERSION" != "$VERSION" ]; then
echo "错误:版本号不匹配 (期望: $VERSION, 实际: $DEPLOYED_VERSION)"
exit 1
fi
echo "版本号验证通过: $DEPLOYED_VERSION"
# 2. 验证健康检查
HEALTH=$(curl -sf $ENDPOINT/health | jq -r '.status')
if [ "$HEALTH" != "ok" ]; then
echo "错误:健康检查失败"
exit 1
fi
echo "健康检查通过"
# 3. 验证关键业务接口
# 3.1 账户查询
curl -sf "$ENDPOINT/api/v1/accounts/12345" > /dev/null
echo "账户查询接口正常"
# 3.2 交易创建
TRANSACTION=$(curl -sf -X POST "$ENDPOINT/api/v1/transactions" \
-H "Content-Type: application/json" \
-d '{"from":"12345","to":"67890","amount":100.00}' | jq -r '.id')
echo "交易创建接口正常, ID: $TRANSACTION"
# 3.3 交易查询
curl -sf "$ENDPOINT/api/v1/transactions/$TRANSACTION" > /dev/null
echo "交易查询接口正常"
# 4. 性能基准测试
echo "执行性能基准测试..."
ab -n 1000 -c 10 "$ENDPOINT/api/v1/accounts/12345" > benchmark.txt
RPS=$(grep \"Requests per second\" benchmark.txt | awk '{print $4}')
echo "RPS: $RPS"
# 5. 验证监控指标
echo "检查 Prometheus 指标..."
curl -sf "http://prometheus:9090/api/v1/query?query=up{job=\"banking-api\"}" | jq '.data.result[].value[1]' | grep -q "1"
echo "Prometheus 监控正常"
echo "=== 所有验证通过,部署成功 ==="
12. 容器导入导出补充说明
除了镜像级别的导入导出,有时也需要对运行中的容器进行迁移或备份。
12.1 容器 checkpoint(检查点)
Docker 支持使用 CRIU 创建容器的检查点,实现容器热迁移:
bash
# 创建检查点(暂停容器并保存状态)
docker checkpoint create webapp webapp-checkpoint-20260513
# 查看检查点列表
docker checkpoint ls webapp
# 从检查点恢复容器
docker start --checkpoint webapp-checkpoint-20260513 webapp
# 删除检查点
docker checkpoint rm webapp webapp-checkpoint-20260513
注意:容器 checkpoint 需要 Docker Engine 启用实验性功能,且对内核版本有要求,生产环境使用需谨慎。
12.2 容器文件系统备份
bash
# 备份容器内特定目录
docker exec webapp tar czf - /app/data > webapp-data-backup-$(date +%Y%m%d).tar.gz
# 从备份恢复
cat webapp-data-backup-20260513.tar.gz | docker exec -i webapp tar xzf - -C /
# 使用卷备份(更推荐)
docker run --rm \
-v webapp-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/webapp-data-backup.tar.gz -C /data .
12.3 生产级案例:完整的企业级 Docker 运维手册
以下是一个综合性的生产级运维场景,涵盖镜像导入导出、版本升级、仓库更新的完整流程:
场景:某大型电商公司需要将核心支付系统从 v2.5.0 升级到 v2.5.1,部署在 3 个数据中心的 Swarm 集群上,使用 Harbor 私有仓库。
完整操作流程:
bash
#!/bin/bash
# enterprise-upgrade.sh
# 企业级 Docker 升级完整流程
set -euo pipefail
# ========== 配置 ==========
REGISTRY="harbor.company.com"
PROJECT="payment"
IMAGE="payment-gateway"
OLD_VERSION="v2.5.0"
NEW_VERSION="v2.5.1"
STACK_NAME="payment-platform"
BACKUP_DIR="/data/docker-backups/$(date +%Y%m%d_%H%M%S)"
# ========== 前置检查 ==========
echo "=== 前置检查 ==="
# 1. 检查仓库连通性
curl -sf https://$REGISTRY/api/v2.0/health || {
echo "错误:无法连接到 Harbor 仓库"
exit 1
}
# 2. 检查新镜像是否存在
docker manifest inspect $REGISTRY/$PROJECT/$IMAGE:$NEW_VERSION > /dev/null 2>&1 || {
echo "错误:新镜像 $NEW_VERSION 不存在于仓库"
exit 1
}
# 3. 检查旧镜像是否存在(用于回滚)
docker manifest inspect $REGISTRY/$PROJECT/$IMAGE:$OLD_VERSION > /dev/null 2>&1 || {
echo "错误:回滚镜像 $OLD_VERSION 不存在于仓库"
exit 1
}
# 4. 检查集群健康
UNHEALTHY_NODES=$(docker node ls -q | xargs docker node inspect --format '{{.Status.State}}' | grep -v ready | wc -l)
if [ $UNHEALTHY_NODES -gt 0 ]; then
echo "错误:有 $UNHEALTHY_NODES 个节点不健康"
exit 1
fi
# 5. 创建备份目录
mkdir -p $BACKUP_DIR
# ========== 备份当前状态 ==========
echo "=== 备份当前状态 ==="
# 1. 导出当前运行的镜像
docker save $REGISTRY/$PROJECT/$IMAGE:$OLD_VERSION | gzip > $BACKUP_DIR/$IMAGE-$OLD_VERSION.tar.gz
echo "镜像已备份到 $BACKUP_DIR/$IMAGE-$OLD_VERSION.tar.gz"
# 2. 备份 Compose 配置
cp compose.prod.yml $BACKUP_DIR/compose.prod.yml.backup
echo "配置文件已备份"
# 3. 导出当前服务配置
docker service inspect $STACK_NAME\_$IMAGE > $BACKUP_DIR/service-config.json
echo "服务配置已备份"
# 4. 备份数据库(由 DBA 执行)
echo "请确认数据库备份已完成,按 Enter 继续..."
read
# ========== 预拉取镜像(减少更新时的拉取时间)==========
echo "=== 预拉取新镜像 ==="
docker pull $REGISTRY/$PROJECT/$IMAGE:$NEW_VERSION
# ========== 执行滚动更新 ==========
echo "=== 开始滚动更新 ==="
# 记录开始时间
START_TIME=$(date +%s)
# 执行更新
docker service update \
--image $REGISTRY/$PROJECT/$IMAGE:$NEW_VERSION \
--update-parallelism 1 \
--update-delay 60s \
--update-failure-action rollback \
--update-order start-first \
--stop-grace-period 120s \
--with-registry-auth \
$STACK_NAME\_$IMAGE
# 监控更新进度
echo "监控更新进度..."
while true; do
STATUS=$(docker service inspect --format '{{.UpdateStatus.State}}' $STACK_NAME\_$IMAGE)
case $STATUS in
"completed")
echo "更新完成"
break
;;
"rollback_completed")
echo "错误:更新失败,已自动回滚"
exit 1
;;
"paused")
echo "警告:更新已暂停"
read -p "按 r 回滚,按 c 继续: " choice
if [ "$choice" = "r" ]; then
docker service update --rollback $STACK_NAME\_$IMAGE
exit 1
fi
docker service update --detach=false $STACK_NAME\_$IMAGE
;;
esac
# 显示进度
RUNNING_NEW=$(docker service ps $STACK_NAME\_$IMAGE --filter "desired-state=running" | grep $NEW_VERSION | wc -l)
TOTAL=$(docker service ps $STACK_NAME\_$IMAGE --filter "desired-state=running" | wc -l)
echo "[$(date '+%H:%M:%S')] 进度: $RUNNING_NEW / $TOTAL 实例已更新 (状态: $STATUS)"
sleep 15
done
# ========== 验证新版本 ==========
echo "=== 验证新版本 ==="
# 1. 版本号验证
for endpoint in https://dc1.payment.company.com/version \
https://dc2.payment.company.com/version \
https://dc3.payment.company.com/version; do
DEPLOYED_VERSION=$(curl -sf $endpoint | jq -r '.version')
if [ "$DEPLOYED_VERSION" != "$NEW_VERSION" ]; then
echo "错误:$endpoint 版本号不匹配 (期望: $NEW_VERSION, 实际: $DEPLOYED_VERSION)"
docker service update --rollback $STACK_NAME\_$IMAGE
exit 1
fi
echo "$endpoint 版本验证通过: $DEPLOYED_VERSION"
done
# 2. 健康检查验证
for endpoint in https://dc1.payment.company.com/health \
https://dc2.payment.company.com/health \
https://dc3.payment.company.com/health; do
HEALTH=$(curl -sf $endpoint | jq -r '.status')
if [ "$HEALTH" != "ok" ]; then
echo "错误:$endpoint 健康检查失败"
docker service update --rollback $STACK_NAME\_$IMAGE
exit 1
fi
echo "$endpoint 健康检查通过"
done
# 3. 业务冒烟测试
echo "执行业务冒烟测试..."
./smoke-test-payment.sh
if [ $? -ne 0 ]; then
echo "错误:冒烟测试失败,执行回滚"
docker service update --rollback $STACK_NAME\_$IMAGE
exit 1
fi
# 4. 监控指标验证(持续 5 分钟)
echo "监控指标验证(持续 5 分钟)..."
for i in {1..30}; do
ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=rate(http_requests_total{job=\\\"payment-gateway\\\",status=~\\\"5..\\\"}[1m])" | jq -r '.data.result[0].value[1] // "0"')
if (( $(echo "$ERROR_RATE > 0.01" | bc -l) )); then
echo "错误:错误率过高 ($ERROR_RATE),执行回滚"
docker service update --rollback $STACK_NAME\_$IMAGE
exit 1
fi
echo "[$(date '+%H:%M:%S')] 错误率: $ERROR_RATE (正常)"
sleep 10
done
# ========== 升级完成 ==========
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "=== 升级成功 ==="
echo "版本: $OLD_VERSION -> $NEW_VERSION"
echo "耗时: $DURATION 秒"
echo "备份位置: $BACKUP_DIR"
# 保留旧版本镜像标签(用于快速回滚)
docker tag $REGISTRY/$PROJECT/$IMAGE:$OLD_VERSION $REGISTRY/$PROJECT/$IMAGE:$OLD_VERSION-backup-$(date +%Y%m%d)
docker push $REGISTRY/$PROJECT/$IMAGE:$OLD_VERSION-backup-$(date +%Y%m%d)
# 清理 30 天前的备份
find /data/docker-backups -type d -mtime +30 -exec rm -rf {} + 2>/dev/null || true
echo "所有操作完成"
以上就是 Docker 指令的完整扩展内容,涵盖了镜像/容器导入导出、生产环境版本升级、私有镜像仓库镜像更新等关键场景,并附带了可直接用于生产环境的完整脚本和案例。
二、Docker Compose 与 Docker Swarm 的关系详解
2.1 一句话定义
Docker Compose 是 Swarm 的"单机版",Docker Swarm 是 Compose 的"集群进化版"。
两者共享同一套 YAML 配置格式和设计理念,但解决的是不同层级的问题:Compose 解决单机多容器编排 ,Swarm 解决多机集群编排。
2.2 核心关系:四个维度
1. 配置兼容:同一份 YAML,两种运行模式
Docker Swarm 的设计初衷之一就是兼容 Compose 配置 。你可以将开发环境的 compose.yaml 直接用于 Swarm 生产部署,只需添加 deploy 字段描述集群策略:
yaml
# 这份文件既可以用 docker compose up 启动(开发环境)
# 也可以用 docker stack deploy 部署(Swarm 集群)
services:
web:
image: myapp:latest
ports:
- "80:8080"
# Swarm 专属字段,Compose 会忽略
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
关键差异 :Swarm 部署时会忽略 build 指令(必须使用预构建镜像),而 Compose 支持现场构建。
2. 命令继承:从 compose up 到 stack deploy
| 场景 | 命令 | 作用域 |
|---|---|---|
| 单机开发 | docker compose up -d |
当前主机的 Docker 引擎 |
| 集群生产 | docker stack deploy -c compose.yml myapp |
整个 Swarm 集群 |
docker stack deploy 底层复用了 Compose 的 YAML 解析逻辑,但将容器调度从本地引擎 升级为集群调度器。
3. 架构升级:从单机到集群的平滑过渡
┌─────────────────────────────────────────┐
│ Docker Compose │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 容器 A │ │ 容器 B │ │ 容器 C │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ 同一台主机的 Docker 引擎 │
└─────────────────────────────────────────┘
↓ 演进
┌─────────────────────────────────────────┐
│ Docker Swarm │
│ ┌─────────┐ ┌─────────┐ │
│ │Manager │◄────►│ Worker 1│ 容器 A,B │
│ │(调度器) │ └─────────┘ │
│ └─────────┘ ┌─────────┐ │
│ ▲ │ Worker 2│ 容器 C │
│ │ └─────────┘ │
│ ┌────┴───┐ │
│ │ Worker 3│ 容器 A 副本 │
│ └─────────┘ │
│ 跨多台主机的虚拟化 Docker 引擎 │
└─────────────────────────────────────────┘
4. 设计哲学:开发效率 vs 生产可用性
| 维度 | Docker Compose | Docker Swarm |
|---|---|---|
| 首要目标 | 让开发者快速搭建本地环境 | 让运维人员管理生产集群 |
| 高可用 | ❌ 单点故障 = 服务中断 | ✅ 节点故障自动迁移容器 |
| 服务发现 | 容器名 DNS(仅限本机) | 集群级 VIP + DNS 轮询 |
| 扩缩容 | 手动修改配置重启 | docker service scale web=5 |
| 滚动更新 | 全量重启 | 金丝雀发布、零停机更新 |
| 负载均衡 | 无内置 | 入口路由网格自动分发 |
2.3 历史演进:从独立工具到内置集群
第一阶段:独立 Swarm(2014-2016)
- Swarm 最初是独立于 Docker Engine 的集群管理工具
- 需要单独安装,与 Compose 完全分离
第二阶段:Swarm Mode(Docker 1.12+,2016 至今)
- Docker 将 Swarm 直接集成进 Docker Engine
- 使用 SwarmKit 作为编排层,与 Docker CLI 深度统一
- 引入
docker stack deploy命令,原生支持 Compose 文件格式 - 从此 Compose 和 Swarm 形成"开发-生产"闭环
2.4 实战:从 Compose 到 Swarm 的迁移路径
Step 1:开发环境(Compose)
bash
# 本地开发,快速迭代
docker compose up -d --build
Step 2:构建镜像并推送到仓库
bash
docker compose build
docker compose push # 推送到镜像仓库,Swarm 节点才能拉取
Step 3:初始化 Swarm 集群
bash
# 在管理节点执行
docker swarm init --advertise-addr 192.168.1.100
# 获取 Worker 加入令牌
docker swarm join-token worker
Step 4:生产部署(Swarm)
bash
# 使用同一份 compose.yaml(已添加 deploy 字段)
docker stack deploy -c compose.yaml myapp
Step 5:运维管理
bash
# 查看服务状态
docker service ls
docker service ps myapp_web
# 动态扩缩容
docker service scale myapp_web=5
# 滚动更新
docker service update --image myapp:v2 myapp_web
2.5 常见误区澄清
| 误区 | 真相 |
|---|---|
| "Compose 和 Swarm 是竞争关系" | ❌ 错误。它们是互补关系,Compose 用于开发,Swarm 用于生产 |
| "Swarm 已经死了,应该直接用 K8s" | ⚠️ 片面。Swarm 在 2025 年仍获 Mirantis 支持至 2030 年,适合中小团队 |
| "Swarm 不支持 Compose 文件" | ❌ 错误。docker stack deploy 原生支持 Compose YAML |
| "单节点 Swarm 不如 Compose" | ⚠️ 视场景而定。单节点 Swarm 仍提供服务发现和自动重启能力 |
三、Docker Compose 详解
3.1 版本演进:V1 → V2(2026年现状)
Docker Compose 经历了重大架构重构,2026年已全面进入 V2 时代:
| 对比维度 | V1(已废弃) | V2(当前主流) |
|---|---|---|
| 实现语言 | Python | Go |
| 命令格式 | docker-compose(连字符) |
docker compose(空格) |
| 安装方式 | 独立二进制文件 | Docker CLI 插件(随 Docker Engine 自动安装) |
| 与 Docker 集成 | 独立工具,需单独升级 | 深度集成,升级 Docker 同步更新 |
| 性能 | 较慢,存在 Python 环境依赖 | 更快,启动速度提升约 40% |
| 新特性支持 | 不支持 profiles、watch 等 | 完整支持所有新特性 |
| 维护状态 | 2023 年 7 月起停止更新 | 官方主推,持续迭代 |
2026 年关键变化 :Compose Specification v5.0.0(代号"Mont Blanc")于 2025 年底发布,移除了内部构建器,统一委托给 Docker Bake,与标准 docker build 行为对齐,支持多平台构建和更优的缓存策略。
迁移建议 :如果你还在使用 docker-compose,应立即迁移到 docker compose。配置文件语法基本兼容,只需将命令中的连字符替换为空格即可。
bash
# 验证当前版本
docker compose version
# 预期输出:Docker Compose version v2.40.x
3.2 核心配置文件结构(2026 年推荐写法)
2026 年推荐的配置文件名为 compose.yaml(不再强制要求 version 字段,Compose 会自动识别格式):
yaml
# compose.yaml --- 2026 年推荐格式
services:
web:
build:
context: ./web
dockerfile: Dockerfile
# 支持 BuildKit 多阶段构建
args:
BUILD_ENV: production
image: myapp/web:latest
container_name: web_app
ports:
- target: 8080 # 容器端口
published: 80 # 宿主机端口
protocol: tcp
mode: host # host 模式(Swarm 场景)
environment:
- DB_HOST=db
- REDIS_HOST=redis
env_file:
- .env.production
volumes:
- type: volume
source: web-data
target: /app/data
- type: bind
source: ./config
target: /app/config
read_only: true
networks:
- frontend
- backend
depends_on:
db:
condition: service_healthy # 等待数据库健康后才启动
redis:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
disable: false
# 2026 年新增:开发模式热重载
develop:
watch:
- action: sync
path: ./src
target: /app/src
ignore:
- node_modules/
- "*.test.js"
- action: rebuild
path: package.json
- action: restart
path: ./config
# 资源限制(生产环境必备)
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- type: volume
source: db-data
target: /var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- type: volume
source: redis-data
target: /data
networks:
- backend
# 2026 年新增:profiles 条件启动
# 使用 docker compose --profile dev up 才会启动
dev-tools:
image: mailhog/mailhog
ports:
- "8025:8025"
profiles:
- dev
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 无外部访问,增强安全性
volumes:
web-data:
db-data:
redis-data:
secrets:
db_password:
file: ./secrets/db_password.txt
3.3 生命周期管理指令详解
3.3.1 项目启动与停止
bash
# 创建并启动所有服务(前台运行,查看实时日志)
docker compose up
# 后台守护进程模式(生产环境常用)
docker compose up -d
# 启动前强制重新构建镜像(代码更新后)
docker compose up --build
# 强制重新创建所有容器(清除旧状态)
docker compose up --force-recreate
# 只启动指定服务及其依赖
docker compose up -d web db
# 优雅停止容器(保留容器状态,可快速重启)
docker compose stop
# 启动已停止的容器
docker compose start
# 完全清理:停止并删除容器、网络(开发环境常用)
docker compose down
# 深度清理:同时删除数据卷(⚠️ 数据会丢失!)
docker compose down -v
# 清理孤儿容器(不在 Compose 文件中定义的容器)
docker compose down --remove-orphans
3.3.2 调试与监控指令
bash
# 查看服务运行状态
docker compose ps
docker compose ps -a # 包含已停止的
# 查看实时日志(排查问题第一步)
docker compose logs -f
docker compose logs -f --tail=100 web # 只看 web 服务最后100行
docker compose logs -t web # 带时间戳
# 进入运行中的容器执行命令
docker compose exec web bash
docker compose exec -u root db psql -U postgres myapp
# 运行一次性容器(执行完即停)
docker compose run --rm web python manage.py migrate
# 查看容器内进程
docker compose top
# 查看资源使用情况
docker compose stats
3.3.3 构建与镜像管理
bash
# 构建所有服务镜像
docker compose build
# 不使用缓存构建(确保最新依赖)
docker compose build --no-cache
# 拉取最新基础镜像
docker compose build --pull
# 拉取远程镜像
docker compose pull
# 推送到镜像仓库
docker compose push
# 验证并查看合并后的配置
docker compose config
3.3.4 开发效率利器:Watch 模式(V2.22+)
Compose V2.22+ 引入的 watch 指令,实现代码热重载,告别手动重建:
bash
# 启动文件监控(自动重建+重启)
docker compose watch
对应配置:
yaml
services:
web:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
ignore:
- node_modules/
- "*.test.js"
- action: rebuild
path: package.json
- action: restart
path: ./config
3.3.5 多环境配置:Override 模式
2026 年最佳实践是使用 Override 文件分离环境配置,而非在一个文件中堆砌条件:
bash
# 开发环境(默认)
docker compose up
# 生产环境(显式覆盖)
docker compose -f compose.yaml -f compose.prod.yaml up -d
base 文件(compose.yaml) :定义共享服务和基础配置
override 文件(compose.prod.yaml):仅覆盖生产环境差异
yaml
# compose.prod.yaml
services:
web:
restart: always
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
# 生产环境移除源码挂载
volumes: !reset [] # 重置为空
3.3.6 Profiles:条件化服务启动
bash
# 只启动基础服务(不含 dev-tools)
docker compose up -d
# 启动包含 dev profile 的服务
docker compose --profile dev up -d
# 同时激活多个 profile
docker compose --profile dev --profile monitoring up -d
3.4 Docker Compose vs Docker Stack 的关键区别
很多开发者混淆了 Compose 和 Stack 的边界,核心区别在于:
| 特性 | Docker Compose | Docker Stack(Swarm 模式) |
|---|---|---|
| 运行环境 | 单机 | 多节点集群 |
| 配置文件 | docker-compose.yml |
docker-compose.yml(需兼容 Swarm) |
| 构建支持 | ✅ 支持 build 指令 |
❌ 不支持 build,仅使用预构建镜像 |
| 部署指令 | ❌ 不支持 deploy |
✅ 支持 deploy(副本、滚动更新等) |
| 服务发现 | 基础 DNS | 内置 DNS + 负载均衡 |
| 扩缩容 | 手动修改配置 | docker service scale |
| 高可用 | 无 | Manager 副本 + 自动故障转移 |
结论:Compose 是单机开发/测试工具,Stack 是 Swarm 集群的生产部署工具。
3.5 生产级案例:电商微服务全栈部署
场景:一个包含前端、API 网关、订单服务、支付服务、数据库、Redis、Nginx 的电商系统。
项目结构:
ecommerce-platform/
├── compose.yaml # 基础配置
├── compose.prod.yaml # 生产覆盖
├── compose.override.yaml # 开发覆盖(自动加载)
├── .env # 环境变量
├── secrets/
│ ├── db_password.txt
│ └── jwt_secret.txt
├── nginx/
│ ├── Dockerfile
│ └── nginx.conf
├── frontend/
│ └── Dockerfile
├── api-gateway/
│ └── Dockerfile
├── order-service/
│ └── Dockerfile
└── payment-service/
└── Dockerfile
compose.yaml(基础配置):
yaml
services:
nginx:
build: ./nginx
ports:
- target: 80
published: 80
- target: 443
published: 443
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- nginx-logs:/var/log/nginx
networks:
- frontend
depends_on:
- api-gateway
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 10s
timeout: 5s
retries: 3
api-gateway:
build: ./api-gateway
environment:
- ORDER_SERVICE_URL=http://order-service:8080
- PAYMENT_SERVICE_URL=http://payment-service:8080
- REDIS_URL=redis://redis:6379
networks:
- frontend
- backend
depends_on:
order-service:
condition: service_healthy
payment-service:
condition: service_healthy
redis:
condition: service_healthy
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
order-service:
build: ./order-service
environment:
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=orders
- DB_USER=order_user
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
volumes:
- order-logs:/app/logs
networks:
- backend
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
payment-service:
build: ./payment-service
environment:
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=payments
- DB_USER=payment_user
- DB_PASSWORD_FILE=/run/secrets/db_password
- JWT_SECRET_FILE=/run/secrets/jwt_secret
secrets:
- db_password
- jwt_secret
volumes:
- payment-logs:/app/logs
networks:
- backend
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: ecommerce
POSTGRES_USER: admin
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d:ro
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
deploy:
resources:
limits:
cpus: '1.0'
memory: 2G
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
# 开发环境专用:邮件捕获工具
mailhog:
image: mailhog/mailhog
ports:
- "8025:8025"
networks:
- backend
profiles:
- dev
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
postgres-data:
redis-data:
nginx-logs:
order-logs:
payment-logs:
secrets:
db_password:
file: ./secrets/db_password.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
compose.prod.yaml(生产覆盖):
yaml
services:
nginx:
restart: always
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
api-gateway:
restart: always
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
order-service:
restart: always
deploy:
replicas: 2
resources:
limits:
cpus: '1.0'
memory: 1G
payment-service:
restart: always
deploy:
replicas: 2
resources:
limits:
cpus: '1.0'
memory: 1G
postgres:
restart: always
deploy:
resources:
limits:
cpus: '2.0'
memory: 4G
redis:
restart: always
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
部署流程:
bash
# 1. 开发环境启动(含 mailhog)
docker compose --profile dev up -d --build
# 2. 查看服务状态
docker compose ps
# 3. 查看实时日志
docker compose logs -f api-gateway
# 3. 运行数据库迁移
docker compose exec order-service python manage.py migrate
# 4. 构建生产镜像并推送
docker compose -f compose.yaml build
docker compose -f compose.yaml push
# 5. 生产环境部署(Swarm)
docker stack deploy -c compose.yaml -c compose.prod.yaml ecommerce
# 6. 验证生产部署
docker stack ps ecommerce
docker service ls
docker service logs -f ecommerce_api-gateway
四、Docker Swarm:原生集群编排
Docker Swarm 是 Docker 内置的集群编排工具,最大优势是零学习成本------如果你会用 Compose,几乎可以直接上手 Swarm。
4.1 集群初始化与节点管理
bash
# 初始化集群(Manager 节点)
docker swarm init --advertise-addr 192.168.1.100
# 获取 Worker 加入令牌
docker swarm join-token worker
# Worker 节点加入集群
docker swarm join --token SWMTKN-1-xxx 192.168.1.100:2377
# 查看集群节点
docker node ls
# 给节点打标签(用于约束调度)
docker node update --label-add role=database node1
docker node update --label-add zone=beijing node2
# 提升 Worker 为 Manager
docker node promote node2
# 节点脱离集群
docker swarm leave
4.2 服务部署与扩缩容
bash
# 部署服务(类似 docker compose up)
docker stack deploy -c docker-compose.yml myapp
# 查看服务列表
docker service ls
# 查看服务详情
docker service ps myapp_web
# 扩容到 5 个副本
docker service scale myapp_web=5
# 滚动更新镜像
docker service update --image myapp:v2 myapp_web
# 配置滚动更新策略
docker service update \
--update-parallelism 2 \
--update-delay 10s \
--update-failure-action rollback \
myapp_web
# 删除服务
docker service rm myapp_web
4.3 Swarm 专属 Compose 配置
yaml
version: '3.8'
services:
web:
image: myapp:latest
deploy:
replicas: 3
update_config:
parallelism: 1 # 每次更新1个实例
delay: 10s # 更新间隔
failure_action: rollback # 失败自动回滚
order: start-first # 先启动新容器再停旧容器
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
placement:
constraints:
- node.role == worker
- node.labels.zone == beijing
resources:
limits:
cpus: '0.5'
memory: 512M
ports:
- target: 8080
published: 80
mode: host # host 模式避免 Swarm 路由网格
networks:
- app-network
db:
image: postgres:15
deploy:
replicas: 1
placement:
constraints:
- node.role == manager # 数据库部署在 Manager
volumes:
- db-data:/var/lib/postgresql/data
secrets:
- db_password
networks:
app-network:
driver: overlay
attachable: true # 允许独立容器加入
volumes:
db-data:
secrets:
db_password:
external: true
4.4 生产级案例:Swarm 部署高可用电商系统
场景:3 节点 Swarm 集群(1 Manager + 2 Worker),部署电商系统,要求 99.9% 可用性。
集群架构:
┌─────────────────────────────────────────┐
│ Manager Node (node-1) │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Raft Leader│ │ PostgreSQL 主库 │ │
│ │ (调度器) │ │ (数据持久化) │ │
│ └─────────────┘ └──────────────────┘ │
└─────────────────────────────────────────┘
↓ 管理流量
┌─────────────────────────────────────────┐
│ Worker Node 1 (node-2) │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ API GW x2│ │ Order x2 │ │ Redis │ │
│ └──────────┘ └──────────┘ └────────┘ │
└─────────────────────────────────────────┘
↓ 管理流量
┌─────────────────────────────────────────┐
│ Worker Node 2 (node-3) │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ API GW x2│ │ Payment │ │ Nginx │ │
│ └──────────┘ └──────────┘ └────────┘ │
└─────────────────────────────────────────┘
部署步骤:
bash
# Step 1: 初始化集群
docker swarm init --advertise-addr 192.168.1.10
# Step 2: Worker 节点加入
# 在 node-2 和 node-3 执行:
docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377
# Step 3: 给节点打标签
docker node update --label-add tier=frontend node-2
docker node update --label-add tier=backend node-3
docker node update --label-add db=primary node-1
# Step 4: 创建加密 Overlay 网络
docker network create --driver overlay --opt encrypted --attachable app-network
# Step 5: 部署服务栈
docker stack deploy -c compose.yaml -c compose.prod.yaml ecommerce
# Step 6: 验证部署
docker stack ps ecommerce
docker service ls
# Step 7: 监控和扩缩容
# 高峰期扩容 API 网关
docker service scale ecommerce_api-gateway=6
# 低谷期缩容
docker service scale ecommerce_api-gateway=3
# Step 8: 滚动更新(零停机发布)
docker service update \
--image mycompany/api-gateway:v2.0.0 \
--update-parallelism 1 \
--update-delay 20s \
--update-failure-action rollback \
ecommerce_api-gateway
# Step 9: 故障演练(模拟节点故障)
docker node update --availability drain node-2
# 观察服务自动迁移到 node-3
docker service ps ecommerce_api-gateway
# Step 10: 清理
docker stack rm ecommerce
docker swarm leave --force # Manager 节点
五、Kubernetes:企业级编排标准
虽然 K8s 学习曲线陡峭,但其强大的抽象能力和生态成熟度使其成为大规模生产环境的不二之选。
5.1 核心资源对象速查
| 资源对象 | 作用 | 类比 Docker |
|---|---|---|
| Pod | 最小调度单元,包含一个或多个容器 | 容器组 |
| Deployment | 管理 Pod 的声明式更新 | Compose 服务 |
| Service | 暴露 Pod 的网络访问 | 端口映射 + LB |
| ConfigMap/Secret | 配置与敏感信息管理 | env/volumes |
| Ingress | HTTP/HTTPS 路由 | 反向代理 |
| PersistentVolume | 持久化存储 | volumes |
| Namespace | 资源隔离边界 | 项目前缀 |
5.2 常用 kubectl 指令
bash
# ========== 集群与节点 ==========
kubectl cluster-info
kubectl get nodes -o wide
kubectl describe node node1
# ========== Pod 生命周期 ==========
kubectl run nginx --image=nginx:alpine
kubectl get pods -o wide
kubectl describe pod nginx
kubectl logs -f nginx
kubectl exec -it nginx -- /bin/sh
kubectl delete pod nginx
# ========== Deployment 管理 ==========
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl scale deployment nginx --replicas=5
kubectl set image deployment/nginx nginx=nginx:1.21
kubectl rollout status deployment/nginx
kubectl rollout history deployment/nginx
kubectl rollout undo deployment/nginx # 回滚
# ========== Service 与网络 ==========
kubectl expose deployment nginx --port=80 --type=LoadBalancer
kubectl get svc
kubectl port-forward svc/nginx 8080:80
# ========== 配置管理 ==========
kubectl create configmap app-config --from-file=config.json
kubectl create secret generic db-pass --from-literal=password=123456
kubectl get configmaps
kubectl get secrets
# ========== 存储 ==========
kubectl apply -f pvc.yaml
kubectl get pv,pvc
# ========== 命名空间 ==========
kubectl create namespace production
kubectl get all -n production
kubectl config set-context --current --namespace=production
5.3 典型 Deployment 配置
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
labels:
app: web
version: v1
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 0
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
version: v1
spec:
containers:
- name: web
image: myapp:v1.2.3
ports:
- containerPort: 8080
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: db_host
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: config-vol
mountPath: /app/config
readOnly: true
volumes:
- name: config-vol
configMap:
name: app-config
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname
5.4 生产级案例:K8s 部署金融级微服务
场景:银行核心系统,要求 99.99% SLA,多可用区部署,自动故障转移。
架构设计:
┌─────────────────────────────────────────┐
│ Ingress Controller │
│ (Nginx / Traefik / Istio) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Service (ClusterIP) │
│ 负载均衡 + 服务发现 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Deployment (3 replicas) │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Pod 1 │ │ Pod 2 │ │ Pod 3 │ │
│ │ Zone A │ │ Zone B │ │ Zone C │ │
│ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ StatefulSet (PostgreSQL 主从) │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Master │ │ Slave │ │ Slave │ │
│ │ Zone A │ │ Zone B │ │ Zone C │ │
│ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────┘
关键配置:
yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: banking-api
namespace: production
spec:
replicas: 6
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: banking-api
template:
metadata:
labels:
app: banking-api
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- banking-api
topologyKey: topology.kubernetes.io/zone
containers:
- name: api
image: registry.bank.com/banking-api:v3.2.1
ports:
- containerPort: 8443
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 8443
scheme: HTTPS
initialDelaySeconds: 60
periodSeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 8443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 5
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
---
# hpa.yaml --- 自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: banking-api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: banking-api
minReplicas: 6
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
部署流程:
bash
# 1. 创建命名空间
kubectl create namespace production
# 2. 应用配置
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
kubectl apply -f hpa.yaml
kubectl apply -f pdb.yaml # PodDisruptionBudget
# 3. 验证部署
kubectl get all -n production
kubectl get pods -n production -o wide
kubectl top pods -n production
# 4. 滚动更新(金丝雀发布)
kubectl set image deployment/banking-api \
api=registry.bank.com/banking-api:v3.2.2 \
-n production
# 5. 监控滚动状态
kubectl rollout status deployment/banking-api -n production
# 6. 回滚(如果出现问题)
kubectl rollout undo deployment/banking-api -n production
# 7. 查看历史版本
kubectl rollout history deployment/banking-api -n production
六、框架选型总结
| 场景 | 推荐方案 | 核心指令 |
|---|---|---|
| 本地开发/测试 | Docker Compose | docker compose up -d |
| CI/CD 流水线 | Docker Compose | docker compose -f compose.test.yml up --abort-on-container-exit |
| 中小规模生产(<50容器) | Docker Swarm | docker stack deploy -c compose.yml app |
| 大规模微服务(>100容器) | Kubernetes | kubectl apply -f manifests/ |
| 混合工作负载(VM+容器) | Nomad | nomad job run job.hcl |
关键建议:
- 不要过度工程化:5个微服务用 K8s 是杀鸡用牛刀,Swarm 可能更合适
- 基础设施即代码:无论选择哪种编排工具,都要将配置纳入版本控制
- 监控先行:部署只是开始,Prometheus + Grafana 的监控体系必须同步建设
- 渐进式演进:从 Compose 到 Swarm 再到 K8s 是风险最低的演进路径
容器编排没有银弹,理解各工具的设计哲学与适用边界,才能在实际项目中做出正确的技术决策。希望本文能成为你容器编排实战路上的可靠参考。