第十章

CI/CD 容器化交付:提交代码自动上线

第十层 · 流水线/自动部署 提交代码自动打包上线

一、手动发布的代价:一次"小改小上线"要 40 分钟

小陈向老周演示一次"普通发布":

云间书店的"手动发布"流程:
  ① 开发改代码            → 本地测试
  ② 手动 docker build     → 构建镜像(几分钟)
  ③ 手动 docker push      → 推到 Harbor(几分钟)
  ④ SSH 登录生产服务器     → 敲 kubectl set image(几分钟)
  ⑤ 盯着滚动更新          → 直到全部 Pod 替换完
  ⑥ 手动验证              → curl 健康检查

一次发布 ≈ 40 分钟,全是手工活,而且:
  - 人容易忘步骤(少 push 一次?)
  - 人容易敲错命令(镜像版本号手滑?)
  - 没人记录"这次发的是什么"
  - 半夜发布?睡意朦胧更容易错

"40 分钟不长,但每周发 3 次,一年下来就是 100 小时的手工活,还带着出错风险。"老周说,"容器时代的答案:CI/CD——让流水线替人干这些活。"


二、什么是 CI/CD:从提交到上线的"自动流水线"

老周画了一条流水线:

CI/CD 流水线(Pipeline):
  ┌──────┐   ┌──────┐   ┌──────┐   ┌──────┐   ┌──────┐
  │ 提交   │ → │ 自动  │ → │ 自动  │ → │ 自动  │ → │ 自动  │
  │ 代码   │   │ 测试  │   │ 构建  │   │ 推送  │   │ 部署  │
  └──────┘   └──────┘   └──────┘   └──────┘   └──────┘
   git push    pytest     docker     docker    kubectl
               (单元测试)  build      push       apply

  CI(持续集成 Continuous Integration):
    每次提交代码 → 自动测试 + 自动构建镜像
    (代码提交即验证,坏代码当场报警)

  CD(持续交付/部署 Continuous Delivery/Deployment):
    构建好的镜像 → 自动推到仓库 → 自动部署到环境
    (发布从"手动操作"变成"流水线自动跑")

"CI/CD 的意义:把'人肉发布'变成'流水线发布'——提交代码之后,剩下的事机器全包了。 人只负责写代码和看结果。"


三、GitLab CI 实战:云间书店的第一条流水线

老周选用了 GitLab CI(和云间书店用的 Git 仓库配套):

# .gitlab-ci.yml —— 云间书店 API 服务的流水线
stages:          # 定义阶段(按顺序执行)
  - test         # 1. 测试
  - build        # 2. 构建镜像
  - deploy       # 3. 部署

# 阶段1:测试
test:
  stage: test
  image: python:3.11-slim
  script:
    - pip install -r requirements.txt
    - pytest tests/ -q          # 跑单元测试

# 阶段2:构建并推送镜像
build:
  stage: build
  image: docker:24
  services:
    - docker:dind
  script:
    - docker build -t harbor.yunjian.com/library/api:$CI_COMMIT_TAG .
    - docker login harbor.yunjian.com -u $REGISTRY_USER -p $REGISTRY_PASS
    - docker push harbor.yunjian.com/library/api:$CI_COMMIT_TAG

# 阶段3:部署到 K8s
deploy:
  stage: deploy
  image: bitnami/kubectl
  script:
    - kubectl set image deploy/api-deploy api=harbor.yunjian.com/library/api:$CI_COMMIT_TAG
  environment: production
  only:
    - tags          # 只有打 tag(发版)才部署生产
流水线怎么跑:
  开发打 tag(如 v1.4.0)→ GitLab 自动触发流水线
  → 测试阶段:跑全部单元测试(挂了?流水线红,不部署)
  → 构建阶段:build 镜像 + push 到 Harbor
  → 部署阶段:kubectl 滚动更新生产
  → 全部绿:上线完成!开发者只做了一件事:打 tag

安全(凭据管理):
  $REGISTRY_USER / $REGISTRY_PASS 存在 GitLab 的 CI 变量里
  → 不写死在代码里(还记得第七章 .env 的教训吗)

"注意 only: tags——生产部署只在'打 tag'时触发。 这就是版本管理和自动化的结合:发版 = 打个 tag,其余全自动。"


四、多环境流水线:测试→预发布→生产

"光有生产流水线不够,要'分环境'部署。"老周画:

多环境流水线(环境即关卡):
  提交代码(feature 分支)
    │
    ▼
  开发环境(自动部署,天天变)      ← 开发者自测
    │ 合并到 develop 分支
    ▼
  测试环境(自动部署)             ← 测试同学验收
    │ 打 tag v1.4.0
    ▼
  预发布环境(自动部署,跑冒烟测试) ← 上线前最后把关
    │ 人工确认
    ▼
  生产环境(自动部署,滚动更新)    ← 正式上线
环境管理原则:
  每个环境有自己的 K8s Namespace(命名空间):
    dev / test / staging / prod
  配置用 ConfigMap/Secret 区分环境(不同数据库地址等)
  生产环境:人工确认这一步不能省(guard 保护)
  好处:代码改动层层验证,坏代码到不了生产

"多环境 = 多道关卡:代码每通过一关,离用户近一步,出错风险降一截。 生产发布前那一脚'人工确认',是留给人的最后一道闸门——机器跑得再快,也要有人踩刹车。"


五、容器化 CI/CD 的三大收益

老周总结容器化交付带来的改变:

① 快:发布从 40 分钟 → 10 分钟(全程自动)
      频率从每周 3 次 → 每天数次(想发就发)
② 稳:每次发布流程一模一样(机器不会手滑)
      坏代码在测试阶段就被拦住(不会带病上线)
③ 可回溯:每次发布都有记录(谁、什么版本、什么时候)
      回滚 = 一句话(kubectl rollout undo)

云间书店发布方式进化:
  阶段1(VMware 季):人肉部署,一次 2 小时
  阶段2(手动容器):docker 命令部署,40 分钟
  阶段3(CI/CD)   :打 tag 全自动,10 分钟
  → 发布终于成了"日常小事"而不是"大工程"

"容器 + CI/CD 是绝配:镜像让'构建产物'标准化(走到哪都一样),流水线让'发布过程'自动化(不用人盯着)。 这就是云原生交付的核心。"


六、章末:老周的第十层总结

第十层:CI/CD 容器化交付
├── CI(持续集成):提交→自动测试→自动构建镜像
├── CD(持续交付):镜像→自动推送→自动部署
├── 流水线:test → build → deploy(GitLab CI 等)
├── 凭据管理:密码存 CI 变量,不写死在代码
├── 多环境:dev → test → staging → prod(层层把关)
└── 收益:发布 40 分钟→10 分钟,稳定、可回溯、可回滚

"小陈,你的流水线跑起来了:代码提交 → 自动测试 → 自动构建 → 自动部署到 K8s。这套东西,就是业界常说的'云原生'的骨架。"

"但是——"老周话锋一转,"容器和自动化的世界跑得越快,安全问题就越致命。一个镜像漏洞,可能顺着流水线直接进生产;一个配置错误,可能把数据库端口暴露到公网。容器时代的安全,比传统时代更需要'主动防护'。 下一章,我们讲容器安全的实战,以及容器技术未来的方向——云原生生态。"

✌ 语言