Linux: CICD-ArgoCD

GitOps 介绍

什么是 GitOps

GitOps 由 Weaveworks 公司在 2017年 提出。

CNCF(云原生基金会) 官方标准定义 GitOps

  • GitOps 是一套标准化云原生运维交付范式,用于实现持续部署
  • 它将 基础设施、应用的全部期望状态 以声明式格式存入 Git 仓库并把 Git 作为 唯一可信数据源
  • 部署在目标集群内的代理程序(如ArgoCD、Flux)会主动从 Git 拉取配置,持续对比集群真实状态,自动收敛至 Git 中定义的期望状态。

传统 CI/CD:CI 打包镜像 –> 工具(kubectl/helm) 直接推送资产原到集群

GitOps:Git 存所有 K8s YAML –> 集群控制器拉取 Git 配置,自动同步集群状态

GitOps 核心理念:声明式运维

CNCF 认证标准符合以下 4 条,才算标准的 GitOps 实现

Declarative 声明式

系统所有期望状态(应用 yaml、helm、kustiomize、网络策略、RBAC) 必须用声明式描述,只定义“最终要达到什么状态”,而非分步执行命令; 工具自动计算差异完成变更。

对比:命令式(kubectl run / Jenkins 脚本)是“一步步做什么”,不符合 GitOps。

Versioned & Immutable 版本化、不可变

所有期望的状态统一放在 Git 版本仓库,天然具备完整提交历史、变更审计;

支持一键回滚至任意历史提交,不允许无记录的临时手动修改集群。

Pulled Automatically 自动拉取(Pull 模型,核心区别于传统 Jenkins)

集群内部代理(ArgoCD)主动从 Git 拉取配置,而非外部 CI 工具推送配置到集群;

集群凭证仅保存在集群内部 ,不会暴露给 Jenkins 等外网流水线,安全性大副提升。

Continuously Reconsiled 持续协调自愈
代理程序循环检测集群真实状态与 Git 期望状态,一旦发现配置飘逸(如人工 kubectl 改集群资源),自动将集群恢复为 Git 内标准状态,杜绝环境不一致。

GitOps 工作流程

仓库分层

通常分两类仓库隔离职责:

  1. 应用代码仓库(App Repo):业务代码、Dockerfile,CI 打包镜像、推送镜像仓库,更新镜像版本提交到配置仓库。
  2. 集群配置仓库(Infra/GitOps Repo):存放所有K8s资源清单,分环境目录(dev/test/prod)。
img_20260903_010220.webp

GitOps 完整流程

流程:

  1. 开发提交业务代码到应用仓库
  2. CI 拉代码、编译、跑测试
  3. CI 流水线构建容器镜像,推送到镜像仓库
  4. CI 自动修改 GitOps 仓库中 Deployment 的镜像 tag,提交 PR(PuRequest)/MR (Merge Request)
  5. 运维审核 PR、合并到主分支

CD流程:GitOps 只工作于 CD,只监听 配置仓库

  1. 集群内 GitOps 控制器(ArgoCD/Flux)定时拉取 Git 仓库
  2. 控制器对比集群当前资源,检测 Git 配置文件变更(镜像版本本、资源规格、环境变量修改),自动执行更新、滚动发布
  3. 集群发生人工篡改(手动 kubectl edit),控制器检测差异, 自动回滚为 Git 版本
  4. 故障回滚:仅需 Git 仓库回滚提交,控制器自动同步旧版本。

GitOps 对比 传统 CD

维度 传统CICD(直接操作集群,kubectl部署) GitOps
可信数据源 集群实时状态 Git 仓库
部署方式 命令式(执行脚本) 声明式(对比状态)
数据流 主动推送配置到集群 集群内 Agent 主动拉取 Git 配置
变更记录 零散日志,难追溯 Git commit完整历史
回滚方式 需要手动操作流水线 直接回滚 Git 版本
集群漂移 极易发生,人工修改无法管控 自动修复漂移
权限管控 CICD 都需开放K8S集群操作权限 CI 仅需要管控 Git 仓库权限
多环境管理 脚本复制,易出错 多分支/目录隔离配置,一套 Git 仓库,
    同时同步多套K8s集群,统一管控基础设施

主流 GitOps 工具对比

工具 开发方 核心特点 适用场景
ArgoCD RedHat UI 可视化、支持 Kustomize/Helm、集群可视化、 企业级生产、可视化操作、多集群管理,
    Webhook、权限完善、支持手动同步、自动同步两种模式 当前最主流企业 GitOps 工具
Flux CD CNCF 毕业项目 轻量、原生集成 Helm、CI 联动强、 云原生原生、轻量化集群、自动化流水线
    无UI(配套Flux Dashboard)  
Argo Rollouts RedHat 配合 ArgoCD,灰度发布、蓝绿、金丝雀 需要精细化发布策略的业务
Flagger Weaveworks 配套 Flux,自动化灰度+指标判断 全自动流量发布

GitOps 适用与不适用场景

适合

  • 多 K8s 集群、多环境企业;
  • 需要严格审计、变更追溯的生产环境;
  • 团队分离开发/运维,收紧集群权限;
  • 微服务持续频繁发布。
  • 只要资源能用 声明式代码 描述、能检测配置漂移,无论云资源、反控制机、裸金属、数据库、传统服务器,都能落地 GitOps

不适合

  • 单机临时测试、短期本地开发环境;
  • 完全无代码管理、一次性临时集群。

Argo 介绍

项目基础概况

https://argoproj.github.io/

Argo 是一套 K8s原生开源工具套件 ,用于运行和管理 Kubernetes上 的作业和应用程序。

由 Intuit 公司创立,2020 年进入 CNCF 孵化,现已正式毕业,是云原生领域最主流的 GitOps、CI/CD、流水线、灰度发布标准工具栈 Code Pipes。

所有的 Argo 工具都实现为控制器和自定义资源。

全部基于 Kubernetes CRD 扩展,所有组件独立可单独部署,也可组合搭建完整云原生交付平台,覆盖 流水线、持续部署、灰度发布、事件自动化 四大核心场景。

发展时间线

  • 2015:初代 ArgoWorkflows 发布
  • 2017:ArgoCD 诞生,落地 GitOps 理念
  • 2019:Argo Rollouts、Argo Events 推出
  • 2020:整体进入 CNCF 孵化
  • 2022:全套四大核心组件正式从 CNCF 毕业

