从 Docker 到容器编排:框架选型与指令详解实战指南

容器化技术彻底改变了应用交付的方式,但当业务规模从单机扩展到集群时,容器编排(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 upstack 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 是风险最低的演进路径

容器编排没有银弹,理解各工具的设计哲学与适用边界,才能在实际项目中做出正确的技术决策。希望本文能成为你容器编排实战路上的可靠参考。


相关推荐
ole ' ola19 小时前
Linux DDR内存使用情况
linux·运维·服务器
CingSyuan19 小时前
华为/长江计算 国产信创服务器:基于 BMC 远程 KVM 安装操作系统
运维·服务器·kylin
杨浦老苏19 小时前
自托管文件同步与协作平台Sync-in
docker·文件管理·群晖·协作
Kingairy19 小时前
Linux 机器信任关系
linux·运维·服务器
齐齐大魔王20 小时前
OpenSSL 原理
运维·网络·nginx·ssh·ssl
流浪00120 小时前
Linux系统篇(一):从零入门操作系统:冯诺依曼体系到进程的完整理解
linux·运维·服务器
STDD20 小时前
Node-RED 自托管部署指南:打造可视化 IoT 自动化平台
运维·物联网·自动化
hj28625120 小时前
Linux学习方法论 + 系统安全加固与性能优化 完整版笔记(含案例)
运维
刘某的Cloud20 小时前
硬链接 和 软链接 区别
运维·系统·硬链接·软链接
jiayong2320 小时前
harness 与 hermes-agent 扩展性、安全与运维
运维·人工智能·安全·ai·架构·智能体·harness