LabHub
学习 学习路径 课程

CI/CD 流水线

蓝绿切换与金丝雀分析

在 LabHub 中继续学习

本实验在真正的 VM 中运行

这台机器不是 Pod,而是 KubeVirt 启动的虚拟机。它拥有独立运行的 Linux 内核, systemd 会真正管理服务,docker 也不是模拟品,而是真正的 Docker 引擎。 通过 docker run 启动的容器会成为实际进程,docker execdocker logs 也都能按原样工作。

过去,本实验运行在 Pod 内。由于该环境移除了全部内核权限, 无法执行启动容器的步骤,因此只能学习手动解开镜像归档的变通方法。 现在不再需要绕行。

有两点需要提前了解。

目标

使用两个容器搭建蓝绿环境,并用 shell 实现流量切换、健康检查、自动回滚、金丝雀比例分流和自动中止判定。

为什么这很重要

部署策略之间的差异,归根结底是回滚速度与流量控制精度之间的权衡。蓝绿部署同时运行两个环境,资源消耗达到 Pod 的两倍,但一旦发现问题,可以立即将全部流量切回。金丝雀部署能够以 1% 为单位精确控制暴露比例,但回滚需要逐步进行。因此,大多数服务使用金丝雀部署,而支付或身份验证这类单次错误也会造成高昂成本的服务则采用蓝绿部署。本实验用文件中的一行表示当前活动目标。由谁在何时修改这一行、修改后检查什么,以及检查失败时如何恢复,就是部署自动化的全部内容。

步骤

  1. 启动响应正文包含 version=blue、名称为 ci3-blue 的容器,并发布到 127.0.0.1:8091。访问 curl http://127.0.0.1:8091/ 时应看到该字符串。
  2. 以相同方式将 ci3-green 启动在 127.0.0.1:8092,但正文设为 version=green。此时 ci3-blue 必须继续保持 running。
  3. 创建 /root/ci3/switch.sh <blue|green>。将活动目标名称写入 /root/ci3/active;如果设置了 ACTIVE_FILE 环境变量,则写入该路径。如果输入值不是 blue/green,不要写入任何内容,并以非 0 状态码退出。完成此步骤时,/root/ci3/active 的内容必须是 green
  4. 创建 /root/ci3/health.sh <URL>。目标正常响应时退出码为 0;没有服务或请求失败时返回非 0 状态码。评分会检查 8091、8092,以及没有服务的 8099。
  5. 创建 /root/ci3/deploy.sh <대상>。先记住当前活动值,切换到目标后,再通过目标端口执行健康检查。失败时,将活动值恢复为之前的值并以非 0 状态码退出。成功时,活动值保持为目标,退出码为 0。端口必须可以通过环境变量 PORT_BLUE(默认 8091)、PORT_GREEN(默认 8092)覆盖,并且也必须遵循 ACTIVE_FILE
  6. 创建 /root/ci3/canary.sh <퍼센트>。发送 100 个请求,统计各自去向,并输出 blue=<수> green=<수>。两个数字之和必须始终为 100;参数为 0 时必须输出 blue=100 green=0,参数为 100 时必须输出 blue=0 green=100
  7. 创建 /root/ci3/analyze.sh <지표파일> <임계퍼센트>。指标文件中各有一行 total=1000errors=10。错误率为 errors * 100 / total;不高于阈值时退出码为 0,超过阈值时输出实际错误率并返回非 0 状态码。total=0 表示没有样本,不得放行,必须判定为失败。
  8. 创建 /root/ci3/deploy-report.json。字段包括 strategyblue-greencanary)、active(必须与当前 /root/ci3/active 内容相同)、previous(必须与 active 不同)、rollback_usederror_rate_pctabort_threshold_pctrollback_used 应根据本次部署是否实际发生回滚,写成 JSON 布尔值(truefalse)——不能写成字符串 "true"error_rate_pct 必须不高于 abort_threshold_pct

参考

启动 blue 环境

启动响应正文包含 version=blue、名称为 ci3-blue 的容器,并发布到 127.0.0.1:8091。访问 curl http://127.0.0.1:8091/ 时应看到该字符串。