四大核心独立组件

四个组件无强制依赖,可按需单独安装使用:

Argo CD
  • 核心定位:GitOps 持续交付工具
  • 核心作用:以Git仓库为唯一可信源,自动同步 K8s 资源配置到集群
  • 关键能力:
    1. 持续对比Git期望状态与集群实际状态,自动修复配置漂移
    2. 提供WebUI、CLI、API,支持多集群统一管理
    3. 一键同步/回滚、部署审计日志、RBAC 权限、SSO 登录
    4. 扩展组件:ApplicationSet 批量管理应用、Image Updater 自动更新镜像
  • 典型业务场景:Git 提交 K8s YAML 清单,ArgoCD 自动拉取配置并完成集群部署,标准 GitOps 落地流程
Argo Workflows
  • 核心定位:K8s 原生容器流水线引擎
  • 核心作用:在 K8s 上编排容器化任务流水线,替代原生 Job/Cronjob
  • 关键能力:
    1. 支持串行、并行、DAG 依赖拓扑编排任务
    2. 每个任务独立容器运行,资源隔离、弹性调度
    3. 内置脚本、缓存、循环、分支、人工审批能力
  • 典型业务场景:代码提交后自动执行完整 CI 流程:代码编译 –> 单元测试 –> 镜像构建 –> 镜像推送
Argo Rollouts
  • 核心定位:渐进式灰度发布控制器
  • 核心作用:弥补 K8s 原生 Deployment 滚动更新短板,提供企业级精细化发布策略
  • 关键能力:
    1. 金丝雀发布:按比例逐步切分流量放量
    2. 蓝绿发布:两套完整环境快速切换,一键回滚
    3. 对接 Prometheus 监控指标,异常自动回滚
    4. 配合服务网格(Istio/Linkerd)实现精准流量权重、标签灰度
  • 典型业务场景:生产新版本上线,先分配 10% 用户流量验证,指标无异常后再全量发布
Argo Events
  • 核心定位:事件驱动自动化框架
  • 核心作用:监听内外各类事件,自动触发集群自动化动作
  • 关键能力:
    1. 支持海量事件源:Git Webhook、镜像推送、K8s 资源变更、定时任务、Kafka/MQ、HTTP 回调、监控告警
    2. 可触发 Workflow、ArgoCD 同步、创建K8s资源等动作
  • 典型业务场景:
    1. Git代码提交自动触发CI流水线
    2. 镜像仓库推送新版本镜像后,自动触发 ArgoCD 重新部署应用

ArgoCD 介绍和架构

ArgoCD 是什么

ArgoCD 是一个为 Kubernetes 而生的,遵循声明式 GitOps 理念的持续部部署工具。

ArgoCD 遵循 GitOps 模式,使用 Git 仓库作为定义所需应用程序状态的真实来源

ArgoCD 是云原生计算基金会(Cloud Native Computing FoNCF)的成员。

2018年3月首次发布 v0.1.0 版本,2019 年 5 月发布 v1.0.0 版本

ArgoCD 核心组件

组件 作用
argocd-server API + UI
argocd-repo-server 拉取 Git 仓库
argocd-application-controller 核心控制器(调谐状态)
argocd-dex-server SSO 认证
Redis 缓存

ArgoCD 配套主流 CI 工具

明确核心分工

ArgoCD 只做 CD(集群部署、GitOps同步),不负责代码编译、镜像构建、单元测试

  • 必须搭配 CI 工具完成「代码→镜像→更新Git配置」整条流水线。

标准 GitOps 流程统一逻辑:

  • 代码提交 → CI 执行测试/构建镜像推送仓库 → CI 修改 GitOps 仓库的 Deployyment/Helm values 镜像标签并提交 → ArgoCD 监听 Git 变更自动同步到集群。

ArgoCD和主流CI对比

CI工具 最佳匹配企业规模 核心优势 短板
Drone 小型私有K8s集群、极简轻量化需求、预算有限小团队 部署极简,单容器即可运行;配置文件简洁;完全容器化执行;资源占用极低;开源免费无臃肿组件 企业级多租户、权限、审计能力薄弱;生态插件少,复杂构建需大量自定义脚本;大厂大规模落地案例少
GitLab CI 几十~两百人中小团队、GitLab 用户 代码仓库一体化,零额外运维 平台化多租户能力弱
Jenkins 传统企业、存量改造、复杂构建 插件丰富,兼容各类老旧构建工具 有单点,运维成本高
Tekton 中大型集团、金融、自研 DevOps 平台、OpenShift K8s 原生、多租户、弹性扩缩容、合规强 上手门槛高,需自研前端门户
Argo Workflows 纯云原生小团队、简单流水线 同 Argo 生态,语法统一 多租户管控不足

安装

安装

官方说明

# 非高可用 HA
kubectl create namespace argocd

## 指定版本
kubectl apply -n argocd --server-side --force-conflicts -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.2/manifests/install.yaml

## 最新版本
kubectl apply -n argocd --server-side --force-conflicts -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# HA
kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts -f https://github.com/argoproj/argo-cd/blob/stable/manifests/ha/install.yaml

方法1-基于 mainfests 安装

kubectl create namespace argocd
VERSION=3.5.2
wget https://raw.githubusercontent.com/argoproj/argo-cd/v${VERSION}/manifests/install.yaml
kubectl apply -n argocd --server-side --force-conflicts -f install.yaml

grep "^kind:" install.yaml
grep "image:" install.yaml # 查看镜像
        image: quay.io/argoproj/argocd:v3.5.2
        image: ghcr.io/dexidp/dex:v2.45.1
        image: quay.io/argoproj/argocd:v3.5.2
        image: quay.io/argoproj/argocd:v3.5.2
        image: public.ecr.aws/docker/library/redis:8.2.3-alpine
        image: quay.io/argoproj/argocd:v3.5.2
        image: quay.io/argoproj/argocd:v3.5.2
        image: quay.io/argoproj/argocd:v3.5.2
        image: quay.io/argoproj/argocd:v3.5.2
        image: quay.io/argoproj/argocd:v3.5.2

        
# 生成 CRD
kubectl get crd | grep argo
kubectl api-resources | grep -i argo

