CI/CD 是什么
CI(持续集成,Continuous Integration):开发者频繁向主分支提交代码,每次提交自动触发构建、测试,尽早发现问题。
CD(持续交付/部署,Continuous Delivery/Deployment):通过 CI 的代码自动发布到测试/生产环境,减少手动发布的风险。
Docker 在 CI/CD 中的核心价值
- 构建标准化:每次构建使用相同的镜像,消除"在 CI 机上能跑"问题
- 环境一致性:开发、测试、生产使用同一个镜像,真正做到环境一致
- 镜像即交付物:镜像是不可变的,构建一次,到处运行,每个版本可精确回滚
GitHub Actions 完整工作流
基础:构建并推送镜像
# .github/workflows/docker-publish.yml
name: Build and Push Docker Image
on:
push:
branches:
- main
tags:
- 'v*' # v1.0.0 等标签触发
pull_request:
branches:
- main # PR 只构建不推送
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }} # org/repo
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
# 1. 拉取代码
- name: Checkout repository
uses: actions/checkout@v4
# 2. 配置 QEMU(跨平台构建需要)
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# 3. 配置 Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# 4. 登录 GitHub Container Registry
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 5. 提取元数据(自动生成标签)
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch # main → :main
type=ref,event=pr # PR → :pr-42
type=semver,pattern={{version}} # v1.2.3 → :1.2.3
type=semver,pattern={{major}}.{{minor}} # → :1.2
type=sha # → :sha-abc1234
# 6. 构建并推送多平台镜像
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # 使用 GitHub Actions 缓存
cache-to: type=gha,mode=max
镜像标签策略在 CI 中
不同触发事件打不同标签,满足不同用途:
| 触发事件 | 生成标签 | 用途 |
|---|---|---|
| push to main | :main, :sha-abc1234 | 最新主分支,用于持续部署到 staging |
| push tag v1.2.3 | :1.2.3, :1.2, :latest | 正式版本,用于生产部署 |
| feature 分支 | :feature-login | 功能测试 |
| Pull Request | :pr-42(只构建不推送) | PR 验证 |
Docker Scout 安全检查
在 CI 流水线中集成漏洞扫描,阻止有高危漏洞的镜像部署:
# 在 build step 之后添加
- name: Docker Scout CVE scan
uses: docker/scout-action@v1
with:
command: cves
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
only-severities: critical,high
exit-code: true # 发现高危漏洞时让 CI 失败
部署策略
蓝绿部署(Blue-Green Deployment)
同时维护两套完全相同的生产环境(蓝/绿),每次更新切换流量到新版本,出问题立即切回旧版。
蓝绿部署流程:
当前状态(蓝色环境 v1.0 接收100%流量):
负载均衡器 → [蓝色 v1.0 ✅] | [绿色 v1.0 空闲]
部署新版本到绿色环境:
负载均衡器 → [蓝色 v1.0 ✅] | [绿色 v2.0 测试]
切换流量到绿色(瞬间):
负载均衡器 → [蓝色 v1.0 保留] | [绿色 v2.0 ✅]
如果出问题,立即切回蓝色:
负载均衡器 → [蓝色 v1.0 ✅] | [绿色 v2.0 回滚]
滚动更新(Rolling Update)
逐步替换服务实例,新旧版本短暂共存,不中断服务:
初始:[v1.0] [v1.0] [v1.0] [v1.0]
步骤1:[v2.0] [v1.0] [v1.0] [v1.0] (等待 v2.0 健康)
步骤2:[v2.0] [v2.0] [v1.0] [v1.0]
步骤3:[v2.0] [v2.0] [v2.0] [v1.0]
完成:[v2.0] [v2.0] [v2.0] [v2.0]
# 使用 Docker Compose 模拟滚动更新
docker compose pull api # 拉取新镜像
docker compose up -d --no-deps api # 只更新 api 服务
生产运行容器的注意事项
日志:写到 stdout/stderr
容器内的应用应将日志写到标准输出(stdout)和标准错误(stderr),而非文件。Docker 会收集这些输出并通过日志驱动处理:
# /etc/docker/daemon.json 配置日志驱动
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
# 其他日志驱动:
# fluentd — 发送到 Fluentd 日志聚合
# awslogs — 发送到 AWS CloudWatch
# gelf — 发送到 Graylog
# syslog — 发送到系统 syslog
信号处理:PID 1 问题
Docker stop 发送 SIGTERM 给容器内的 PID 1 进程。如果应用不是 PID 1(例如通过 shell 启动),信号可能无法传递,导致强制 SIGKILL。
# ❌ Shell 形式:sh 成为 PID 1,node 无法收到 SIGTERM
CMD node server.js
# ✅ Exec 形式:node 直接成为 PID 1
CMD ["node", "server.js"]
# ✅ 使用 tini 作为 init 进程(处理孤儿进程)
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]
健康检查与重启
# Dockerfile 中定义健康检查(第3章已介绍)
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# Compose 中配置自动重启
services:
api:
restart: unless-stopped
Kubernetes 简介
当你的应用需要跨多台机器、自动扩缩容、高可用部署时,Docker Compose 就不够用了。Kubernetes(K8s)是容器编排领域的事实标准。
Docker Compose vs Kubernetes
| 能力 | Docker Compose | Kubernetes |
|---|---|---|
| 运行节点 | 单台机器 | 多台机器集群 |
| 自动扩缩容 | 手动 --scale | 自动 HPA(水平 Pod 自动扩缩) |
| 自愈能力 | restart 策略 | 自动替换异常 Pod |
| 滚动更新 | 手动 | 内置,可配置策略 |
| 服务发现 | 容器名 DNS | Service + CoreDNS |
| 配置管理 | env_file | ConfigMap + Secret |
| 学习曲线 | 低 | 高 |
| 适用场景 | 开发、小型单机部署 | 生产、微服务、大规模 |
Kubernetes 核心概念速览
- Pod K8s 最小部署单元,包含一个或多个容器,共享网络和存储。类似于 Docker Compose 中的 service 实例。
- Deployment 管理 Pod 的期望状态(副本数、镜像版本),负责滚动更新和回滚。类似 Compose 的 service 定义。
- Service 为一组 Pod 提供稳定的网络访问入口,负责负载均衡。Pod 会变化,但 Service 的 DNS 名称不变。
- Namespace K8s 资源的逻辑隔离单元,用于区分不同环境(dev/staging/prod)或不同团队。
- ConfigMap / Secret 分别存储非敏感配置和敏感配置(密码、Token),注入到 Pod 作为环境变量或文件。
将 Docker Compose 转换为 K8s
# 使用 Kompose 工具自动转换
brew install kompose
# 将 compose.yml 转换为 K8s YAML 文件
kompose convert -f compose.yml
# 部署到 K8s
kubectl apply -f .
学习路径建议 — 先用 Docker Compose 掌握多容器应用的概念(服务依赖、网络、卷),再进阶 Kubernetes。K8s 的绝大多数概念与 Compose 类似,只是功能更强大、配置更复杂。推荐用 minikube 或 k3d 在本机搭建 K8s 练习环境。
课程总结
恭喜你完成了全部 10 章的学习!以下是你已掌握的完整知识体系:
第1章:容器化概念、Namespace/Cgroup、Docker 架构
第2章:安装 Docker、镜像命令、容器生命周期
第3章:Dockerfile 指令、分层缓存、.dockerignore
第4-5章:多阶段构建、镜像优化、Docker 网络
第6-7章:数据卷持久化、Docker Compose 编排
第8-10章:镜像安全、镜像仓库、CI/CD 集成