从代码提交到自动上线的完整 CI/CD 实践
在现代云原生开发中,GitOps 已成为一种主流的持续交付范式。它以 Git 作为唯一事实源(Single Source of Truth),通过声明式配置驱动整个应用部署流程。本文将手把手带你构建一套完整的 CI/CD 流水线 ,使用 Kubernetes + Helm + ArgoCD 技术栈,实现 Java 应用从代码提交到自动上线的全流程自动化。
一、整体架构概览
我们的目标是构建如下流程:
开发者提交代码 → GitHub Actions 触发 CI 构建 → 推送 Docker 镜像 → 更新 Helm Chart 的 values.yaml → ArgoCD 自动同步变更 → 应用部署到 Kubernetes
核心组件:
- GitHub/GitLab:代码仓库 & CI 触发器
- Maven/Gradle:Java 项目构建工具
- Docker:容器镜像打包
- Helm:K8s 应用包管理器
- ArgoCD:GitOps 持续交付控制器
- Kubernetes:运行时平台
二、准备工作
1. 环境要求
- 一个可用的 Kubernetes 集群(如 Minikube、Kind、EKS、GKE、AKS)
- 安装
kubectl、helm、argocdCLI - 一个 GitHub 账号(或 GitLab)
- Docker Hub / Harbor / ECR 等镜像仓库
2. 项目结构设计
建议采用 多仓库模式(Multi-repo) 或 单仓库多目录(Monorepo) 。本文采用 双仓库模式:
- app-repo :存放 Java 源码(如
my-java-app) - infra-repo :存放 Helm Chart 和 ArgoCD 配置(如
my-java-app-deploy)
为什么分开?便于权限隔离、职责分离,也更符合 GitOps 原则。
三、步骤详解
第一步:构建 Java 应用并打包为 Docker 镜像
假设你有一个 Spring Boot 项目,pom.xml 中已配置好打包插件(如 spring-boot-maven-plugin)。
1. 编写 Dockerfile
dockerfile
# Dockerfile
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
2. 配置 GitHub Actions CI(.github/workflows/ci.yml)
yaml
name: Build and Push Docker Image
on:
push:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: mvn -B package -DskipTests
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
此工作流会在每次
main分支推送时:
- 构建 JAR 包
- 构建 Docker 镜像
- 推送到 GitHub Container Registry (GHCR),标签格式如
ghcr.io/yourname/my-java-app:main-abc123
第二步:准备 Helm Chart
在 infra-repo 中创建 Helm Chart:
bash
helm create my-java-app
修改 values.yaml:
yaml
replicaCount: 2
image:
repository: ghcr.io/yourname/my-java-app
tag: "main-latest" # 初始值,后续由 CI 自动更新
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 8080
ingress:
enabled: true
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
同时保留 Chart.yaml、templates/ 等标准结构。
提示:可将
values.yaml拆分为values-prod.yaml、values-staging.yaml以支持多环境。
第三步:配置 ArgoCD 实现 GitOps 同步
1. 安装 ArgoCD
bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
获取初始密码(admin 用户):
bash
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
启动端口转发:
bash
kubectl port-forward svc/argocd-server -n argocd 8080:443
访问 https://localhost:8080 登录(忽略证书警告)。
2. 创建 Application(声明式方式推荐)
在 infra-repo 中添加 argocd/app.yaml:
yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-java-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/yourname/my-java-app-deploy.git
targetRevision: main
path: my-java-app # Helm Chart 所在路径
helm:
valueFiles:
- values-prod.yaml
destination:
server: https://kubernetes.default.svc
namespace: my-java-app
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
应用该配置:
bash
kubectl apply -f argocd/app.yaml
ArgoCD 会自动监控
infra-repo中my-java-app目录的变化,并同步到集群。
第四步:CI 中自动更新 Helm values 并提交
回到 app-repo 的 GitHub Actions,在构建镜像后,自动更新 infra-repo 中的 values 文件。
修改 CI 流程(追加步骤)
yaml
# ... 前面的构建和推送镜像步骤 ...
- name: Clone infra repo
uses: actions/checkout@v4
with:
repository: yourname/my-java-app-deploy
token: ${{ secrets.INFRA_REPO_TOKEN }}
path: ./infra
- name: Update Helm values
run: |
cd ./infra
yq e '.image.tag = "${{ steps.meta.outputs.version }}"' -i my-java-app/values-prod.yaml
- name: Commit and push changes
run: |
cd ./infra
git config --global user.name "CI Bot"
git config --global user.email "ci-bot@example.com"
git add .
git diff --staged --quiet || git commit -m "chore: update image tag to ${{ steps.meta.outputs.version }}"
git push
注意:
- 需要创建一个 Personal Access Token (PAT) 并存入
secrets.INFRA_REPO_TOKEN,赋予repo权限。- 使用
yq工具安全地修改 YAML(需在 workflow 中安装):
yaml
- name: Install yq
run: |
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
chmod +x /usr/local/bin/yq
第五步:验证自动部署
- 开发者向
app-repo/main提交代码 - GitHub Actions 触发:
- 构建 JAR
- 构建并推送新镜像(如
ghcr.io/...:main-abc123) - 克隆
infra-repo - 更新
values-prod.yaml中的image.tag - 提交并推送变更
- ArgoCD 检测到
infra-repo变更(默认每 3 分钟轮询,或配置 Webhook 实时触发) - ArgoCD 自动执行
helm upgrade,滚动更新 Deployment - 应用新版本上线!
四、增强与优化建议
1. 多环境支持(Staging / Prod)
- 在
infra-repo中为每个环境创建独立目录或 values 文件 - 配置多个 ArgoCD Application(如
myapp-staging,myapp-prod) - CI 中根据分支(如
release/*)决定更新哪个环境
2. 安全加固
- 使用 ArgoCD RBAC 控制用户权限
- 镜像使用 SHA256 digest 而非 tag(防篡改)
- Helm values 中敏感信息使用 Sealed Secrets 或 External Secrets Operator
3. 性能与可靠性
- 为 ArgoCD 配置 Webhook(而非轮询),加速同步
- 添加 健康检查(Health Check)确保 Pod 就绪后再标记同步成功
- 集成 Prometheus + Grafana 监控部署状态
4. 回滚机制
- Git 即历史:回滚只需
git revert或切换到旧 commit - ArgoCD UI 支持一键回滚到任意历史版本
五、常见问题排查
| 问题 | 解决方案 |
|---|---|
| ArgoCD 显示 "OutOfSync" 但未自动同步 | 检查 syncPolicy.automated 是否启用;确认 Repo 凭据有效 |
| Helm 部署失败 | 查看 ArgoCD 中资源详情,检查 values 语法、镜像拉取权限 |
| CI 无法写入 infra-repo | 检查 PAT 权限是否包含 repo 写权限 |
| 镜像拉取失败(ImagePullBackOff) | 确保 K8s 集群有访问私有 Registry 的 imagePullSecret |
六、总结
通过 Kubernetes + Helm + ArgoCD 的组合,我们成功构建了一套 声明式、可审计、自动化 的 GitOps 流水线。其核心优势在于:
✅ 一切皆代码 :基础设施、配置、部署策略全部版本化
✅ 自动同步 :无需人工干预,Git 即部署指令
✅ 快速回滚 :Git 历史即部署历史
✅ 安全可靠:权限清晰,操作可追溯
这套方案不仅适用于 Java 应用,也适用于 Go、Python、Node.js 等任何可容器化的服务。随着云原生生态的成熟,GitOps 正在成为企业级交付的标准范式。