kubectl get pod -n argocd
kubectl get cm -n argocd
kubectl get secrets -n argocd

范例

root@jenkins:~/.jasper/tmp# kubectl get crd | grep argo
applications.argoproj.io                                  2026-09-05T06:51:28Z
applicationsets.argoproj.io                               2026-09-05T06:51:29Z
appprojects.argoproj.io                                   2026-09-05T06:51:30Z
root@jenkins:~/.jasper/tmp# kubectl api-resources | grep -i argo
applications                        app,apps                          argoproj.io/v1alpha1                  true         Application
applicationsets                     appset,appsets                    argoproj.io/v1alpha1                  true         ApplicationSet
appprojects                         appproj,appprojs                  argoproj.io/v1alpha1                  true         AppProject
root@jenkins:~/.jasper/tmp# kubectl get pod -n argocd
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          55s
argocd-applicationset-controller-5959f79d67-klcvn   1/1     Running   0          56s
argocd-dex-server-6f84fd5569-k56gs                  1/1     Running   0          56s
argocd-notifications-controller-5856884878-lhmd4    1/1     Running   0          56s
argocd-redis-86846d5986-2z2rh                       1/1     Running   0          56s
argocd-repo-server-7d44c57bc8-hjv67                 1/1     Running   0          56s
argocd-server-8567f6cc96-m4hmn                      1/1     Running   0          56s

kubectl get cm -n argocd
NAME                        DATA   AGE
argocd-cm                   9      58s
argocd-cmd-params-cm        0      58s
argocd-gpg-keys-cm          0      58s
argocd-notifications-cm     0      58s
argocd-rbac-cm              0      58s
argocd-ssh-known-hosts-cm   1      58s
argocd-tls-certs-cm         0      58s
kube-root-ca.crt            1      2m36s

root@jenkins:~/.jasper/tmp# kubectl get secrets -n argocd
NAME                          TYPE     DATA   AGE
argocd-initial-admin-secret   Opaque   1      60s
argocd-notifications-secret   Opaque   0      73s
argocd-redis                  Opaque   1      63s
argocd-secret                 Opaque   5      73s

方法2-基于 helm 安装

# 添加 helm repo
helm repo add argo-cd https://argoproj.github.io/argo-helm
helm repo update

# 创建命名空间并安装
helm install --create-namespace argocd arg/argo-cd -n argocd

UI 访问

方法1-基于 LoadBalancer 或者 NodePort 类型

# 将 argocd-server 服务类型更改为 LoadBalancer
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
# 稍等片刻,你的云服务提供商将为该服务分配一个外部 IP 地址。你可以通过以下命令获取该 IP
kubectl get svc argocd-server -n argocd -o=jsonpath='{.status.loadBalancer.ingress[0].ip}'

方法2-基于 ingress http

# 方法1:修改 ConfigMap argocd‑cmd‑params‑cm
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cmd-params-cm
  namespace: argocd
data:
  server.insecure: "true"

# 生效
kubectl rollout restart deployment argocd-server -n argocd


# 方法2:直接修改 Deployment 容器 args(直接追加 --insecure)
containers:
- name: argocd-server
  command: ["/usr/local/bin/argocd-server"]
  args:
    - --insecure   #增加此行
# ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-ingress
  namespace: argocd
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.xx.com
    http:
      paths:
      - path: /
        #pathType: ImplementationSpecific
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 80

方法3-基于 ingress SSL Passthrough TLS 透传实例 https

默认 ArgoCD 的 Pod 开启 https,在 ingress 上开启 ssl Passthrough TLS(四层 TCP 透传,不解密,读取 SNI 域名路由)实现访问

流量链路

  • 用户 http –> 重定向 https 443 –> nginx ingress 四层透传不解密 –> argocd-server Service:443 –> Pod:8080(argo自签证书)
# ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    # 开启 tls 透传
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    # ingress 到后端走 https 协议
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
  name: argocd-ingress-passthrough
  namespace: argocd
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.xx.com
    http:
      paths:
      - path: /
        #pathType: ImplementationSpecific
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 443

方法4-基于 Port Forwarding

端口转发

# 确保 argocd-server 的 pod 所在宿主机节点已安装 socat 工具
apt update && apt -y install socat

# 通过节点 8080 端口暴露服务
kubectl port-forward svc/argocd-server -n argocd 8080:443 --address 0.0.0.0

方法5-基于 gateway api

# 默认 http 转到 https ,所以提前关闭 argocd 的 https
cat <<\EOF>> httprout.yaml 
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: argocd-httproute
  namespace: argocd
spec:
  parentRefs:
    - name: gateway-internal
      namespace: default
  hostnames:
  - "devargocd.xxx.cn"
  rules:
    - backendRefs:
        - name: argocd-server
          port: 80
      matches:
        - path:
            type: PathPrefix
            value: /
EOF

UI 登录修改密码

获取登录密码

kubectl get secrets argocd-initial-admin-secret -n argocd -oyaml

# 提取 password 变量的值,即 admin 用户登录密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d

登录并修改密码

在登录界面 User Info 侧边栏更改密码。也可以用 ArgoCD CLI 命令行工具修改密码。

相关 CR 资源说明

ArgoCD 核心 CR (Custom Resource)

ArgoCD 基于 argoproj.io/v1alpha1 提供多套自定义资源 CR

最主要是3个:Application、AppProject、Application

Application(最核心,单应用部署定义)

代表一套 GitOps 应用,定义「Git源码位置+目标集群+同步策略」,ArgoCD Controller 持续调谐 Git 与集群状态。

所有 UI/CLI 创建的应用最终都会生成该 CR,存于 argocd nameespace。

Application 资源的完整结构说明

代码库
# ssh 连接
界面添加 Settings --> Repositories 或者都通过文件生成

cat > argcd-deploy-secret.yaml << EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-tls-certs-cm
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: git@github.com:argoproj/my-private-repository.git
  sshPrivateKey: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----
EOF

# 通过 SSH 建立连接,每个仓库服务器的公钥必须预先在 Argo CD 中配置好
# https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#ssh-known-host-public-keys
# 比如 获取 git 仓库 47.2.9.1 的公钥,将公钥信息添加到 argocd 中
for host in 47.2.9.1 ; do ssh-keyscan $host 2> /dev/null ; done

