Linux基础:GitOps发布流程

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. 前置准备

  1. 在GitLab创建两个仓库:
    • 业务代码仓库:devops-demo(存放Spring Boot/前端代码)
    • 配置仓库:devops-demo-k8s(存放K8s的Deployment/Service/Ingress YAML)
  2. 把Jenkins的公钥(~/.ssh/id_rsa.pub)添加到GitLab的SSH密钥中,让Jenkins能读写这两个仓库
  3. 在Harbor创建项目devops,用于存储镜像
  4. 配置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创建
  1. 登录ArgoCD UI(http://argocd.zls.com
  2. 点击"New App",填写应用名称、项目、同步策略
  3. 填写Git仓库地址、分支、路径
  4. 填写目标集群和命名空间
  5. 点击"Create"完成创建

2. 关键参数解释

  • prune: true:如果Git中删除了某个资源的YAML,ArgoCD会自动在集群中删除该资源,避免残留
  • selfHeal: true:如果有人手动修改了集群中的资源(比如kubectl edit deployment),ArgoCD会自动将其恢复为Git中的状态,保证Git是唯一可信源
  • CreateNamespace=true:自动创建目标命名空间,不需要提前手动创建

五、完整发布闭环演示(对应文档lol-web例子)

现在我们模拟一次完整的代码提交到上线的过程,你就能彻底理解整个流程了:

  1. 开发者提交代码 :修改devops-demo仓库的代码,提交到main分支
  2. GitLab触发Webhook:自动通知Jenkins开始构建
  3. Jenkins执行CI流程
    • 拉取最新代码
    • 编译打包生成jar包
    • 构建Docker镜像,标签为10.0.0.107/devops/hello-world:123(123是Jenkins构建号)
    • 推送镜像到Harbor
    • 克隆配置仓库devops-demo-k8s,修改deployment.yaml中的镜像标签为123
    • 提交并推送修改到GitLab
  4. ArgoCD检测到变化 :每隔3分钟轮询Git配置仓库,发现deployment.yaml有更新
  5. ArgoCD自动同步 :执行kubectl apply -f deployment.yaml,更新K8s集群中的Deployment
  6. K8s执行滚动更新:逐步替换旧的Pod为新的Pod,服务无中断上线
  7. 验证结果 :访问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 参数化构建

  1. 在GitLab创建hello-world代码仓库和hello-world-k8s配置仓库
  2. 编写hello-world的Dockerfile和K8s配置文件(deployment.yaml/service.yaml/ingress.yaml)
  3. 在Jenkins创建参数化构建项目,添加IMAGE_TAG参数,默认值为${BUILD_NUMBER}
  4. 把上面的Pipeline脚本复制到Jenkins项目中,修改对应的仓库地址和Harbor地址
  5. 在ArgoCD创建应用,关联hello-world-k8s配置仓库
  6. 提交代码到hello-world仓库,验证自动构建和部署是否成功
  7. 测试参数化构建:手动触发构建,指定不同的镜像标签,验证是否能正常发布

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 改

五、整体密钥流向(一句话串)

  1. SSH 私钥:宿主机 → K8s Secret → Jenkins 容器 → 免密读写 GitLab
  2. Harbor 账号密码:Jenkins 凭证(推镜像)+ K8s Secret(拉镜像)
  3. Jenkins/ArgoCD 密码:各自容器/Secret,用于网页登录

面试极简总结(直接背)

  • GitLab SSH 密钥:宿主机生成 → GitLab 加公钥 → K8s Secret 存私钥 → Jenkins 挂载使用
  • Harbor 密钥:Jenkins 凭证(推镜像)、K8s imagePullSecret(拉镜像)
  • Jenkins/ArgoCD 密码:各自初始密码/Secret,用于登录
相关推荐
鱼鳞_3 小时前
苍穹外卖-Day05(Redis)
java·redis
雨落在了我的手上3 小时前
初识java(九):类和对象(⼀)
java·开发语言
是码龙不是码农3 小时前
数据库主键选型:为什么别用自增 ID?
java·数据库
北风toto3 小时前
Jenkins新手入门安装插件全报错
java·运维·jenkins
罗超驿3 小时前
20.MySQL事务隔离级别示例详解(脏读、不可重复读、幻读)
java·数据库·mysql·面试
Dicky-_-zhang3 小时前
KubeEdge边缘部署实践
java·jvm
dislike_shuati3 小时前
Ubuntu18多用户情况一用户桌面卡死,鼠标能动但点击没用——解决办法
linux·运维·服务器
码银3 小时前
在若依中如何新建一个模块(图文教程)
java·javascript