讲解

收官一章,把散落各章的原则收拢成一张发布前检查清单。镜像侧:基础镜像锁版本(最好锁 digest)、体积最小化(alpine/distroless + 多阶段)、.dockerignore 防泄密、镜像里不带任何密钥、非 root 运行、一个容器只跑一个主进程。构建侧:Dockerfile 进版本库、依赖清单先行吃满缓存、CI 里构建并扫漏洞、镜像打语义化标签再推仓库。

运行侧:重启策略 unless-stopped;--memory/--cpus 必配;日志进 stdout 且配轮转;敏感配置走 secret 不走 ENV;端口最小暴露(内部服务零映射);只读根文件系统 + 按需 tmpfs;健康检查让编排系统能判断死活。数据侧:有状态数据进命名卷;备份独立于卷和机器;恢复流程要演练过(没演练过的备份约等于没有)。

心智层面三句话收尾。不可变基础设施:改任何东西靠重建容器,不在运行中的容器里做手术——exec 进去改配置是反模式。声明优于命令:能写进 compose/Dockerfile 的不留在手册里,环境差异全部参数化。小步验证:每一层(镜像构建、单容器、compose 栈、发布)都有可执行的验证命令,本教程每章的示例就是这个习惯的示范。到这里,你已经具备用 Docker 独立交付一个应用的完整技能——剩下的功夫在真实项目里。

示例

发布前自检脚本:确认镜像非 root、有健康检查、标签规范(对本教程的实战镜像逐项检查):

img=ohmydocs-verify-nodeapp:1.0.0
user=$(docker image inspect "$img" --format '{{.Config.User}}')
[ "$user" = "node" ] && echo "✓ 非 root 用户 ($user)"
size=$(docker image inspect "$img" --format '{{.Size}}')
echo "✓ 镜像大小 $((size / 1024 / 1024)) MB (alpine 基底)"
docker image inspect "$img" --format '✓ 启动命令 {{json .Config.Cmd}}'

最终形态参考:一份带过实战栈全部纪律的 compose 骨架(仅示意,不启动):

# 仅示意:生产骨架——锁版本、健康检查、资源限制、只读、非 root、命名卷
services:
  app:
    image: registry.example.com/team/app:1.0.0
    user: "1000:1000"
    read_only: true
    tmpfs: ["/tmp"]
    mem_limit: 256m
    cpus: 0.5
    restart: unless-stopped
    env_file: .env
    ports: ["127.0.0.1:3000:3000"]
    depends_on:
      db: { condition: service_healthy }
  db:
    image: mysql:8.0
    restart: unless-stopped
    env_file: .env
    volumes: ["dbdata:/var/lib/mysql"]
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
      interval: 5s
      retries: 20
volumes:
  dbdata:

用 config 校验上面的骨架语法正确(只解析不启动):

cat > skeleton-check.yaml <<'YAML'
services:
  app:
    image: alpine:3.21
    read_only: true
    restart: unless-stopped
    depends_on:
      db: { condition: service_started }
  db:
    image: alpine:3.21
    volumes: ["dbdata:/data"]
volumes:
  dbdata:
YAML
docker compose -f skeleton-check.yaml config --quiet && echo "骨架语法合法"

回顾全程创建过的教程资源(清理脚本会按此前缀统一回收):

docker images --filter "reference=ohmydocs-verify-*" --format '{{.Repository}}:{{.Tag}}'

常见坑

  • 清单收藏不执行:把检查清单做成 CI 脚本(如上面的非 root 检查),自动化才有约束力。
  • 在运行容器里热修:exec 进去改配置、装包,下次重建全部丢失且无人记得——改 Dockerfile 重建。
  • 演练只有构建没有恢复:定期做「删库重建 + 备份恢复」演习,恢复时长要心里有数。
  • 学了 Compose 跳过编排进阶:多机需求出现时(滚动更新、自动扩缩),评估 Kubernetes——但先把单机纪律做好。

小结

检查清单覆盖镜像、构建、运行、数据四侧;三条心智:不可变、声明式、小步验证。教程完结——去把你手头的第一个服务容器化吧。