← 返回笔记列表

起因

个人项目原来的发布方式很粗暴:拉代码、装依赖、重启服务。 问题是重启那几秒钟服务是不可用的,如果刚好在用,就是一次报错。 更麻烦的是回滚——发现新版本有问题时,只能再走一遍完整流程。

思路

蓝绿发布的核心不复杂:同时存在两份服务实例,流量只指向其中一份。 发布时更新"空闲的那份",健康检查通过后再把流量切过去。

# /etc/nginx/conf.d/upstream-active.conf(由发布脚本改写)
upstream app_backend {
    server 127.0.0.1:8001;   # 当前生效:blue
}

发布脚本要卡住的几个点

① 先健康检查,再切流量

新实例起来 ≠ 能用。必须实际请求一次健康检查接口,拿到预期响应才算就绪。 我的脚本会轮询若干次,超时就直接放弃本次发布,老实例继续服务。

for i in $(seq 1 30); do
  if curl -fsS "http://127.0.0.1:${NEW_PORT}/health" >/dev/null; then
    echo "new instance ready"; break
  fi
  sleep 1
  [ "$i" = "30" ] && { echo "健康检查超时,放弃发布"; exit 1; }
done

② reload 前必须 nginx -t

配置写坏了直接 reload,等于自己把站点弄挂。校验不过就退出,不动线上。

③ 数据库迁移单独处理

这是最容易翻车的地方。两份实例可能同时在线, 所以迁移必须是向后兼容的:先加字段、后用字段,删字段留到下一次发布。

④ 保留旧实例一段时间

切流量后不要马上把旧实例杀掉。留着它,出问题时改回 upstream 就是秒级回滚。

效果

改完之后,发布过程外部感知不到中断,回滚从"重跑一遍部署"变成"改一行 + reload"。 单机也能吃到这套模式的好处,成本只是多占一份内存。