Settings --> Repository certificates and known hosts
## 查看对应公钥
kubectl  get cm argocd-ssh-known-hosts-cm -oyaml -n argocd 
多集群管理

下载 argocd 命令行客户端

# 查看 Argo CD 的最新版本
VERSION=$(curl --silent "https://api.github.com/repos/argoproj/argo-cd/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')

# mac
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/download/$VERSION/argocd-darwin-arm64
# linux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64


sudo install -m 555 argocd /usr/local/bin/argocd
rm argocd

添加集群

# 将另一个集群的 kubeconfig 配置文件放到本地
scp xxx.xx.x:~/.kube/config ~/.kube/one.config

# 添加 k8s 集群上下文
export KUBECONFIG=$HOME/.kube/config:$HOME/.kube/on.config

# 查看多集群信息

# kubectl  config get-contexts 
CURRENT   NAME               CLUSTER     AUTHINFO       NAMESPACE
*         ks-v1              ks-v1       ks-v1   
          k8s-admin@one      one         k8s-admin

# 添加
argocd login argocd.xxx.com       
argocd cluster add k8s-admin@one 

在 UI 页面就可以看到对应集群了。

  • Settings –> Clusters

ApplicationSet(批量生成 Application)

ApplicationSet 模板化批量生成多个 Application CR,解决多环境、多集群、多租户重复写 Application YAML 的痛点。

20260903-110242.webp

ArgoCD 内置多种生成器(List/Cluster/Git/Matrix),自动渲染参数生成应用。

主要 Generator

  1. ListGenerator:静态多环境参数(dev/test/prod)
  2. ClusterGenerator:自动读取 ArgoCD 注册的所有集群,一键全集群部署
  3. GitGenerator:扫描 Git 目录自动生成应用(目录即环境)
  4. MatrixGenerator:多维度组合(集群+环境)

AppProject(多租户权限管控)

AppProject (CRD:argoproj.io/v1alpha1) 是 ArgoCD 的 权限隔离、资源白名单控制单元 ,所有 Application 必须绑定一个 Project (默认自带 default )。

作用:给应用划分边界,限制应用能访问哪些 Git 仓库、部署到哪些集群、能创建哪些K8s资源、设置资源配额、阻断高危操作,实现多租户/多环境隔离。

区分:

  • Application:单个应用部署声明(在哪拉代码、部署到哪)
  • AppProject:权限规则容器,批量管控一组 Application 的约束

AppProject 对应用做 逻辑分组+权限隔离 ,企业多环境/多团队必备约束项目内所有 Application:

AppProject 核心能力

  1. 限制可访问的 Git 仓库(允许/禁止仓库地址)
  2. 限制可部署的目标集群&命名空间
  3. 允许/禁止创建的 K8s 资源类型(禁止创建 Namespace、Secret、ClusterRole 等高危资源)
  4. 资源配额:限制该项目下所有应用总 CPU/内存/Pod 数量
  5. 集群资源黑名单:阻止创建特权容器、节点端口、HostPatth 等风险配置
  6. 配置外部集群、集群级资源权限
  7. 项目级元数据、描述、UI展示信息
# 默认 default 没做控制,权限开放的
kubectl get appprojects -n argocd default -oyaml

AppProject资源的完整结构说明

自定义 Project

界面操作 Settings –> Projects

#生产环境 delete 权限非常危险,可以不给此权限,默认不配置的权限都是 deny
]# kubectl -n argocd get appprojects.argoproj.io  evescn  -o yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: evescn
  namespace: argocd