容器名称必须准确写成 ci3-blue,发布端口为 127.0.0.1:8091。无法绑定 1024 以下的端口。响应正文必须包含 version=blue,最简单的方法是创建 index.html 并进行挂载。

并行启动 green 环境

以相同方式将 ci3-green 启动在 127.0.0.1:8092,但正文设为 version=green。此时 ci3-blue 必须继续保持 running。

ci3-green 启动在 8092,正文为 version=green。此时不能关闭 blue。两个环境必须同时存活,才能实现无中断切换。

活动目标切换脚本

创建 /root/ci3/switch.sh <blue|green>。将活动目标名称写入 /root/ci3/active;如果设置了 ACTIVE_FILE 环境变量,则写入该路径。如果输入值不是 blue/green,不要写入任何内容,并以非 0 状态码退出。完成此步骤时,/root/ci3/active 的内容必须是 green

格式为 switch.sh <blue|green>,默认记录文件是 /root/ci3/active。如果存在 ACTIVE_FILE 环境变量,必须使用其路径(评分会通过临时路径验证)。遇到未知值时不要写入任何内容,并返回失败。一个拼写错误就可能把流量送到不存在的目标。

健康检查

创建 /root/ci3/health.sh <URL>。目标正常响应时退出码为 0;没有服务或请求失败时返回非 0 状态码。评分会检查 8091、8092,以及没有服务的 8099。

health.sh <URL> 在服务存活时返回 0,否则返回非 0 状态码。请像 curl -fsS -m 3 这样调用,使失败时产生错误并设置超时。永远通过的健康检查等同于没有健康检查。

失败时自动回滚

创建 /root/ci3/deploy.sh <대상>。先记住当前活动值,切换到目标后,再通过目标端口执行健康检查。失败时,将活动值恢复为之前的值并以非 0 状态码退出。成功时,活动值保持为目标,退出码为 0。端口必须可以通过环境变量 PORT_BLUE(默认 8091)、PORT_GREEN(默认 8092)覆盖,并且也必须遵循 ACTIVE_FILE

deploy.sh <대상> 必须先记住当前活动值,才能进行恢复。端口必须可通过 PORT_BLUE(默认 8091)、PORT_GREEN(默认 8092)覆盖,并且必须遵循 ACTIVE_FILE。健康检查失败时,应恢复之前的值并返回非 0 退出码。

按比例分流

创建 /root/ci3/canary.sh <퍼센트>。发送 100 个请求,统计各自去向,并输出 blue=<수> green=<수>。两个数字之和必须始终为 100;参数为 0 时必须输出 blue=100 green=0,参数为 100 时必须输出 blue=0 green=100

canary.sh <퍼센트> 会发送 100 个请求并输出 blue=<수> green=<수>。总和必须始终为 100,因此不能直接忽略请求失败。基于序号的分配方式比随机数更容易复现。

自动中止判定

创建 /root/ci3/analyze.sh <지표파일> <임계퍼센트>。指标文件中各有一行 total=1000errors=10。错误率为 errors * 100 / total;不高于阈值时退出码为 0,超过阈值时输出实际错误率并返回非 0 状态码。total=0 表示没有样本,不得放行,必须判定为失败。

格式为 analyze.sh <지표파일> <임계퍼센트>,指标文件包含 total=1000errors=10 两行。等于阈值时通过。total 为 0 时没有样本,无法作出判断,因此不能通过。中止时请输出实际错误率。

部署报告

创建 /root/ci3/deploy-report.json。字段包括 strategyblue-greencanary)、active(必须与当前 /root/ci3/active 内容相同)、previous(必须与 active 不同)、rollback_usederror_rate_pctabort_threshold_pctrollback_used 应根据本次部署是否实际发生回滚,写成 JSON 布尔值(truefalse)——不能写成字符串 "true"error_rate_pct 必须不高于 abort_threshold_pct

/root/ci3/deploy-report.json 中的 active 必须与 /root/ci3/active 内容相同,previous 必须不同。rollback_used 应按本次部署是否实际发生回滚填写为真或假——必须是不带引号的 JSON 布尔值。error_rate_pct 必须不高于 abort_threshold_pct。