部署策略
这一课你将能做到
- 对比三种把产物送到环境的路径:SSH/rsync(Push)、Helm upgrade(Push)、GitOps 改 values(Pull)
- 读懂「CI 只推镜像 + 开 PR 改
image.tag」在本站 deploy/ 目录中的落点
- 按场景选出适合小站 VPS 与适合生产 K8s 的策略,并能口述蓝绿/滚动/金丝雀的差别
为什么要学
镜像进了 GHCR,集群或 VPS 不会自己知道「该跑新 tag」。部署策略回答的是:谁、凭什么权限、以什么真相来源,把新版本落到环境。
Push 式(CI 直接 SSH 或 helm upgrade)简单直接,但 CI 持有高权限凭证。GitOps 式让仓库里的 YAML 成为期望状态,集群内控制器来拉——CI 的权限被压缩到「推镜像 + 开 PR」,风险面小得多。
本课建立选型脑图;不要求你当场打通生产,但要求能画进本站的 deploy/charts 与 deploy/env/prod,并在面试里讲清蓝绿、滚动、金丝雀。
先建立图像
方式 A:SSH Push
CI 持有 SSH 私钥 → scp JAR/compose → 远端重启
方式 B:Helm Push
CI 持有 kubeconfig → helm upgrade --set image.tag=sha
方式 C:GitOps(生产推荐)
CI 推镜像 → CI/人开 PR 改 values 里的 image.tag
→ merge 后 Argo/Flux 发现 Git 变化 → 集群自行同步
人话:A/B 像快递员直接踹门放货(门钥匙在快递员口袋);C 像把「货架清单」改在公告栏,店员自己按清单补货——钥匙在店里。
| SSH | Helm upgrade | GitOps |
|---|
| 真相来源 | 服务器当前文件 | 集群当前 release | Git 中的 values |
| CI 权限 | SSH 钥匙 | kubeconfig 大权 | 主要写镜像仓 + 开 PR |
| 适合 | 单机/小站 | 能接受 Push 的集群 | 多环境、要审计 |
| 回滚 | 拷回旧 JAR | helm rollback | revert values 的 PR |
跟着做
步骤 1:摸清本站部署目录
在仓库浏览:
deploy/charts/backend/
deploy/env/dev/backend-values.yaml
deploy/env/prod/backend-values.yaml
打开 prod values,找到 image.repository / image.tag(字段名以实际文件为准)。笔记写:「改 tag = 声明新版本;谁来改、谁来应用,决定是 Push 还是 GitOps。」
步骤 2:读一遍 SSH 示例(了解即可)
jobs:
deploy-vps:
runs-on: ubuntu-latest
environment: production # 挂审批门闩
needs: [backend] # 先测过
steps:
- uses: actions/checkout@v4
# … 构建或 download-artifact …
- name: 拷贝 JAR 到服务器
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: backend/target/*.jar
strip_components: 2
target: /opt/codeforge/
- name: 重启服务
uses: appleboy/ssh-action@v1.2.2
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
systemctl restart codeforge
systemctl status codeforge --no-pager
应看到:secret 是 SSH 钥与主机信息,没有 kubeconfig。适合 systemd/Compose 单机模型。
步骤 3:读一遍 Helm Push 示例(对照风险)
- name: Helm 升级
run: |
# 需要事先配置好 kubeconfig secret(权限极大,慎用)
helm upgrade backend ./deploy/charts/backend \
-n codeforge \
-f deploy/env/prod/backend-values.yaml \
--set image.tag=${{ github.sha }}
笔记写:「CI 能 upgrade,就能对集群做很多事——密钥泄漏面大。」
步骤 4:画 GitOps 主路径
CI: docker build/push → ghcr.io/…/backend:<sha>
CI 或 bot: 开 PR,把 deploy/env/prod/backend-values.yaml
的 image.tag 改为 <sha>
人审 PR → merge
Argo CD: 侦测 Git 变化 → sync → 集群拉取新镜像
口头发一句:CI 造镜像;Git 记版本;集群拉版本。
步骤 5:本地验收 chart 能渲染
helm template backend ./deploy/charts/backend \
-f deploy/env/dev/backend-values.yaml
输出里应能定位镜像名与 tag。这保证「改 values」有意义,而不是改了个无效字段。
步骤 6:写选型表进笔记
为「个人 VPS 演示站」与「多副本生产」各选一行策略,并写一条理由(权限、审计、复杂度)。没有唯一正确答案;清楚权衡比背「必须 GitOps」更重要。教学默认:生产叙事走 GitOps,小站可 SSH。
讲清楚要点
- 因为部署是高风险写操作,所以策略首先关心凭证放哪、谁能触发——不是只关心命令炫不炫。
- 因为 Push 部署让 CI 持有门钥匙,所以密钥泄漏等于环境沦陷——Environment 审批只能降低频率,不能消灭风险。
- 因为 GitOps 把期望状态放进 Git,所以回滚常等于 revert values——与应用代码一样可 review、可追溯。
- 因为本站已有 charts 与 env values,所以 tag 更新的落点应在
deploy/env/…——避免旁路手改集群却不改 Git。
- 因为镜像与配置是两截,所以「推了镜像但没改 tag」集群不会变——这是 GitOps 初学者最常见的「我推了怎么没更新」。
- 因为小站与生产约束不同,所以允许 SSH 作为入门 CD,同时知道升级路径——技能可迁移。
你可能会懵的地方
-
「GitOps 还要不要 Actions?」
要。Actions 仍做 CI 与推镜像,可选做 bump PR;它不再直接 helm upgrade 生产。
-
「只有 Compose 没有 K8s 怎么办?」
SSH 更新 compose 文件里的 tag 再 docker compose up -d;或用「改 Git 中的 compose → 服务器定时 pull 同步」的弱 GitOps。
-
「Argo 一定会立刻同步吗?」
取决于自动 sync 策略与健康检查配置。排障顺序:看 Application 状态 → 看 Git 与集群 diff → 确认新镜像真的可拉(私有包要 imagePullSecrets)。
-
「kubeconfig 放 secret 方便吗?」
方便但危险,权限往往覆盖整个集群。能收窄 RBAC 或换 OIDC/短时凭证更好;教学上理解风险优先于图省事。
-
「蓝绿和金丝雀在 Actions 里能做吗?」
能,但 Actions 本身只负责「触发与脚本」,真正的流量切换靠 K8s/网关(如 Ingress 权重、Service selector 切换、Argo Rollouts)。Actions 是发起方,不是执行方。
错法对照
| 错法 | 问题 | 正解 |
|---|
| main 一绿就 SSH 无审批直推生产 | 事故难挡 | Environment reviewers 或 GitOps PR |
| 只推镜像不改 values | 环境不变 | 更新 image.tag 并触发同步 |
| CI 长期保存全能 kubeconfig | 泄漏面过大 | GitOps / 收窄 RBAC / OIDC |
| 手改集群与 Git 各玩各的 | 配置漂移 | Git 为唯一真相来源 |
卡点急救
- 推了镜像但环境没变化:九成是没更新
image.tag 或同步器没跑。查三处——values 里的 tag 是否真是新 sha;Argo/Flux 是否 sync 成功;新镜像是否可拉(私有包需要 imagePullSecrets)。记住「镜像 ≠ 部署」。
- SSH 部署连不上:查安全组是否放行 runner 出口 IP(托管 runner IP 不固定,建议用跳板或仅放行必要端口);确认私钥格式与指纹、服务器
authorized_keys 已加入公钥;先用 ssh -v 本地模拟同一凭据。
- 上线后要回滚:Push 模式重跑旧 tag 的部署 job 或
helm rollback;GitOps 直接 revert 那次 bump PR——这也是为什么 tag 要可追溯。演练一次「回滚」,才算真懂这条链路。
面试常问
-
蓝绿部署、滚动更新、金丝雀发布分别是什么?怎么选?
蓝绿:新旧两套完整环境,流量一键切换,回滚秒级,但资源翻倍;滚动:逐个替换副本,资源省,但新旧版本短暂共存,需兼容 schema;金丝雀:先放小比例流量到新版本,观察指标再逐步放量,风险最小但需要指标采集与网关支持。选型:小流量验证价值高的(用户敏感、变更大)用金丝雀;无状态服务与资源紧张用滚动;要求极短回滚窗口的用蓝绿。Actions 里通常负责触发,实际切换由 K8s/Argo Rollouts 执行。
-
GitOps 是什么?相比 CI 直推(Push)有什么优势?
GitOps 把期望状态声明在 Git,集群内控制器持续比对并收敛。优势:① 权限收敛——CI 不再持有集群大权,只需推镜像和开 PR;② 审计与回滚——每次部署是一个 merge commit,revert 即回滚;③ 漂移自愈——有人手改集群会被控制器拉回声明状态;④ 环境一致性——dev/prod 各自的 values 目录即环境清单。
-
你们的部署回滚流程怎么设计?
三层答:镜像层——tag 用 sha,任何历史版本都可重新引用;配置层——GitOps 下 revert bump PR(或 Helm rollback);数据层——迁移脚本必须向前兼容,使回滚应用版本时旧代码能读新 schema。核心是「回滚演练过」才叫有回滚,没演练过的只能叫回滚设想。
自测三问
- 用两句话对比 Push 部署与 GitOps。
- 本站表达「生产后端镜像版本」的文件通常在哪?改哪个字段?
- 为什么说「推了 GHCR 但集群没变」仍然可能发生?
小结一句话
生产优先 GitOps(镜像由 CI 造、版本由 Git 声明);小站可用 SSH,但要清楚钥匙在谁口袋。
延伸