CI/CD流水线架构选型与GitOps理念
传统CI/CD流水线中,部署阶段通常通过脚本直接操作目标环境(kubectl apply、helm install等),部署状态散落在各次执行记录中,难以审计和回滚。GitOps将Git仓库作为系统状态的唯一真实来源,部署过程变为”让Git中的声明状态与集群实际状态一致”。ArgoCD作为Kubernetes原生的GitOps持续交付工具,持续监控Git仓库与集群状态的差异并自动同步。
完整的GitOps流水线分为两个阶段:CI阶段(代码提交到镜像构建推送)由GitLab CI/CD负责,CD阶段(镜像部署到集群)由ArgoCD负责。两者通过镜像仓库(Harbor/ACR)解耦,CI只负责产出制品,CD只负责消费制品。
GitLab CI/CD流水线配置
GitLab CI/CD通过项目根目录的.gitlab-ci.yml文件定义流水线。以下配置实现代码检查、单元测试、镜像构建和推送的完整CI流程:
# .gitlab-ci.yml
stages:
- lint
- test
- build
- deploy-trigger
variables:
IMAGE_REGISTRY: "registry.cn-east-1.aliyuncs.com"
IMAGE_NAME: "myapp/api-server"
DOCKER_DRIVER: overlay2
# 代码检查
lint:
stage: lint
image: golangci/golangci-lint:v1.61
script:
- golangci-lint run --timeout 5m ./...
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# 单元测试
test:
stage: test
image: golang:1.23-alpine
services:
- name: redis:7-alpine
alias: redis-test
- name: mysql:8.0
alias: mysql-test
command: ["--default-authentication-plugin=mysql_native_password"]
variables:
REDIS_HOST: redis-test
MYSQL_HOST: mysql-test
MYSQL_ROOT_PASSWORD: testpass
MYSQL_DATABASE: app_test
script:
- go test -race -coverprofile=coverage.out -covermode=atomic ./...
- go tool cover -func=coverage.out | tail -1
coverage: '/coverage:\s+(\d+\.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.out
# 镜像构建与推送(仅main分支触发)
build-and-push:
stage: build
image: docker:24.0
services:
- docker:24.0-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $IMAGE_REGISTRY
- docker build -t $IMAGE_REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA .
- docker tag $IMAGE_REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA $IMAGE_REGISTRY/$IMAGE_NAME:latest
- docker push $IMAGE_REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
- docker push $IMAGE_REGISTRY/$IMAGE_NAME:latest
rules:
- if: $CI_COMMIT_BRANCH == "main"
# 触发ArgoCD同步(更新GitOps仓库中的镜像版本)
update-gitops:
stage: deploy-trigger
image: alpine:3.20
before_script:
- apk add --no-cache git curl jq
script:
- git clone https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.com/team/gitops-repo.git
- cd gitops-repo
- |
sed -i "s|image:.*|image: $IMAGE_REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA|" apps/api-server/deployment.yaml
- git config user.name "GitLab CI"
- git config user.email "ci@gitlab.com"
- git add apps/api-server/deployment.yaml
- git commit -m "Update api-server image to $CI_COMMIT_SHORT_SHA"
- git push origin main
rules:
- if: $CI_COMMIT_BRANCH == "main"
流水线的关键设计:rules字段控制Job执行条件,merge request阶段只运行lint和test,main分支推送时才触发build和deploy-trigger。update-gitops步骤将新镜像版本写入GitOps仓库,ArgoCD检测到变更后自动同步部署。
Dockerfile多阶段构建优化
镜像构建环节对最终镜像大小和构建速度有直接影响。多阶段构建将编译环境和运行环境分离,运行镜像只包含二进制文件和必要依赖:
# Dockerfile
# 阶段1:构建
FROM golang:1.23-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o api-server ./cmd/server
# 阶段2:运行
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /build/api-server /usr/local/bin/
COPY --from=builder /build/configs /app/configs
EXPOSE 8080
ENTRYPOINT ["api-server"]
-ldflags="-s -w"去除调试信息和符号表,二进制体积减少约30%。使用go mod download单独缓存依赖层,代码变更时不会重新下载依赖。
ArgoCD安装与Application配置
ArgoCD通过Helm安装在Kubernetes集群中:
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd -n argocd --create-namespace
# 获取初始密码
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
Application定义GitOps仓库与Kubernetes集群的同步关系。以下配置监控GitOps仓库的apps/api-server目录,自动同步到production命名空间:
# argocd-app-api-server.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-server
namespace: argocd
spec:
project: default
source:
repoURL: https://gitlab.com/team/gitops-repo.git
targetRevision: main
path: apps/api-server
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # 删除Git中已移除的资源
selfHeal: true # 自动修复手动修改导致的漂移
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
selfHeal: true是GitOps的核心约束:如果有人手动kubectl edit修改了集群中的资源,ArgoCD会自动将其恢复为Git仓库中声明的状态。这确保了集群状态始终与Git仓库一致。如果需要临时手动修改,需先将变更提交到Git仓库。
多环境部署与ApplicationSet
生产环境通常需要dev、staging、prod三个环境,手动为每个环境创建Application会导致配置重复。ApplicationSet通过模板化生成Application,一份配置管理多环境:
# applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: api-server-multi-env
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
branch: develop
namespace: dev
- env: staging
branch: release
namespace: staging
- env: prod
branch: main
namespace: production
template:
metadata:
name: 'api-server-{{env}}'
spec:
project: default
source:
repoURL: https://gitlab.com/team/gitops-repo.git
targetRevision: '{{branch}}'
path: 'apps/api-server/overlays/{{env}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
配合Kustomize的overlays目录结构,每个环境使用独立的配置覆盖(副本数、资源限制、环境变量等):
apps/api-server/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── patches.yaml
├── staging/
│ ├── kustomization.yaml
│ └── patches.yaml
└── prod/
├── kustomization.yaml
└── patches.yaml
GitOps仓库结构清晰后,开发人员只需提交代码,CI流水线自动构建镜像并更新对应环境的Kustomize配置,ArgoCD自动同步到集群。整个部署流程无需人工操作,且每次变更都有Git提交记录可审计。
同步状态监控与告警
ArgoCD的同步状态需要持续监控。通过ArgoCD Notifications插件实现同步失败时自动发送告警:
# argocd-notifications-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
trigger.on-deploy-failed: |
- when: app.status.operationState.phase in ['Failed', 'Error']
send: [slack-failed]
template.slack-failed: |
message: |
ArgoCD同步失败: {{.app.metadata.name}}
状态: {{.app.status.operationState.phase}}
错误: {{.app.status.operationState.message}}
链接: https://argocd.example.com/applications/{{.app.metadata.name}}
使用argocd app sync命令可手动触发同步,argocd app diff查看Git仓库与集群状态的差异。生产环境建议关闭automated自动同步,改为手动审批后同步,dev和staging环境保持自动同步以提高迭代速度。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/cicd-liu-shui-xian-zi-dong-hua-shi-zhan-gitlabcicd-yu/