自动化 CD:GitHub Actions → ECS k3s 自动部署
Problem Statement
当前部署流程存在以下痛点:
手动操作繁琐 :每次 GitHub Actions 构建并推送镜像到私有仓库后,需要手动 SSH 到 ECS 执行 k3s kubectl apply 和 rollout restart 才能拉取新镜像并重新部署
易遗漏步骤 :容易忘记在 ECS 上执行部署操作,导致代码变更没有及时生效
无自动化反馈 :镜像推送成功后,不知道部署是否成功,需要额外登录 ECS 验证
ECS 位于私有网络 :ECS 可以访问外网,但外网无法直接 SSH 到 ECS(NAT 环境),排除 GitHub Actions 直接 SSH 的方案
用户视角的痛点 :
"每次改完代码 push main,等 CI 构建完,还得记得去 ECS 上手动 pull 镜像并重启服务,既麻烦又容易忘。要是 push 后自动部署就好了。"
Solution
采用 **GitHub Self-hosted Runner(Pull 模式)**实现自动化部署:
在 ECS 上安装 GitHub Actions Runner agent :Runner 主动轮询 GitHub(出站连接,天然支持 NAT),无需开放任何入站端口
GitHub Actions 部署 job 运行在 self-hosted runner 上 :构建镜像成功后,触发 deploy job,该 job 在 ECS 本地执行部署命令
完整自动化流程 :
push main → GitHub Actions build job → 构建并推送 3 个镜像
deploy job (runs-on: self-hosted) → ECS 上的 runner 执行 deploy.sh
deploy.sh → 渲染 kustomize → kubectl apply → rollout restart
处理配置变更 :
清单级配置(env、资源):修改 YAML 提交即可,kubectl apply 幂等更新
运行时密钥(API key):通过 GitHub Secrets 同步到 k8s Secret
用户视角的收益 :
"现在 push main 后什么都不用管,GitHub Actions 自动构建、自动部署到 ECS,直接去 Portal 验证新功能就行。"
User Stories
核心功能
作为开发者,我希望 push main 后自动部署到 ECS,这样我就不需要手动 SSH 去拉镜像和重启服务
作为开发者,我希望配置变更(新增 env、修改资源)也能自动生效,这样部署流程完全自动化
作为开发者,我希望运行时密钥变更不需要改代码,这样敏感信息不会进入代码库
作为运维人员,我希望部署失败能及时感知,这样我可以快速排查问题
作为运维人员,我希望有回滚机制,这样部署出问题时可以快速恢复
约束场景
作为部署方案,必须支持 ECS 位于私有网络(NAT 环境),这样不需要开放入站端口
作为部署方案,必须与现有架构兼容(k3s 单节点、无需 git/kustomize),这样不需要额外基础设施
作为部署方案,必须支持镜像仓库认证(私有仓库),这样 k3s 能拉取镜像
操作流程
作为初次使用者,我希望有清晰的初始化步骤(安装 runner),这样我可以一次性配置好自动化
作为运维人员,我希望可以监控 runner 健康状态,这样 runner 挂掉时能及时发现
作为运维人员,我希望可以查看部署日志,这样排查问题时能看到完整执行过程
扩展场景
作为架构设计者,我希望方案支持多服务器扩展,这样以后加新服务器时不需要重新设计方案
作为架构设计者,我希望方案支持多环境(dev/staging/prod),这样可以在不同环境使用不同配置
作为安全考虑,我希望 runner 权限可受控,这样不会因为 runner 攻击影响整个系统
作为成本考虑,我希望方案低维护成本,这样不需要频繁运维 runner
Implementation Decisions
1. 使用 GitHub Self-hosted Runner 而非其他方案
决策 :采用 GitHub Self-hosted Runner(Pull 模式)
考虑过的替代方案 :
❌ GitHub Actions SSH Push:需要外网能连到 ECS,不适用 NAT 环境
❌ FluxCD:引入额外控制器,需要维护 manifest repo,对于单节点 ECS 过度设计
❌ Watchtower:只能处理镜像更新,无法处理清单配置变更
选择理由 :
✅ 天然支持 NAT(runner 主动轮询 GitHub)
✅ 无需额外基础设施(与现有 k3s 架构兼容)
✅ 完整处理镜像 + 配置变更
✅ GitHub 官方支持,社区成熟
2. Runner 安装位置和配置
决策 :Runner 安装在 /opt/actions-runner,以 systemd 服务运行
技术细节 :
Runner 下载:curl -o actions-runner-linux-x64.tar.gz -L https://github.com/actions/runner/releases/download/...
注册:./config.sh --url https://github.com/<org>/<repo> --token <REGISTRATION_TOKEN> --name ecs-runner --labels ecs,production
服务安装:./svc.sh install && ./svc.sh start
自动启动:systemd 服务,ECS 重启后自动拉起
标签设计 :
ecs:标识 runner 位于 ECS
production:标识生产环境(未来扩展 staging 环境)
3. GitHub Actions 工作流结构
决策 :在现有 deploy.yml 添加 deploy job
jobs :
build :
# ... 现有构建推送步骤 ...
deploy :
needs : build
runs-on : [self-hosted, ecs] # 指定跑在 ECS runner 上
steps :
- uses : actions/checkout@v4
- name : Deploy to k3s
run : bash scripts/deploy.sh
幂等性保证 :
kubectl apply:幂等更新,重复执行无副作用
rollout restart:触发滚动更新,Pod 逐个重启
rollout status:等待 Pod 就绪后才返回
4. 配置变更处理策略
清单级配置 (env var、k8s 资源、副本数等):
直接修改 infra/ 下 YAML 文件,提交 main 后自动 apply
运行时密钥 (upstream-api-key、jwt-secret 等):
GitHub Secrets 中维护(不进入代码库)
deploy job 在 apply 前同步到 k8s Secret
同步逻辑 :
- name : Sync runtime secrets
run : |
JWT=$(k3s kubectl get secret talos-portal-secrets -n system -o jsonpath='{.data.jwt-secret}' | base64 -d)
k3s kubectl create secret generic talos-portal-secrets \
--from-literal=jwt-secret="$JWT" \
--from-literal=upstream-api-key="$UPSTREAM_API_KEY" \
--namespace system --dry-run=client -o yaml | k3s kubectl apply -f -
5. 镜像仓库认证
决策 :沿用 ecs-init.sh 中已配置的 /etc/rancher/k3s/registries.yaml
现状 :
ecs-init.sh 已创建 registry auth 配置
k3s 会自动使用该配置拉取私有镜像
无需额外操作 :runner 运行在同一 ECS 上,继承 k3s 配置
6. 安全加固
决策 :为 deploy job 配置 environment 保护
GitHub Actions Environment 配置 :
创建 production environment
设置 required reviewers(防止意外 push 直接部署)
deploy job 声明 environment: production
7. 多环境扩展设计
决策 :使用 runner labels 区分环境
标签命名约定 :
ecs,production:生产环境
ecs,staging:预发布环境
ecs,dev:开发环境
工作流配置 :
deploy :
strategy :
matrix :
environment : [production, staging]
runs-on : [self-hosted, ecs, ${{ matrix.environment }}]
8. 回滚机制
决策 :提供手动回滚脚本,不自动回滚
理由 :
k3s 集群已有 deployment revision 历史
手动回滚更可控(避免级联失败)
提供快捷脚本 npm run ecs:rollback
回滚命令 :
k3s kubectl rollout undo deploy/talos-portal -n system
Testing Decisions
测试原则
仅测试外部行为 :验证镜像更新后 Pod 是否重启并使用新镜像,不测试 runner 内部实现
端到端测试 :从 push main 到 Portal 验证新版本的完整流程
幂等性测试 :重复执行部署命令,确保无副作用
测试场景
镜像更新测试 :
修改 Portal 代码,push main
GitHub Actions 完成 build + deploy
SSH 到 ECS 验证 Pod 重启,镜像 tag 为 latest
访问 Portal 验证新功能生效
配置变更测试 :
修改 infra/base/portal.yaml 新增 env var
push main
验证 Pod 内新 env var 存在
密钥同步测试 :
更新 GitHub Secrets 中 UPSTREAM_API_KEY
重新触发 deploy job
验证 k8s Secret 更新
幂等性测试 :
连续触发 deploy job 3 次
验证每次都成功,Pod 不频繁重启
Runner 容错测试 :
停止 runner 服务
触发 GitHub Actions
验证 job 在队列等待(不是失败)
启动 runner,验证 job 开始执行
现有测试模式
参考 doc/k3d-image-update.md 中已有的镜像更新测试流程,适配到 k3s 环境。
Out of Scope
本次实现不包含以下功能:
自动健康检查和告警 :Runner 健康监控需要额外配置(如 Prometheus),本次不包含
自动回滚 :部署失败不自动回滚,依赖人工介入
蓝绿部署/金丝雀发布 :单节点 k3s 不支持这些高级发布策略
多服务器负载均衡 :当前只有单台 ECS,不涉及多服务器协调
CI/CD 流水线可视化 :依赖 GitHub Actions 界面,不额外提供 UI
部署审批流集成 :Environment 保护机制已足够,不集成额外审批系统
Further Notes
初始化检查清单
首次使用时需要执行:
SSH 到 ECS,下载并注册 GitHub Actions Runner
在 GitHub Repo → Settings → Actions → Runners 验证 runner 状态为 Idle
验证 runner 以有 kubectl 权限的用户运行
(可选)配置 GitHub Actions Environment 保护
推送测试改动验证完整流程
运维注意事项
Runner 证书轮换 :Runner 使用 self-signed 证书与 GitHub 通信,需定期更新(通常由 GitHub 自动处理)
Runner 版本升级 :GitHub 会在 runner 版本过期时提示,需手动升级(下载新版本 tar.gz 重新安装)
磁盘空间监控 :Runner 会缓存工作目录和日志,需定期清理防止磁盘满
网络中断处理 :Runner 使用长轮询,短暂网络中断会自动重连,无需人工干预
故障排查
Runner 离线 :检查 ECS 上 systemctl status actions-runner.* 服务状态
部署失败 :查看 GitHub Actions 日志,定位 kubectl apply 或 rollout restart 错误
镜像拉取失败 :检查 /etc/rancher/k3s/registries.yaml 配置,确认 registry 凭据有效
Pod 无法启动 :k3s kubectl describe pod 查看事件,定位问题
参考文档
自动化 CD:GitHub Actions → ECS k3s 自动部署
Problem Statement
当前部署流程存在以下痛点:
k3s kubectl apply和rollout restart才能拉取新镜像并重新部署用户视角的痛点:
Solution
采用 **GitHub Self-hosted Runner(Pull 模式)**实现自动化部署:
deployjob,该 job 在 ECS 本地执行部署命令buildjob → 构建并推送 3 个镜像deployjob (runs-on: self-hosted) → ECS 上的 runner 执行deploy.shdeploy.sh→ 渲染 kustomize →kubectl apply→rollout restartkubectl apply幂等更新用户视角的收益:
User Stories
核心功能
约束场景
操作流程
扩展场景
Implementation Decisions
1. 使用 GitHub Self-hosted Runner 而非其他方案
决策:采用 GitHub Self-hosted Runner(Pull 模式)
考虑过的替代方案:
选择理由:
2. Runner 安装位置和配置
决策:Runner 安装在
/opt/actions-runner,以 systemd 服务运行技术细节:
curl -o actions-runner-linux-x64.tar.gz -L https://github.com/actions/runner/releases/download/..../config.sh --url https://github.com/<org>/<repo> --token <REGISTRATION_TOKEN> --name ecs-runner --labels ecs,production./svc.sh install && ./svc.sh start标签设计:
ecs:标识 runner 位于 ECSproduction:标识生产环境(未来扩展 staging 环境)3. GitHub Actions 工作流结构
决策:在现有
deploy.yml添加deployjob幂等性保证:
kubectl apply:幂等更新,重复执行无副作用rollout restart:触发滚动更新,Pod 逐个重启rollout status:等待 Pod 就绪后才返回4. 配置变更处理策略
清单级配置(env var、k8s 资源、副本数等):
infra/下 YAML 文件,提交 main 后自动 apply运行时密钥(upstream-api-key、jwt-secret 等):
同步逻辑:
5. 镜像仓库认证
决策:沿用
ecs-init.sh中已配置的/etc/rancher/k3s/registries.yaml现状:
ecs-init.sh已创建 registry auth 配置无需额外操作:runner 运行在同一 ECS 上,继承 k3s 配置
6. 安全加固
决策:为 deploy job 配置 environment 保护
GitHub Actions Environment 配置:
productionenvironmentenvironment: production7. 多环境扩展设计
决策:使用 runner labels 区分环境
标签命名约定:
ecs,production:生产环境ecs,staging:预发布环境ecs,dev:开发环境工作流配置:
8. 回滚机制
决策:提供手动回滚脚本,不自动回滚
理由:
npm run ecs:rollback回滚命令:
Testing Decisions
测试原则
测试场景
镜像更新测试:
配置变更测试:
infra/base/portal.yaml新增 env var密钥同步测试:
幂等性测试:
Runner 容错测试:
现有测试模式
参考
doc/k3d-image-update.md中已有的镜像更新测试流程,适配到 k3s 环境。Out of Scope
本次实现不包含以下功能:
Further Notes
初始化检查清单
首次使用时需要执行:
运维注意事项
故障排查
systemctl status actions-runner.*服务状态kubectl apply或rollout restart错误/etc/rancher/k3s/registries.yaml配置,确认 registry 凭据有效k3s kubectl describe pod查看事件,定位问题参考文档
doc/k3d-image-update.md(镜像更新流程)