GitLab+Jenkins+ArgoCD+Harbor 完整GitOps发布流程详解
这份文档是生产级K8s GitOps流水线的完整落地手册 ,核心逻辑是Git作为唯一可信源,Jenkins负责CI构建,ArgoCD负责CD同步 ,彻底实现"代码提交即自动上线"。下面我会从架构原理→组件部署→CI配置→CD配置→完整发布闭环一步步拆解,结合文档里的每一条命令和配置讲清楚"做什么、为什么这么做"。
一、先搞懂整体架构与核心分工
1. 架构图(对应文档环境)
开发者提交代码 → GitLab(代码仓库+配置仓库) → Jenkins自动触发CI → 编译打包 → 推镜像到Harbor → Jenkins更新GitLab配置仓库的镜像标签 → ArgoCD检测到Git变化 → 自动同步配置到K8s集群 → 服务上线
2. 各组件明确分工(文档严格遵循)
| 组件 | 负责工作 | 核心作用 |
|---|---|---|
| GitLab | 存储业务代码仓库 和K8s配置仓库 | 唯一可信源,所有变更都记录在Git |
| Jenkins | 拉代码→编译→测试→构建镜像→推Harbor→更新配置仓库 | 纯CI(持续集成),只做构建不做部署 |
| ArgoCD | 监控Git配置仓库→自动同步到K8s集群→保证集群状态与Git一致 | 纯CD(持续部署),只做部署不做构建 |
| Harbor | 存储Docker镜像 | 私有镜像仓库,统一管理所有服务镜像 |
3. 文档环境说明
- K8s集群:1个Master节点+2个Worker节点(node01/node02)
- 所有组件都部署在K8s的
gitops命名空间下(ArgoCD单独在argocd命名空间) - 集群内部域名:
*.svc.cluster.local,外部访问用Ingress域名:gitlab.zls.com/jenkins.zls.com/argocd.zls.com
二、第一步:部署三大核心组件(GitLab/Jenkins/ArgoCD)
所有组件都通过K8s YAML资源清单部署,统一管理、持久化存储,避免物理机部署的混乱。
1. 部署GitLab(代码/配置仓库)
文档提供了两种部署方式:Docker命令和K8s YAML,生产环境用K8s YAML。
关键配置解释
yaml
# 1. 持久化存储:把GitLab的配置、日志、数据挂载到宿主机目录,避免Pod重启丢失数据
volumes:
- name: gitlab-config
hostPath:
path: /data/gitlab/config # 宿主机目录,提前创建
- name: gitlab-log
hostPath:
path: /data/gitlab/log
- name: gitlab-data
hostPath:
path: /data/gitlab/data
# 2. 环境变量:关闭不需要的Prometheus监控,减少资源占用;配置GitLab访问地址
env:
- name: GITLAB_OMNIBUS_CONFIG
value: |
external_url 'http://gitlab-svc.gitops.svc.cluster.local' # 集群内部访问地址
gitlab_rails['gitlab_shell_ssh_port'] = 22
prometheus['enable'] = false # 关闭监控,节省资源
部署后验证
bash
# 查看Pod状态
kubectl get pod -n gitops
# 获取初始root密码
kubectl exec -it -n gitops gitlab-xxx -- grep 'Password' /etc/gitlab/initial_root_password
# 测试访问(配置本地hosts解析:10.0.0.102 gitlab.zls.com)
curl http://gitlab.zls.com
2. 部署Jenkins(CI构建工具)
这是最关键的一步,Jenkins需要能运行Docker命令 和能访问GitLab,文档里的配置解决了这两个核心问题。
核心配置详解
yaml
# 1. 特权模式+挂载Docker套接字:让Jenkins容器能直接调用宿主机的Docker引擎
securityContext:
privileged: true # 开启特权模式
capabilities:
add: ["ALL"]
volumes:
- name: docker-command
hostPath:
path: /usr/bin/docker # 挂载宿主机docker命令
- name: docker-socket
hostPath:
path: /var/run/docker.sock # 挂载宿主机Docker套接字(核心)
# 2. InitContainer初始化SSH密钥:让Jenkins能通过SSH拉取GitLab代码
initContainers:
- name: setup-ssh
image: busybox:latest
command: ["/bin/sh", "-c"]
args:
- mkdir -p /root/.ssh && cp /tmp/ssh-key/id_rsa /root/.ssh/id_rsa && chmod 700 /root/.ssh && chmod 600 /root/.ssh/id_rsa
volumeMounts:
- name: ssh-key-volume # 从Secret中读取提前生成的SSH私钥
mountPath: /tmp/ssh-key
readOnly: true
- name: ssh-dir
mountPath: /root/.ssh
# 3. Secret存储SSH私钥:把提前生成的SSH私钥base64编码后存入K8s Secret
apiVersion: v1
kind: Secret
metadata:
name: gitlab-ssh-key
namespace: gitops
type: kubernetes.io/ssh-auth
data:
ssh-privatekey: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQo= # 你的私钥base64编码
为什么这么做?
- 挂载
docker.sock:Jenkins本身运行在容器里,无法直接运行Docker命令,通过挂载宿主机的Docker套接字,就能调用宿主机的Docker引擎构建镜像 - InitContainer初始化SSH:避免把私钥直接写在YAML里,通过Secret管理更安全,同时自动设置正确的权限(SSH私钥必须是600权限,否则无法使用)
部署后验证
bash
# 获取Jenkins初始密码
kubectl exec -it -n gitops jenkins-xxx -- cat /var/jenkins_home/secrets/initialAdminPassword
# 测试Jenkins能否拉取GitLab代码
kubectl exec -it -n gitops jenkins-xxx -- git clone git@gitlab-svc.gitops.svc.cluster.local:root/test.git
3. 部署ArgoCD(CD同步工具)
ArgoCD官方提供了一键部署的YAML,文档里做了两个关键优化:关闭HTTPS和配置Ingress。
关键配置
yaml
# 1. 关闭ArgoCD的HTTPS,方便通过Ingress HTTP访问
args:
- /usr/local/bin/argocd-server
- --insecure # 关闭HTTPS
# 2. Ingress配置:外部访问ArgoCD
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-ingress
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/ssl-redirect: "false" # 关闭HTTPS重定向
spec:
rules:
- host: argocd.zls.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 80
部署后验证
bash
# 获取ArgoCD初始admin密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# 登录ArgoCD CLI
argocd login 10.1.6.33 --username admin --insecure --grpc-web
# 查看集群状态
argocd cluster list
三、第二步:配置CI流水线(Jenkins端)
Jenkins的核心工作是:代码提交后自动触发,完成构建→推镜像→更新配置仓库。
1. 前置准备
- 在GitLab创建两个仓库:
- 业务代码仓库:
devops-demo(存放Spring Boot/前端代码) - 配置仓库:
devops-demo-k8s(存放K8s的Deployment/Service/Ingress YAML)
- 业务代码仓库:
- 把Jenkins的公钥(
~/.ssh/id_rsa.pub)添加到GitLab的SSH密钥中,让Jenkins能读写这两个仓库 - 在Harbor创建项目
devops,用于存储镜像 - 配置Jenkins的Harbor凭证(用户名密码),用于推送镜像
2. 完整Jenkins Pipeline脚本(对应文档作业)
groovy
pipeline {
agent any
environment {
// 全局变量,参数化构建时可修改
IMAGE_NAME = "10.0.0.107/devops/hello-world" // Harbor地址+项目名+镜像名
IMAGE_TAG = "${BUILD_NUMBER}" // 用Jenkins构建号作为镜像标签,唯一且可追溯
CONFIG_REPO = "git@gitlab-svc.gitops.svc.cluster.local:root/devops-demo-k8s.git" // 配置仓库地址
}
stages {
stage('拉取业务代码') {
steps {
git url: 'git@gitlab-svc.gitops.svc.cluster.local:root/devops-demo.git',
branch: 'main',
credentialsId: 'gitlab-ssh' // Jenkins中配置的GitLab SSH凭证
}
}
stage('编译打包') {
steps {
// Java项目示例
sh 'mvn clean package -DskipTests'
// 前端项目示例:sh 'npm install && npm run build'
}
}
stage('构建Docker镜像') {
steps {
// 用项目根目录的Dockerfile构建镜像
sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
}
}
stage('推送镜像到Harbor') {
steps {
withCredentials([usernamePassword(
credentialsId: 'harbor-cred',
usernameVariable: 'HARBOR_USER',
passwordVariable: 'HARBOR_PASS'
)]) {
// 登录Harbor
sh "docker login 10.0.0.107 -u ${HARBOR_USER} -p ${HARBOR_PASS}"
// 推送镜像
sh "docker push ${IMAGE_NAME}:${IMAGE_TAG}"
// 清理本地镜像,节省空间
sh "docker rmi ${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
stage('更新Git配置仓库') {
steps {
// 克隆配置仓库
sh "git clone ${CONFIG_REPO} config-repo"
dir('config-repo') {
// 替换Deployment中的镜像标签
sh """
sed -i "s|image: 10.0.0.107/devops/hello-world:.*|image: ${IMAGE_NAME}:${IMAGE_TAG}|g" deployment.yaml
"""
// 提交并推送修改
sh """
git config user.name "jenkins"
git config user.email "jenkins@example.com"
git add deployment.yaml
git commit -m "Update image to ${IMAGE_TAG}"
git push origin main
"""
}
}
}
}
post {
success {
echo '构建成功!ArgoCD将自动同步部署'
}
failure {
echo '构建失败!请查看日志排查问题'
}
}
}
3. 配置自动触发
在GitLab的业务代码仓库中配置Webhook,地址为http://jenkins.zls.com/project/devops-demo,触发事件选择"Push events",这样开发者提交代码到main分支就会自动触发Jenkins构建。
四、第三步:配置CD同步(ArgoCD端)
ArgoCD的核心工作是:持续监控Git配置仓库,一旦发现配置变化,自动同步到K8s集群。
1. 两种创建ArgoCD应用的方式
文档提供了UI创建和YAML创建两种方式,生产环境推荐用YAML创建,可版本化管理。
方式1:YAML创建(推荐)
yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: hello-world
namespace: argocd
spec:
project: default # 所属项目,默认default
# Git配置仓库信息
source:
repoURL: git@gitlab-svc.gitops.svc.cluster.local:root/devops-demo-k8s.git
targetRevision: main # 监控的分支
path: "." # 配置文件所在目录
# 部署目标集群和命名空间
destination:
server: https://kubernetes.default.svc # 部署到当前K8s集群
namespace: hello-world # 目标命名空间
# 自动同步策略(核心)
syncPolicy:
automated:
prune: true # 自动删除Git中不存在的资源(比如旧的Pod)
selfHeal: true # 自动修复手动修改的集群资源(保证Git是唯一可信源)
syncOptions:
- CreateNamespace=true # 如果目标命名空间不存在,自动创建
部署命令:kubectl apply -f hello-world-argo.yaml
方式2:UI创建
- 登录ArgoCD UI(
http://argocd.zls.com) - 点击"New App",填写应用名称、项目、同步策略
- 填写Git仓库地址、分支、路径
- 填写目标集群和命名空间
- 点击"Create"完成创建
2. 关键参数解释
prune: true:如果Git中删除了某个资源的YAML,ArgoCD会自动在集群中删除该资源,避免残留selfHeal: true:如果有人手动修改了集群中的资源(比如kubectl edit deployment),ArgoCD会自动将其恢复为Git中的状态,保证Git是唯一可信源CreateNamespace=true:自动创建目标命名空间,不需要提前手动创建
五、完整发布闭环演示(对应文档lol-web例子)
现在我们模拟一次完整的代码提交到上线的过程,你就能彻底理解整个流程了:
- 开发者提交代码 :修改
devops-demo仓库的代码,提交到main分支 - GitLab触发Webhook:自动通知Jenkins开始构建
- Jenkins执行CI流程 :
- 拉取最新代码
- 编译打包生成jar包
- 构建Docker镜像,标签为
10.0.0.107/devops/hello-world:123(123是Jenkins构建号) - 推送镜像到Harbor
- 克隆配置仓库
devops-demo-k8s,修改deployment.yaml中的镜像标签为123 - 提交并推送修改到GitLab
- ArgoCD检测到变化 :每隔3分钟轮询Git配置仓库,发现
deployment.yaml有更新 - ArgoCD自动同步 :执行
kubectl apply -f deployment.yaml,更新K8s集群中的Deployment - K8s执行滚动更新:逐步替换旧的Pod为新的Pod,服务无中断上线
- 验证结果 :访问
http://hello.zls.com,看到最新的代码效果
六、文档中的坑与生产优化建议
1. 文档中的坑
- YAML缩进错误:文档中部分YAML的缩进不正确(比如Jenkins Service的namespace位置),复制时需要修正
- HostPath存储:生产环境不要用HostPath,应该用PV/PVC或云存储,避免节点故障导致数据丢失
- 没有配置资源限制:所有组件都没有配置CPU/内存限制,可能导致资源抢占,生产环境必须添加
- HTTP访问:生产环境应该配置HTTPS证书,不要用明文HTTP
2. 生产优化建议
- 多环境管理:配置仓库用不同分支对应不同环境(dev/test/prod),ArgoCD分别同步
- 权限分离:开发人员只有代码仓库的读写权限,没有配置仓库的写入权限,只有运维人员能修改生产环境配置
- 镜像版本管理:除了构建号,还可以加上Git提交哈希,方便追溯
- 监控告警:监控Jenkins构建状态、ArgoCD同步状态、服务运行状态
- 回滚机制:出问题时直接回滚Git配置仓库的提交,ArgoCD会自动同步回滚
- 完整触发链 (你关心的)
你(或 Jenkins)改 GitLab 配置仓库里的 web.yaml
git add → commit → push 推到 GitLab
ArgoCD 定时拉取 Git(默认 3 分钟),发现 YAML 变了
ArgoCD 自动 apply 到 K8s,Deployment 更新、Pod 滚动替换
集群状态和 Git 保持一致 - 一句话总结
GitLab 是唯一真实状态;YAML 一更新,ArgoCD 自动同步到 K8s,全程不用 kubectl。
七、文档作业完成指南
作业要求:gitlab + jenkins + argoCD 发布 hello-world + harbor 参数化构建
- 在GitLab创建
hello-world代码仓库和hello-world-k8s配置仓库 - 编写
hello-world的Dockerfile和K8s配置文件(deployment.yaml/service.yaml/ingress.yaml) - 在Jenkins创建参数化构建项目,添加
IMAGE_TAG参数,默认值为${BUILD_NUMBER} - 把上面的Pipeline脚本复制到Jenkins项目中,修改对应的仓库地址和Harbor地址
- 在ArgoCD创建应用,关联
hello-world-k8s配置仓库 - 提交代码到
hello-world仓库,验证自动构建和部署是否成功 - 测试参数化构建:手动触发构建,指定不同的镜像标签,验证是否能正常发布
GitLab 相关密钥(SSH 私钥)
用途:Jenkins 免密读写 GitLab(代码仓、配置仓)
1. 生成位置
在 master01 或 Jenkins 宿主机生成 SSH 密钥对:
bash
ssh-keygen
私钥:~/.ssh/id_rsa
公钥:~/.ssh/id_rsa.pub
2. 配置位置(三处)
1)GitLab 网页 :把 公钥 加到 GitLab 用户 SSH Keys → Jenkins 能拉/推代码
2)K8s Secret :私钥 base64 后创建 Secret(名字:gitlab-ssh-key)
yaml
apiVersion: v1
kind: Secret
metadata:
name: gitlab-ssh-key
namespace: gitops
type: kubernetes.io/ssh-auth
data:
ssh-privatekey: 私钥base64
3)Jenkins YAML:挂载这个 Secret 到 Jenkins 容器
yaml
volumes:
- name: ssh-key-volume
secret:
secretName: gitlab-ssh-key
items:
- key: ssh-privatekey
path: id_rsa
→ 容器里 /tmp/ssh-key/id_rsa → 复制到 /root/.ssh/id_rsa → 免密访问 GitLab
二、Harbor 镜像仓库密钥(账号密码)
用途:Jenkins 登录 Harbor 推镜像;K8s 拉镜像
1. 配置位置(两处)
1)Jenkins 凭证 :Jenkins 里添加 usernamePassword 凭证 → Pipeline 里登录 Harbor 推镜像
groovy
withCredentials([usernamePassword(credentialsId: 'harbor-cred', ...)]) {
sh "docker login harbor地址 -u \$USER -p \$PASS"
}
2)K8s Secret(imagePullSecret):集群拉 Harbor 私有镜像用
bash
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor地址 \
--docker-username=admin \
--docker-password=xxx
Deployment 里引用:
yaml
spec:
imagePullSecrets:
- name: harbor-secret
三、Jenkins 自身密码
用途:登录 Jenkins 网页
- 初始密码:容器内
/var/jenkins_home/secrets/initialAdminPassword - 可改密码:Jenkins 网页里修改
四、ArgoCD 密码
用途:登录 ArgoCD UI / CLI
- 初始密码:K8s Secret
argocd-initial-admin-secret
bash
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
- 可改:
kubectl edit secret或 UI 改
五、整体密钥流向(一句话串)
- SSH 私钥:宿主机 → K8s Secret → Jenkins 容器 → 免密读写 GitLab
- Harbor 账号密码:Jenkins 凭证(推镜像)+ K8s Secret(拉镜像)
- Jenkins/ArgoCD 密码:各自容器/Secret,用于网页登录
面试极简总结(直接背)
- GitLab SSH 密钥:宿主机生成 → GitLab 加公钥 → K8s Secret 存私钥 → Jenkins 挂载使用
- Harbor 密钥:Jenkins 凭证(推镜像)、K8s imagePullSecret(拉镜像)
- Jenkins/ArgoCD 密码:各自初始密码/Secret,用于登录