代码一推自动上线:EKS + CodePipeline + Argo CD 搭建 GitOps 实战
K8s 应用部署还在手写 kubectl apply 脚本?配置漂移查不出来?回滚得翻半天 Git log?
亚马逊云科技官博最近发了一篇实战文章:在中国区 EKS 上用 Code 家族(CodeCommit + CodePipeline + CodeBuild)+ Argo CD 搭一套完整的 GitOps CI/CD。代码一推,镜像自动构建,K8s 应用自动更新,全程不用手动敲命令。
这篇从痛点出发,走一遍完整搭建流程。
传统 CI/CD 的痛
先说为什么要 GitOps。传统 K8s 部署流程这几个问题你一定遇过:
- 手动脚本,出错难查:deploy.sh 写了一堆 kubectl 命令,哪天参数写错了,排查半天
- 配置漂移:有人直接在集群里改了配置,Git 里的和实际跑的不一样,出问题了才发现
- 回滚困难:想回到上个版本,得找到上次的镜像 tag、对应的 YAML 文件,手动重新 apply
- 权限混乱:谁都能 kubectl 操作集群,改了什么没有审计记录
GitOps 的解法:Git 仓库是唯一真相来源。所有变更走 Git,Argo CD 自动同步到集群。
方案架构
scss
开发者 → CodeCommit(代码仓库)
↓ (代码推送触发)
CodePipeline(流水线编排)
↓
CodeBuild(构建镜像) → ECR(镜像仓库)
↓ (更新 manifest 仓库镜像版本)
CodeCommit(清单仓库)
↓ (Argo CD 监控变更)
Argo CD → EKS(自动部署/更新)
两个 Git 仓库分开管:
- 代码仓库(cicd-test-app):业务代码 + Dockerfile + buildspec.yml
- 清单仓库(cicd-test-manifests):K8s deployment.yaml
核心组件
| 组件 | 作用 |
|---|---|
| CodeCommit | 托管 Git 仓库,代码变更的入口 |
| CodePipeline | 流水线编排,串联 CI 各阶段 |
| CodeBuild | 构建容器镜像,推送到 ECR |
| ECR | 私有镜像仓库 |
| Argo CD | GitOps CD 工具,监控清单仓库并同步到集群 |
| Amazon EKS | 托管 K8s 集群 |
搭建步骤
1. 创建 EKS 集群
bash
eksctl create cluster \
--name gitops-demo \
--region cn-north-1 \
--nodegroup-name workers \
--node-type t3.medium \
--nodes 2
2. 创建两个 CodeCommit 仓库
bash
# 应用代码仓库
aws codecommit create-repository \
--repository-name cicd-test-app
# K8s 清单仓库
aws codecommit create-repository \
--repository-name cicd-test-manifests
3. 准备应用代码
示例用 Go 写一个简单 HTTP 服务:
go
package main
import (
"fmt"
"log"
"net/http"
"os"
)
const Version = "v1.0.0"
func handler(w http.ResponseWriter, r *http.Request) {
hostname, _ := os.Hostname()
fmt.Fprintf(w, "Hello from EKS! Version: %s | Host: %s\n",
Version, hostname)
}
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "OK")
})
log.Printf("Starting on :8080, version %s", Version)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Dockerfile(多阶段构建,最终镜像很小):
dockerfile
FROM public.ecr.aws/docker/library/golang:1.22-alpine AS builder
WORKDIR /app
COPY main.go .
RUN go build -o server main.go
FROM public.ecr.aws/docker/library/alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/server /root/
EXPOSE 8080
CMD ["/root/server"]
4. 配置 CodeBuild(buildspec.yml)
yaml
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to ECR...
- ECR_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com.cn
- aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URI
- VERSION=$(grep -oP 'const Version = "\K[^"]+' main.go)
build:
commands:
- docker build -t $IMAGE_REPO_NAME:$VERSION .
- docker tag $IMAGE_REPO_NAME:$VERSION $ECR_URI/$IMAGE_REPO_NAME:$VERSION
post_build:
commands:
- docker push $ECR_URI/$IMAGE_REPO_NAME:$VERSION
- echo Build completed, image tag $VERSION
5. 创建 CodePipeline
在控制台创建 Pipeline:
- Source:关联 CodeCommit 的 cicd-test-app 仓库
- Build:选择 CodeBuild 项目
- 触发条件:代码推送到 main 分支自动触发
6. 准备 K8s 清单(deployment.yaml)
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cicd-demo
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: cicd-demo
template:
metadata:
labels:
app: cicd-demo
spec:
containers:
- name: app
image: <ACCOUNT_ID>.dkr.ecr.cn-north-1.amazonaws.com.cn/cicd-test-app:v1.0.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: cicd-demo-svc
spec:
type: LoadBalancer
selector:
app: cicd-demo
ports:
- port: 80
targetPort: 8080
7. 部署 Argo CD
bash
# 安装 Argo CD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 获取初始密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# 暴露 UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
8. 配置 Argo CD 应用
bash
argocd app create cicd-demo \
--repo https://git-codecommit.cn-north-1.amazonaws.com.cn/v1/repos/cicd-test-manifests \
--path . \
--dest-server https://kubernetes.default.svc \
--dest-namespace default \
--sync-policy automated \
--auto-prune \
--self-heal
关键参数:
--sync-policy automated:检测到 Git 变更自动同步--auto-prune:Git 里删了的资源,集群里也自动删--self-heal:有人手动改了集群配置,自动恢复到 Git 定义的状态
实际工作流程
应用发新版本:
- 改 main.go 里的 Version = "v2.0.0"
git push到 CodeCommit- CodePipeline 自动触发 → CodeBuild 构建 v2.0.0 镜像 → 推送到 ECR
- 更新清单仓库的 deployment.yaml 里的镜像 tag
- Argo CD 检测到清单变更 → 自动滚动更新 EKS 里的 Pod
回滚也简单:git revert 清单仓库到上个 commit,Argo CD 自动同步回旧版本。
这套方案好在哪
- 全自动化:代码推送到应用上线,分钟级完成,不用手动操作
- 配置不漂移 :
--self-heal确保集群状态永远和 Git 一致 - 回滚秒级:Git revert 一下就行,不用找旧镜像旧配置
- 审计完整:谁改了什么,Git log 里全有
- 权限收敛:开发者只需要 Git 权限,不需要直接访问 K8s 集群
踩坑提醒
- 中国区 ECR 域名 :是
.amazonaws.com.cn,不是.amazonaws.com - IRSA 权限:Argo CD 访问 CodeCommit 需要配 IRSA(IAM Roles for Service Accounts),别用明文密码
- 镜像版本更新:CodeBuild 构建完镜像后,还需要更新清单仓库的 tag。可以在 buildspec 里加个 git push 步骤,或者用 Argo CD Image Updater 自动检测新镜像
- Argo CD 同步频率:默认 3 分钟检查一次 Git 变更,想更快可以配 webhook
亚马逊云科技官博原文:aws.amazon.com/cn/blogs/ch... Amazon EKS:aws.amazon.com/cn/eks/ Argo CD:argo-cd.readthedocs.io/ CodePipeline:aws.amazon.com/cn/codepipe...