spec:
  # 允许的 git 仓库白名单
  sourceRepos:
  - https://gitee.com/evescn/kustomize-demo
  description: test project
  # 允许部署的 k8s 集群和名称空间白明单
  destinations:
  - name: in-cluster
    namespace: dev-*
    server: https://kubernetes.default.svc
  - name: in-cluster
    namespace: test
    server: https://kubernetes.default.svc
  # 集群资源白名单(允许管理 CRD/ClusterRole 等)
  clusterResourceWhitelist:
  - group: '*'
    kind: Namespace
  # 集群资源黑名单
  clusterResourceBlacklist:
  - group: '*'
    kind: '*'
  # 允许的名称空间
  namespaceResourceWhitelist:
  - group: '*'
    kind: '*'
  # 禁止的命名空间
  namespaceResourceBlacklist:
  - group: '*'
    kind: Secret
  # 项目内 RBAC 权限
  roles:
  - description: evescn_role 开发仅可查看、手动同步
    name: evescn_role
    policies:
    - p, role:dev, applications, get, payment-team/*, allow
    - p, role:dev, applications, sync, payment-team/*, allow
    - p, proj:evescn:evescn_role, applications, sync, evescn/*, allow
    - p, proj:evescn:evescn_role, applications, get, evescn/*, allow
    - p, proj:evescn:evescn_role, applications, delete, evescn/*, allow
    jwtTokens:
    - iat: 1691651971
      id: evescn_token
    - iat: 1691649777
      id: token

role 中 同步窗口类似于版本火车概念

添加用户
  1. 本地用户(local accounts):修改 argocd-cm 创建账号, argocd‑rbac‑cm 分配 RBAC 权限
    • ⚠️生产大规模环境推荐 OIDC/SSO(Dex、Keycloak),本地账号不适合多人正式环境
  2. SSO 单点登录 (OIDC/Dex):对接企业 ldap/github,本文不展开
# 1. 创建本地用户(修改 argocd‑cm)
kubectl edit cm argocd-cm -n argocd

data:
  #启用用户devuser,允许 webUI 和 cli 登录
  accounts.devuser.enabled: "true"
  accounts.devuser: "login"
  accounts.jasper.enabled: "true"
  accounts.jasper: "login"
  accounts.bx.enabled: "true"
  accounts.bx: "login"
  accounts.cdsync.enabled: "true"
  accounts.cdsync: "apiKey"
  #如果是 API 机器人账号,改成 capabilities: "apiKey" 禁止网页登录

# 查看用户
user@host ~ % argocd --grpc-web account list
NAME     ENABLED  CAPABILITIES
admin    true     login
bx       true     login
devuser  true     login
jasper   true     login

# 不想输入 --grpc-web 可以设置环境变量,永久生效
alias argocd='argocd --grpc-web'

## 查看用户情况
argocd --grpc-web account get --account devuser
argocd --grpc-web account get --account jasper

# 设置devuser密码
argocd  --grpc-web account update-password \
  --account devuser

## 或者明文输入
argocd  --grpc-web account update-password \
  --account <name> \
  --current-password <current-user-password> \
  --new-password <new-user-password>

argocd --grpc-web account update-password \
  --account jasper \
  --new-password '72x3%prigswjsey0x66zargocd'

# 2. RBAC 权限 (argocd‑rbac‑cm)

kubectl edit cm argocd-rbac-cm -n argocd

## 内置 3 个系统角色
#- role:admin:全部权限
#- role:readonly:只能查看,不能同步修改
#- role:clusterAdmin:集群、仓库全部管理权限

#语法规则:
#p,角色名,资源,动作,项目/应用,allow
#g,用户名,角色名

#资源动作常用值:get/sync/refresh/delete/rollback/create/update

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.default: role:readonly
  policy.csv: |
    # 开发人员只能查看和 sync 非生产环境
    p, role:developer, applications, get, */*, allow
    p, role:developer, applications, sync, */*-dev, allow
    p, role:developer, applications, sync, */*-staging, allow

    # SRE可以操作所有环境
    p, role:sre, applications, *, */*, allow
    p, role:sre, clusters, *, *, allow

    # Sync 同步
    p, role:rync, applications, get, */*, allow
    p, role:rync, applications, sync, */*, allow

    # 绑定用户devuser到devops角色
    g, cdsync, role:rync
    g, devuser, role:developer
    g, jasper, role:sre
    g, bx, role:sre
    
    # 绑定GitHub Team
    #g, myorg:developers, role:developer
    #g, myorg:sre-team, role:sre



# 3. 验证权限
1. UI 登录:使用新账号密码登录
2. CLI 测试
argocd login <argocd-server>
argocd app list
argocd app sync myapp
# 权限不足会返回`PermissionDenied`

两种权限模型

  1. 全局 RBAC(argocd‑rbac‑cm):全局,跨 Project 权限
  2. AppProject 内部角色(项目级 RBAC):在 AppProject CR 里定义,仅作用于本项目,适合多团队隔离

可以叠加使用

api 同步
# 1. 创建本地用户(修改 argocd‑cm)
kubectl edit cm argocd-cm -n argocd

data:
  accounts.cdsync.enabled: "true"
  accounts.cdsync: "apiKey"

# 2. 设置全局 RBAC 权限 (argocd‑rbac‑cm)

kubectl edit cm argocd-rbac-cm -n argocd
data:
    # Sync 同步
    p, role:rync, applications, get, */*, allow
    p, role:rync, applications, sync, */*, allow

    # 绑定用户到角色
    g, cdsync, role:rync

# 3. 生成用户 token
## https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_account_generate-token/
% argocd account generate-token --account cdsync
eyJhbGciOiJIUzI1NiIsInR5cCI

## 查看用户 token
argocd account get -a cdsync

同步更新验证

ARGO_APP="nginx-dev"
ARGOCD_SERVER='argocd.xxx.com:80'
ARGOCD_AUTH_TOKEN='eyJxxxxoXnlQ'
GITOPS_SHA='HEAD'
argocd app list --grpc-web --server "$ARGOCD_SERVER" --auth-token "$ARGOCD_AUTH_TOKEN"

           
                        argocd app sync "$ARGO_APP" \
                          --server "$ARGOCD_SERVER" \
                          --auth-token "$ARGOCD_AUTH_TOKEN" \
                          --revision "$GITOPS_SHA" \
                          --grpc-web \
                          --plaintext \
                          --timeout 10

                        argocd app wait "$ARGO_APP" \
                          --server "$ARGOCD_SERVER" \
                          --auth-token "$ARGOCD_AUTH_TOKEN" \
                          --sync \
                          --health \
                          --operation \
                          --insecure \
                          --timeout 600

ArgoCD Application source 支持渲染类型

spec.source 下只能选下面四种的其中一种渲染器,互互斥不能共存:

四种渲染器完整对比

类型 适用仓库内容 核心能力
directory 纯原生 Deployment/ServiceYAML,无任何工具配置文件 直接下发原始清单,无变量替换能力
kustomize 带 kustomization.yaml 的 Base+Overlay 目录 镜像替换、副本补丁、多环境覆盖、无模板语法
helm Helm Chart (Chart.yaml+templates+values) 模板渲染、values分层、Chart 依赖
plugin 自定义 CRD /第三方渲染插件 Jsonnet/Helmfile/Terraform 等第三方工具工程 扩展支持任意外部laC工具,高度自定义
  1. source 下 helm/kustomize/directory/plugin 四仲会直接报错 cannot specify multiple source type
  2. 日常 GitOps 主流只用:helm/kustomize;
  3. 简单静态清单用 directory;复杂混合 IaC(Infrastructure as Code)工具才用 plugin

官方文档

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  # ArgoCD 页面展示的应用名称,prod 环境实例
  name: order-prod
  # Application CR 自身存放的命名空间,固定 argocd(所有 Argo 应用都在这里)
  namespace: argocd
  # 删除应用时同步删除集群资源(级联删除)
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  # 归属项目(权限隔离),default 为默认项目
  project: default

  # Source: Git 期望状态源(Kustomize/Helm/原生Yaml)
  source:
    repoURL: https://github.com/user/my-repo.git
    targetRevision: main # 分支/tag/commit hash
    path: app/order/prod
    directory:         # 纯 yaml/kustomize 目录配置
      resourse: true   # 是否递归扫描子目录
      include: "{*.yaml, *.yml}"
      exclude:         # 排队文件
      - *.tmp
    # Helm 专用配置
    helm:
      valueFiles:
      - values-prod.yaml
      valueObject:
        replicaCount: 3
      values: |
        image:
          repository: user/my-image
          pullPolicy: Always
          tag: xxx
    # Kustomize 专用
    kustomize:
      version: v5

  # Destination:部署目标集群和命名空间
  destination:
    # 本地集群: https://kubernetes.default.svc
    server: https://esk-prod.ap-southeast-1.eks.amazonaws.com
    namespace: order-prod

  # SyncPolicy 自动同步/自愈/修剪策略(GitOps 核心)
  syncPolicy:
    automated:
      prune: true          # git 删除资源,集群同步
      selfHeal: true       # 集群手动篡改,自动恢复 git 状态
      allowEmpty: false    # 不允许同步后无资源
    syncOptions:
    - CreateNamespace=true # 不存在 ns 自动创建
    - PrunePropagationPolicy=forground
    retry: # 部署失败自动重试
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

# status: ArgoCD 自动填充,只读
status:
  sync:
    status: Synced # Synced/OutOfSync/Unknown
  health:
    status: Healthy # Healthy/Progressing/Degraded/Missing

秒级同步

自动同步间隔由argocd-cm ConfigMap 中的timeout.reconciliation值决定,默认值为120s,会额外增加60s的抖动,最长可达3分钟。

kubectl  -n argocd edit cm argocd-cm
data:
  # 同步间隔为 10 + 额外的 20 s 拉动 = 30s 同步
  # 只是控制器 “多久醒来一轮干活”,不是 git 轮询间隔,改小它无法消除 2min 缓存延迟
  timeout.reconciliation: 10s
  timeout.reconciliation.jitter: 20s

秒级同步方案1

# comparison 缓存没过期(2min),ArgoCD 不会去远端 git 拉取新 commit
kubectl -n argocd logs -f argocd-application-controller-0 |grep "comparison expired" |grep "nginx-dev"

# expiry:2m0s 是 ArgoCD controller 硬编码的比较缓存 TTL,cm 参数无法修改。
# 但是只要 comparison 缓存未过期(硬编码 2min,无配置项),就算每 10s 醒来一次,
# 也不会去拉取远端 Git**,直接复用旧缓存,日志打印 Skipping auto‑sync: application status is Synced。

#注释 / 删除这一段(最关键!恢复注解刷新能力)
kubectl  -n argocd edit cm argocd-cm
# resource.customizations.ignoreResourceUpdates.argoproj.io_Application: |
#   jqPathExpressions:
#     - '.metadata.annotations."argocd.argoproj.io/refresh"'
#     - '.metadata.annotations."argocd.argoproj.io/hydrate"'
#     - '.operation'

#修改 cm 后重启 argocd‑application‑controller
kubectl rollout restart statefulset -n argocd argocd-application-controller

#重启完成后,再执行 annotate 刷新注解,才能真正触发即时拉取 git。
kubectl annotate -n argocd app nginx-dev argocd.argoproj.io/refresh=hard --overwrite

管理应用实现 CD 实例

GitOps 仓库结构设计

合理的仓库结构是GitOps成功的关键。强烈建议分离应用代码仓库和部署配置仓库,避免配置变更触发不必要的CI流程:

# 应用代码仓库 (app-repo)
app-repo/
├── src/
├── tests/
├── Dockerfile
├── .github/
│   └── workflows/
│       └── ci.yaml
└── README.md

# 部署配置仓库 (deploy-repo)
deploy-repo/
├── apps/
│   ├── frontend/
│   │   ├── base/
│   │   │   ├── deployment.yaml
│   │   │   ├── service.yaml
│   │   │   └── kustomization.yaml
│   │   └── overlays/
│   │       ├── dev/
│   │       ├── staging/
│   │       └── prod/
│   └── backend/
├── argocd/
│   └── applications/
└── README.md

参考:

下面案例来源:

基于 Directory 案例

argocd-demo % tree manifest
manifest
├── dev
│   ├── 01-namespace.yaml
│   ├── 02-service.yaml
│   └── 03-deployment.yaml
├── prod
│   ├── 01-namespace.yaml
│   ├── 02-service.yaml
│   └── 03-deployment.yaml
└── test
    ├── 01-namespace.yaml
    ├── 02-service.yaml
    └── 03-deployment.yaml
cat <<\EOF>> manifest/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: spring-boot-helloworld-test
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitee.com/lbtooth/argocd-demo.git  # 必须要在 coredns 中实现域名 gitlab.xx.com 解析
    targetRevision: HEAD
    path: manifest/test
    directory:
      resourse: true  # 是否递归扫描子目录
      include: "{*.yaml, *.yml}"
      exclude: "{README.md, dos/**,scripts/*.sh}"
  destination:
    # 应用在当前集群
    server: https://kubernetes.default.svc
    namespace: test
  # 同步策略
  syncPolicy:
    # 开启 git 变更同步
    automated:
      prune: true          # git 删除资源,集群同步
      selfHeal: true       # 集群手动篡改,自动回滚为 git 标准配置
      allowEmpty: false    # 不允许同步后无资源
    # 定时轮询拉取 git 仓库
    syncOptions:
    - CreateNamespace=true # 目标不存在 namespace 则自动创建
    # 同步重试机制(部署失败自动重试)
    retry:
      limit: 3
      backoff:
        duration: "30s"
        factor: 2
        maxDuration: "5m"
EOF

kubectl apply -f application.yaml

kubectl get applications -n argocd

kubectl get pod -n test

# 手动修改副本数
kubectl scale deploy -n test --replicas 3 spring-boot-helloworld; kubectl get pod -n test
# 过一会儿副本数又恢复为 1 个副本
kubectl get pod -n test

基于 Kustomize 案例

# 复用一套配置,overlays 打补丁
argocd-demo % tree kustomization
kustomization
├── base
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
└── overlays
    ├── dev
    │   └── kustomization.yaml
    ├── prod
    │   └── kustomization.yaml
    └── test
        └── kustomization.yaml


kubectl create deploy nginx --image=nginx:1.15.12 --replicas=2 -oyaml --dry-run=client >base/deployment.yaml 
kubectl create svc clusterip nginx --tcp=8080:80 -o yaml --dry-run=client > base/service.yaml
cat > kustomization.yaml << EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
EOF
cat <<\EOF>> kustomize/dev.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: spring-boot-hello-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitee.com/lbtooth/argocd-demo.git
    targetRevision: HEAD
    path: kustomization/overlays/dev
    # Kustomize 专用
    kustomize:
      # kustomize 渲染时自动给所有资源添加 namespace: dev,优先级高于 kustomization/overlays/test/kustomization.yaml
      namespace: dev
  destination:
    server: https://kubernetes.default.svc
    # 指定 k8s 集群最终放在业务 pod/service 的命名空间,优先级高于上面的 kustomize.namespace
    namespace: dev
  # 同步策略
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    retry:
      limit: 5
      backoff:
        duration: "30s"
        factor: 2
        maxDuration: "5m"
    syncOptions:
    - CreateNamespace=true
EOF

基于 Helm 案例

argocd-demo % tree chart
chart
├── Chart.yaml
├── templates
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   └── service.yaml
├── values-dev.yaml
├── values-prod.yaml
├── values-test.yaml
└── values.yaml
cat <<\EOF>> helm/dev.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: spring-boot-hello-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitee.com/lbtooth/argocd-demo.git
    targetRevision: HEAD
    path: chart
    helm:
      valueFiles:
      - values.yaml     # 基础文件
      - values-dev.yaml # 补充文件
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  # 同步策略
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
     retry:
      limit: 5
      backoff:
        duration: "30s"
        factor: 2
        maxDuration: "5m"
    syncOptions:
    - CreateNamespace=true
EOF

applicationset 案例

如果要部署到多个名称空间,要写多个 application,比较麻烦。使用 applicationset 来生成具体的 application

支持多种生成器

  • 列表生成器
  • 集群生成器
  • Git 生成器
  • 矩阵生成器

列表生成器

cat <<\EOF>> manifest/applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: spring-boot-helloworld
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - env: dev
        path: manifest/dev
        ns: dev
      - env: test
        path: manifest/test
        ns: test
      - env: prod
        path: manifest/prod
        ns: prod
  template:
    metadata:
      name: 'sprint-boot-helloword-{{env}}'
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: https://gitee.com/lbtooth/argocd-demo.git
        targetRevision: HEAD
        path: "{{path}"
        directory:
          resourse: true
          include: "{*.yaml, *.yml}"
          exclude: "{README.md,dos/**,scripts/*.sh}"
      destination:
        server: https://kubernetes.default.svc
        namespace: dev
      # 同步策略
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
          allowEmpty: false
        retry:
          limit: 5
          backoff:
            duration: "30s"
            factor: 2
            maxDuration: "5m"
        syncOptions:
        - CreateNamespace=true
EOF
cat > argocd/kustomize/applicationset.yaml  << EOF
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: nginx
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - env: dev
        business: pt
        path: pt/argocd/tmp/overlays/dev
        k8s-cluster: https://kubernetes.default.svc
        ns: default
      - env: test
        business: pt
        path: pt/argocd/tmp/overlays/test
        k8s-cluster: https://kubernetes.default.svc
        ns: test
      - env: prod
        business: pt
        path: pt/argocd/tmp/overlays/prod
        k8s-cluster: https://kubernetes.default.svc
        ns: prod
  template:
    metadata:
      name: '{{business}}-nginx-{{env}}'
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: git@git.xxx.com:gitops/ops-deploy.git
        targetRevision: HEAD
        path: "{{path}}"
        kustomize:
          namespace: "{{ns}}"
      destination:
        server: "{{k8s-cluster}}"
        namespace: "{{ns}}"
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
          allowEmpty: false
        retry:
          limit: 5
          backoff:
            duration: "30s"
            factor: 2
            maxDuration: "5m"
        syncOptions:
        - CreateNamespace=true
EOF

CLI 工具

argocd 安装和登录

curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64

# Mac
brew install argocd

命令补全

echo 'source <(argocd completion bash)' >> ~/.bashrc
source  ~/.bashrc

基础登录

# 获取密码方法1
argocd admin initial-password -n argocd
# 获取密码方法2:k8s 集群内执行
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d

# 修改前,先登录 admin
argocd login argocd.xxx.com --username admin --password <初始密码> --insecure
## 修改密码。输入旧密码,再输入新密码
argocd account update-password

# 注销后用新密码登录
argocd logout argocd.xx.com
argocd login argocd.xxx.com

argocd 用法说明

前置说明

  • 登录前置: argocd login <argocd-server地址>
  • 能用全局参数: --namespace argocd--grpc-web--insecure
  • 分类:登录认证、Application、Project、仓库/集群、插件配置、同步/运维、状态查询

全局能用参数

--server    #指定 ArgoCDServer 访问地址。适用多套 ArgoCD 环境切换登录
--username  #登录用户名。脚本自动化登录,无需交互式输入
--password  #登录密码。自动化脚本批量执行 argocd login
--insecure  #跳过 TLS 证书校验。测试环境自签证书、内网无合法SSL证书
--grpc-web  #使用 grpc-web 协议通信。通过 Ingress/LB 访问 ArgoCD 服务,必备参数
--timeout   #设置请求超时时间。适用于网络较差、跨机房访问,防止命令超时失败
-y/--yes    #所有交互式确认自动选择 yes。适用于自动化脚本、CI 流水线,避免等待人工确认

登录和账号管理命令

argocd login                   #登录ArgoCD服务端,保存本地token。如 
argocd login argocd.example.com --username admin password xxx

argocd logout                  #退出登录,清除本地凭证。如 
argocd logout argocd.example.com

argocd account update-password #修改当前登录用户密码

argocd account list            #列出所有用户账号


argocd context list            #查看本地保存的多个 argocd 服务连接

argocd context switch          #切换本地 argocd 服务上下文
argocd context switch argocd-prod

Application 应用核心操作

argocd app list  # 查询所有 application 列表
argocd app list -o wide

argocd app get <应用名>  # 查看单个应用详情

argocd app create       # 创建 application cr(命令行创建,替代 yaml apply)
argocd app create order-svc --repo https://gitlab/xxx \
   --path manifests \
   --dest-server https://k8s/api \
   --dest-namespace prod \
   --project prod-project

argocd app delete       # 删除应用

AppProject 项目权限管理

argocd proj xxx

仓库/集群管理

argocd repo list
argocd repo xx

argocd cluster list
argocd cluster xx

配置管理插件/系统配置

argocd admin settings get # 读取全局 argocd-cm 配置
argocd admin settings edit # 直接编辑全局配置

同步策略/运维批量操作

argocd app sync --all # 同步集群内所有应用
argocd app list --sync-status OutOfSync  # 筛选所有不同步的应用
argocd app list --health-status Degraded # 筛选异常不健康应用
argocd app teminate-op                   # 终止卡住的同步操作

导入/导出资源(迁移备份)

argocd app export # 导出 application 完整 yaml
argocd app export order-svc > app-order.yaml

argocd proj export # 导出 AppProject 完整 yaml

维护

查看

argocd app get nginx-dev

# 树形层级展示(看父子关系:Deployment → ReplicaSet → Pod)
argocd app resources nginx-dev --output tree

# 查看 Git 渲染出来的全部 yaml 清单
argocd app manifests nginx-dev

kubectl 查看 Application CR 内记录的资源

kubectl get application nginx-dev -n argocd -o yaml
# 重点看 status.resources 数组,里面记录所有托管资源
kubectl describe application nginx-dev -n argocd

同步

# 提前恢复注解刷新能力。 修改 configMap argocd-cm
APP=nginx-dev
kubectl annotate -n argocd app ${APP} argocd.argoproj.io/refresh=hard --overwrite

回滚

推荐使用Git revert保留完整变更历史:

# 方法1: ArgoCD UI回滚
# 在History页面选择之前版本Sync

# 方法2: 命令行回滚
argocd app rollback myapp-prod

# 方法3: Git revert(推荐)
cd deploy-repo
git revert HEAD
git push

jenkins 回滚思路

  • - 目标 tag 参数 → 修改服务 yaml 镜像 tag 版本 → 人工确认 → git 提交 → argocd 同步

CICD 脚本

jenkins pipline

  • jenkins 中提前准备相关密钥凭证
  • 创建 argocd 用户并生成 token
  • 发送 Lark 通知
pipeline {
    agent any

    options {
        withBuildUser()
    }
    environment {
        BUSINESS = "rl"
        DEPLOY_ENV = "dev"
        
        jobname = "${JOB_BASE_NAME}"
        OPS_GIT_URL = 'git@1.x.x.x:gitops/ops-deploy.git'
        OPS_PATH = "ops-deploy/${BUSINESS}/${jobname}/overlays/${DEPLOY_ENV}"
        image_url="public.ecr.aws/xxx/${jobname}:v${BUILD_NUMBER}"

        ARGO_APP = "${jobname}" + "-${DEPLOY_ENV}"
        ARGOCD_SERVER   = 'argocd.xxx.com:80'
        GITOPS_SHA = 'HEAD'
    }

    stages {

        
        stage('create deployment yaml') {
            steps {
                script {
                  //configFileProvider([configFile(fileId: 'eks-config', targetLocation: "eks-config")]){
                  //    sh """
                  //    /root/bin/kubectl --kubeconfig=/root/.kube/config-dev set image deployment/${jobname} ${jobname}=${image_url}
                  //    """
                  //} 
                  dir("ops-deploy") {
                    git branch: 'main',  changelog: false, poll: false, credentialsId: 'git-argocd', url: OPS_GIT_URL
                  }
                  dir(OPS_PATH) {
                    withCredentials([sshUserPrivateKey(credentialsId: 'git-argocd', keyFileVariable: 'PK')]) {
                      sh """
                      ls -l
                      yq '.images[0].newTag = "v" + strenv(BUILD_NUMBER)' kustomization.yaml 
                      git status
                      yq -i '.images[0].newTag = "v" + strenv(BUILD_NUMBER)' kustomization.yaml
                      git status
                      GIT_SSH_COMMAND="ssh -i $PK" git pull origin main
                      git add kustomization.yaml
                      git commit -m "Ci: ${jobname}.${DEPLOY_ENV}.${BUSINESS} image: ${image_url}"
                      GIT_SSH_COMMAND="ssh -i $PK" git push  origin HEAD:main
                      """
                    }
                  }
                }
            }
        }

        stage('Argo CD Deploy') {
            steps {
                withCredentials([
                    string(
                        credentialsId: 'argocd-token',
                        variable: 'ARGOCD_AUTH_TOKEN'
                    )
                ]) {
                    sh '''
                        echo "$ARGOCD_AUTH_TOKEN"
                        argocd app sync "$ARGO_APP" \
                          --server "$ARGOCD_SERVER" \
                          --grpc-web \
                          --plaintext \
                          --auth-token "$ARGOCD_AUTH_TOKEN" \
                          --revision "$GITOPS_SHA" \
                          --timeout 600

                        argocd app wait "$ARGO_APP" \
                          --server "$ARGOCD_SERVER" \
                          --grpc-web \
                          --plaintext \
                          --auth-token "$ARGOCD_AUTH_TOKEN" \
                          --sync \
                          --health \
                          --operation \
                          --timeout 600
                    '''
                }
            }
        }
    }
    post {
        success {
            script {
                notifyLark('SUCCESS')
            }
        }

        failure {
            script {
                notifyLark('FAILURE')
            }
        }

        aborted {
            script {
                notifyLark('ABORTED')
            }
        }
    }
}

import groovy.json.JsonOutput
def notifyLark(String result) {
    def success = result == 'SUCCESS'
    def title = success ? '✅ Argo CD 发布成功' : '❌ Argo CD 发布失败'
    def color = success ? 'green' : 'red'

    withCredentials([
        string(
            credentialsId: 'lark-release-webhook',
            variable: 'LARK_WEBHOOK'
        )
    ]) {
        def payload = JsonOutput.toJson([
            msg_type: 'interactive',
            card: [
                header: [
                    template: color,
                    title: [
                        tag    : 'plain_text',
                        content: title
                    ]
                ],
                elements: [
                    [
                        tag: 'markdown',
                        content: """\
**项目:** ${BUSINESS ?: 'unknown'}
**应用:** ${ARGO_APP ?: 'unknown'}
**环境:** ${DEPLOY_ENV ?: 'unknown'}
**GitOps SHA:** `${env.GITOPS_SHA ?: 'unknown'}`
**构建任务:** ${env.JOB_NAME} #${env.BUILD_NUMBER} by ${env.BUILD_USER}
**发布结果:** ${result}
**详情:** [查看 Jenkins 构建](${env.BUILD_URL})
""".stripIndent()
                    ]
                ]
            ]
        ])

        writeFile file: 'lark-message.json', text: payload

        sh '''
            curl --fail-with-body \
              --silent \
              --show-error \
              --request POST \
              --header 'Content-Type: application/json' \
              --data @lark-message.json \
              "$LARK_WEBHOOK"
        '''
    }
}

参考