一:教程定位

前面的 Harness 教程主要采用传统 CI/CD 模式:

代码提交 ↓ 构建镜像 ↓ Pipeline 直接调用 Kubernetes API ↓ 部署 Deployment、Service、Ingress

这种方式简单直接,但在企业环境中会逐渐出现一些问题:

集群中的实际配置和 Git 配置不一致 运维人员手工修改 Kubernetes 资源后难以追踪 无法快速确认当前环境对应哪个 Git Commit 回滚依赖 Pipeline 历史或 kubectl rollout 多套环境的配置变更缺少统一审核 Pipeline 和集群之间存在较高权限耦合

GitOps 使用另一种交付模式:

Git 保存期望状态 ↓ GitOps Controller 持续读取 Git ↓ 比较 Git 期望状态与集群实际状态 ↓ 发现差异后执行同步 ↓ 让集群逐步收敛到 Git 中声明的状态

在 Harness GitOps 中,这个控制器体系由 Harness GitOps Agent 和 Argo CD 相关组件共同完成。

本篇将构建如下流程:

开发人员提交代码 ↓ Harness CI 执行测试 ↓ 构建镜像并推送 Harbor ↓ Pipeline 修改 GitOps 配置仓库中的镜像 Tag ↓ 提交 Git Commit ↓ Harness GitOpsSync 步骤触发 Application 同步 ↓ Argo CD 将配置同步到 Kubernetes ↓ 等待 Application 状态变为 Synced + Healthy


二:适合人群

本文适合中级用户:

DevOps 工程师 平台工程师 SRE Kubernetes 运维人员 正在从传统 CD 迁移到 GitOps 的团队 已经使用 Argo CD、希望纳入 Harness 管理的团队

建议已经掌握:

Harness Pipeline、Stage、Step Harness Service、Environment、Connector Kubernetes Deployment 和 Service Docker 镜像与 Harbor GitLab/Gitee 分支、Commit 和 Merge Request 基础 Shell 脚本


三:学习目标

完成本文后,你应该能够:

理解 GitOps 的核心原则 理解传统 CD 和 GitOps 的区别 理解 Harness GitOps Agent 与 Harness Delegate 的区别 安装 Harness GitOps Agent 检查 Agent 和 Argo CD 组件状态 配置 Harness GitOps Repository 配置 GitOps Cluster 创建 Harness GitOps Application 理解 Synced、OutOfSync、Healthy、Degraded 等状态 在 Pipeline 中更新 GitOps 配置仓库 使用 GitOpsSync 步骤同步 Application 等待 Application 达到 Healthy 通过 Git revert 完成可审计回滚 验证 Self Heal 和 Drift Correction 处理国内网络、私有仓库、自签证书和镜像拉取问题


四:GitOps 的核心原则

1. Git 是单一事实来源

应用应该部署成什么样,不以集群当前状态为准,而以 Git 中声明的配置为准。

例如:

spec:
  replicas: 3

表示期望状态为三个副本。

如果有人手工执行:

kubectl scale deployment harness-gitops-demo \
  --replicas=1 \
  -n gitops-dev

那么:

Git 期望状态:3 集群实际状态:1 Application 状态:OutOfSync

开启自动同步和 Self Heal 后,GitOps Controller 可以把副本数重新调整为 3。


2. 所有变更通过 Git 完成

推荐流程:

修改 YAML ↓ 提交分支 ↓ 创建 Merge Request ↓ 自动校验 ↓ 人工 Review ↓ 合并 ↓ GitOps 同步

不推荐:

直接 kubectl edit 直接 kubectl patch 直接在集群修改镜像 绕过 Git 修改生产资源


3. 使用声明式配置

Git 中保存的是最终期望状态:

image: harbor.company.com/devops/harness-gitops-demo:v1.2.0

而不是保存一组命令:

kubectl set image ...
kubectl scale ...
kubectl patch ...

常见声明式资源包括:

Kubernetes YAML Helm Chart Helm values Kustomize Argo CD Application ApplicationSet


4. 控制器持续调谐

GitOps Controller 会持续比较:

Desired State:Git 中声明的状态 Live State:Kubernetes 中实际运行的状态

两者相同:

Synced

两者不同:

OutOfSync

资源正常运行:

Healthy

资源运行异常:

Degraded


五:传统 CD 与 GitOps 的区别

对比项 传统 CD GitOps
部署发起者 Pipeline GitOps Controller
配置来源 Pipeline、制品、脚本 Git
应用方式 Pipeline 推送到集群 Controller 从 Git 拉取并同步
漂移检测 通常需要额外工具 持续比较 Git 与集群
回滚方式 Pipeline 回滚、kubectl undo Git revert 后重新同步
审计来源 Pipeline 执行记录 Git 历史 + Pipeline 记录
集群凭证 Pipeline 通常需要访问集群 Agent/Controller 持有目标访问能力
手工修改 容易长期保留 可被检测或自动修正

GitOps 并不是完全替代 Pipeline。

更准确的组合是:

Pipeline: 负责构建、测试、扫描、审批、更新 Git

GitOps: 负责把 Git 中的期望状态同步到集群


六:Harness GitOps 核心组件

1. Harness GitOps Agent

GitOps Agent 运行在用户的 Kubernetes 环境中,主要负责:

连接 Harness SaaS 连接 GitOps Repository 连接目标 Kubernetes Cluster 处理 GitOps 实体和操作 向 Harness 返回同步和健康状态 协调 Argo CD 组件执行任务

Agent 主要使用出站连接,不要求从公网直接访问集群中的 Agent 服务。


2. Argo CD Application Controller

Application Controller 负责:

持续监控 Application 读取期望状态 读取集群实际状态 计算差异 判断同步状态 执行同步或纠正操作 判断资源健康状态


3. Argo CD Repo Server

Repo Server 负责:

访问 Git 仓库 拉取指定分支、Tag 或 Commit 读取 Kubernetes Manifest 执行 Helm 模板渲染 执行 Kustomize 渲染 向 Application Controller 返回最终 Manifest


4. Redis

Redis 用于缓存 GitOps 和 Argo CD 运行过程中需要的数据。

它不是业务应用的 Redis,也不应与业务 Redis 共用。


5. GitOps Repository

GitOps Repository 保存期望状态,可以是:

Git 仓库 HTTP Helm Repository OCI Helm Repository

注意:

Harness GitOps Repository 只服务于 GitOps。

Harness CI 或普通 CD Pipeline 拉取、修改代码时, 应使用普通 Git Connector。

这两个连接即使指向同一个 GitLab,也不是同一种 Harness 实体。


6. GitOps Cluster

GitOps Cluster 表示目标 Kubernetes 集群。

Agent 安装在目标集群时,通常可以使用:

in-cluster

Agent 安装在独立管理集群时,也可以配置远程目标集群。


7. GitOps Application

Application 将以下内容组合起来:

哪个 Agent 执行 从哪个 Repository 读取 读取哪个分支或 Tag 读取哪个目录 同步到哪个 Cluster 同步到哪个 Namespace 使用哪种 Sync Policy 是否 Prune 是否 Self Heal

可以简单理解为:

Application = Repository + Revision + Path + Cluster + Namespace + Sync Policy


七:Harness GitOps Agent 与 Delegate 的区别

这是初学 GitOps 时最容易混淆的概念。

GitOps Agent

主要负责:

读取 GitOps 期望状态 管理 Argo CD Application 同步 Kubernetes 配置 监控同步和健康状态 检测集群漂移

Harness Delegate

主要负责:

执行 Pipeline 内部步骤 访问 Git、Harbor、SonarQube 等内网资源 运行 Shell Script 调用云厂商 API 执行普通 CD 部署 执行 PR Pipeline 中的 Git 操作

本篇流程同时使用两者:

Delegate: 执行 CI 构建镜像 更新 GitOps 配置仓库

GitOps Agent: 读取 GitOps 仓库 让 Argo CD 同步目标集群

如果只在 Harness 页面手工创建 Application 并执行 GitOps Sync,通常只需要 GitOps Agent。

如果 Pipeline 还需要克隆、修改和推送 Git 仓库,则仍然需要 CI 执行环境或 Delegate。


八:推荐实验架构

Harness SaaS │ ├── Harness Delegate │ ├── 访问 GitLab │ ├── 访问 Harbor │ └── 更新 GitOps Repository │ └── Harness GitOps Service │ ▼ Harness GitOps Agent │ ├── Argo CD Application Controller ├── Argo CD Repo Server ├── Redis └── ApplicationSet Controller │ ▼ Kubernetes Cluster

国内环境建议:

Git:GitLab / Gitee / 企业 Git 镜像仓库:Harbor / ACR / TCR / SWR Kubernetes:自建集群 / ACK / TKE / CCE Agent 与 Delegate:部署在企业内网或云 VPC


九:准备条件

Kubernetes 集群

建议实验环境至少具备:

可用 Kubernetes 集群 kubectl 已配置 Helm 3 可访问 Harness SaaS 可访问 GitLab/Gitee 可访问 Harbor 能够创建 CRD、Deployment、StatefulSet、Role 等资源

检查:

kubectl cluster-info
kubectl get nodes
helm version

创建命名空间

Agent 命名空间:

kubectl create namespace harness-gitops

应用命名空间:

kubectl create namespace gitops-dev

注意:

在创建 GitOps Application 前, 目标应用 Namespace 应提前创建。


网络检查

curl -I --connect-timeout 10 https://app.harness.io
curl -k -I --connect-timeout 10 https://gitlab.company.com
curl -k -I --connect-timeout 10 https://harbor.company.com/v2/

如果企业使用代理,需要提前规划:

HTTP_PROXY HTTPS_PROXY NO_PROXY

NO_PROXY 至少应考虑:

localhost 127.0.0.1 .svc .cluster.local kubernetes.default.svc GitLab 内网域名 Harbor 内网域名


十:创建 Harness GitOps Agent

在 Harness 项目中进入:

Deployments → GitOps → Settings → GitOps Agents → New GitOps Agent

建议填写:

Name: gitops-dev-agent

GitOps Operator: Argo

Namespace: harness-gitops

Existing Argo CD: No

如果企业已经运行原生 Argo CD,可以选择 Bring Your Own Argo CD,但基础教程先使用 Harness 新建的组件。

安装方式一般有:

Helm Chart Kubernetes YAML

对于普通 Kubernetes 集群,推荐优先使用:

Helm Chart 或 Kubernetes YAML


十一:方式一:使用 Helm 安装 Agent

在 Harness Agent 安装向导中下载:

override.yaml

然后执行:

helm repo add gitops-agent \
  https://harness.github.io/gitops-helm/

helm repo update gitops-agent

helm install harness-gitops-agent \
  gitops-agent/gitops-helm \
  --values override.yaml \
  --namespace harness-gitops

如果需要由 Helm 创建命名空间,也可以加入:

--create-namespace

完整示例:

helm install harness-gitops-agent \
  gitops-agent/gitops-helm \
  --values override.yaml \
  --namespace harness-gitops \
  --create-namespace

如果集群已经存在 Argo CD CRD,需要根据实际情况评估是否跳过 CRD 安装:

--set argo-cd.crds.install=false

不要在不了解现有 Argo CD 环境的情况下重复创建或删除 CRD。


十二:方式二:使用 YAML 安装 Agent

在 Harness 向导中下载:

gitops-agent.yaml

执行:

kubectl apply \
  -f gitops-agent.yaml \
  -n harness-gitops

检查资源:

kubectl get all -n harness-gitops
kubectl get pods -n harness-gitops
kubectl get statefulset -n harness-gitops
kubectl get cronjob -n harness-gitops

一般可以看到:

gitops-agent argocd-application-controller argocd-repo-server argocd-redis argocd-applicationset-controller gitops-agent-upgrader

具体资源名称以当前生成的 YAML 为准。


十三:国内网络环境下同步 Agent 镜像

Agent YAML 或 Helm Chart 可能引用公网镜像。

先检查镜像清单:

grep -E '^[[:space:]]*image:' gitops-agent.yaml \
  | awk '{print $2}' \
  | sort -u

Helm 安装前可以先渲染:

helm template harness-gitops-agent \
  gitops-agent/gitops-helm \
  --values override.yaml \
  --namespace harness-gitops \
  > rendered-agent.yaml

查看:

grep -E '^[[:space:]]*image:' rendered-agent.yaml \
  | awk '{print $2}' \
  | sort -u

如果节点无法稳定访问公网镜像仓库,应:

把所需镜像同步到 Harbor 在 Agent 安装配置中使用企业私有镜像仓库 配置 Harbor imagePullSecret 确保 Agent 自动升级任务也能从私有仓库拉取镜像

不要只修改当前 Deployment,而忽略:

Agent Upgrader Application Controller Repo Server Redis ApplicationSet Controller 初始化容器

具体镜像覆盖字段应以当前下载的 override.yaml 和 Agent 安装向导为准,不建议根据旧版本文档硬写字段。


十四:检查 Agent 是否正常

查看 Pod

kubectl get pods -n harness-gitops -o wide

查看 Agent 日志

kubectl logs \
  deployment/gitops-agent \
  -n harness-gitops \
  --tail=200

如果实际资源名不同:

kubectl get deployment -n harness-gitops

查看 Argo CD Controller

kubectl logs \
  statefulset/argocd-application-controller \
  -n harness-gitops \
  --tail=200

查看 Repo Server

kubectl logs \
  deployment/argocd-repo-server \
  -n harness-gitops \
  --tail=200

最终在 Harness 页面确认:

Agent Status: Healthy Connected


十五:准备 GitOps 配置仓库

建议把应用源代码和部署配置拆成两个仓库。

应用源码仓库

harness-gitops-demo-app

保存:

业务代码 Dockerfile 单元测试 CI 配置

GitOps 配置仓库

harness-gitops-config

保存:

Kubernetes YAML Helm values Kustomize overlays 环境配置

推荐结构:

harness-gitops-config/ ├── README.md ├── applications/ │ └── harness-gitops-demo/ │ ├── dev/ │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── configmap.yaml │ ├── test/ │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── configmap.yaml │ └── prod/ │ ├── deployment.yaml │ ├── service.yaml │ └── configmap.yaml └── docs/ ├── release-process.md └── rollback-process.md


十六:编写 Deployment

applications/harness-gitops-demo/dev/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: harness-gitops-demo
  namespace: gitops-dev
  labels:
    app: harness-gitops-demo
spec:
  replicas: 2
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: harness-gitops-demo
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: harness-gitops-demo
    spec:
      imagePullSecrets:
        - name: harbor-pull-secret
      containers:
        - name: harness-gitops-demo
          image: harbor.company.com/devops/harness-gitops-demo:v1.0.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 3000
          envFrom:
            - configMapRef:
                name: harness-gitops-demo-config
          readinessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 2
            failureThreshold: 6
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 20
            periodSeconds: 20
            timeoutSeconds: 2
            failureThreshold: 3
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi

十七:编写 Service

applications/harness-gitops-demo/dev/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: harness-gitops-demo
  namespace: gitops-dev
  labels:
    app: harness-gitops-demo
spec:
  type: ClusterIP
  selector:
    app: harness-gitops-demo
  ports:
    - name: http
      port: 80
      targetPort: http

十八:编写 ConfigMap

applications/harness-gitops-demo/dev/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: harness-gitops-demo-config
  namespace: gitops-dev
data:
  APP_NAME: harness-gitops-demo
  APP_ENV: dev
  APP_VERSION: v1.0.0
  LOG_LEVEL: info

十九:准备 Harbor 拉取凭证

kubectl create secret docker-registry harbor-pull-secret \
  --docker-server=harbor.company.com \
  --docker-username='robot$gitops' \
  --docker-password='YOUR_TOKEN' \
  --namespace gitops-dev

更推荐由以下方案管理 Secret:

External Secrets Operator HashiCorp Vault Sealed Secrets 云厂商 Secret Manager

不要把 Harbor Token 直接提交到 Git。


二十:提交初始 GitOps 配置

git clone \
  https://gitlab.company.com/devops/harness-gitops-config.git

cd harness-gitops-config

git add applications/harness-gitops-demo/dev

git commit -m "feat: add harness gitops demo dev manifests"

git push origin main

此时 Git 已保存 dev 环境的期望状态。


二十一:添加 Harness GitOps Repository

进入:

Deployments → GitOps → Settings → Repositories → New Repository

选择:

Repository Type: Git

Name: gitops-config-repository

GitOps Agent: gitops-dev-agent

Repository URL: https://gitlab.company.com/devops/harness-gitops-config.git

认证可以选择:

HTTPS 用户名 + Token SSH Key 凭证模板

国内企业建议:

优先使用只读 Deploy Token 或专用 GitOps Robot Account

GitOps Agent读取配置仓库通常只需要:

read_repository

Pipeline 如果还要修改这个仓库,则需要另一个可写凭证,并通过普通 Git Connector或 Harness Secret 使用。


二十二:自签证书和内网 GitLab

如果 GitLab 使用企业私有 CA,不建议长期打开跳过验证。

推荐进入:

GitOps → Settings → Repository Certificates → New Repository Certificate

上传:

TLS Repository Certificate

证书内容应为 PEM 格式:

-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----

如果使用 SSH,还应配置正确的 Known Host Key。


二十三:创建 GitOps Cluster

Agent 安装在目标集群且使用集群级权限时,一般会自动存在:

in-cluster

基础实验可以直接使用它。

如果 Agent 是 Namespaced 模式,或需要管理远程集群,应额外创建 Cluster,并提供:

Kubernetes API 地址 认证凭证 允许的 Namespace Agent

生产环境应坚持最小权限原则:

dev Agent 只管理 dev Cluster/Namespace prod Agent 只管理 prod Cluster/Namespace 不同团队使用不同 Agent 或 Argo Project


二十四:创建 Harness Service

创建:

Service Name: harness-gitops-demo

Identifier: harness_gitops_demo

该 Service 用于关联:

Pipeline Environment GitOps Application 运行实例

不要把 Service Identifier 随意修改,否则 Pipeline 和 Application 的关联可能失效。


二十五:创建 Harness Environment

创建:

Environment Name: dev

Environment Type: Pre-Production

后续还可以创建:

test pre prod

生产环境应单独配置权限和审批。


二十六:创建 GitOps Application

进入:

Deployments → GitOps → Applications → New Application

推荐填写:

Application Name: harness-gitops-demo-dev

Service: harness-gitops-demo

Environment: dev

GitOps Agent: gitops-dev-agent

Repository: gitops-config-repository

Target Revision: main

Path: applications/harness-gitops-demo/dev

Cluster: in-cluster

Namespace: gitops-dev

Manifest 类型由 Repo Server 根据目录内容处理。本例使用普通 Kubernetes YAML。


二十七:配置 Sync Policy

基础教程建议先使用手动同步:

Automatic Sync: Disabled

Prune: Disabled

Self Heal: Disabled

原因:

先观察 OutOfSync 手工确认差异 验证 Pipeline GitOpsSync 降低误删资源的风险

完成实验后,可以逐步开启:

Automatic Sync Self Heal Prune Apply Out Of Sync Only


二十八:Prune、Self Heal 的含义

Prune

如果 Git 中删除了某个资源,例如:

service.yaml 被删除

开启 Prune 后,GitOps 同步可以从集群删除这个 Service。

风险:

错误提交可能删除仍在使用的资源

建议:

dev/test 可在验证后开启 prod 开启前必须有 MR 审核、保护分支和删除保护策略


Self Heal

如果有人手工修改集群:

kubectl scale deployment harness-gitops-demo \
  --replicas=1 \
  -n gitops-dev

而 Git 中仍是:

replicas: 2

开启 Self Heal 后,Controller 可以重新恢复为两个副本。


二十九:第一次手工同步

创建 Application 后,初始状态通常可能是:

Sync Status: OutOfSync

进入 Application 页面,查看 App Diff。

确认差异后执行:

Sync → Synchronize

同步后检查:

kubectl get deployment -n gitops-dev
kubectl get pods -n gitops-dev
kubectl get service -n gitops-dev

期望 Harness 显示:

Sync Status: Synced

Health Status: Healthy


三十:Pipeline GitOps 流程设计

推荐 Pipeline:

Pipeline: harness-gitops-release

Stage 1: CI Test

  • npm install
  • npm test

Stage 2: Build And Push

  • docker build
  • docker push Harbor

Stage 3: Update GitOps Repository

  • clone GitOps Repository
  • 修改 Deployment image
  • 修改 ConfigMap APP_VERSION
  • git commit
  • git push

Stage 4: GitOps Sync

  • GitOpsSync
  • Wait Until Healthy
  • Fail If Step Times Out

Stage 5: Verify

  • 检查 Application 状态
  • 业务冒烟测试

GitOps 模式下不要再加入:

K8sRollingDeploy kubectl apply HelmDeploy

否则会形成两个部署控制源:

Pipeline 直接部署 GitOps Controller 同步

容易造成配置互相覆盖。


三十一:Pipeline 变量

variables:
  - name: app_name
    type: String
    value: harness-gitops-demo

  - name: deploy_env
    type: String
    value: dev

  - name: image_repository
    type: String
    value: harbor.company.com/devops/harness-gitops-demo

  - name: image_tag
    type: String
    value: <+input>

  - name: gitops_repo_url
    type: String
    value: https://gitlab.company.com/devops/harness-gitops-config.git

  - name: gitops_branch
    type: String
    value: main

  - name: gitops_manifest_path
    type: String
    value: applications/harness-gitops-demo/dev/deployment.yaml

  - name: gitops_configmap_path
    type: String
    value: applications/harness-gitops-demo/dev/configmap.yaml

三十二:更新 GitOps Repository 脚本

scripts/update-gitops-image.sh

#!/usr/bin/env bash
set -euo pipefail

GITOPS_REPO_URL="${GITOPS_REPO_URL:?GITOPS_REPO_URL is required}"
GITOPS_BRANCH="${GITOPS_BRANCH:-main}"

GIT_USERNAME="${GIT_USERNAME:?GIT_USERNAME is required}"
GIT_TOKEN="${GIT_TOKEN:?GIT_TOKEN is required}"
GIT_HOST="${GIT_HOST:?GIT_HOST is required}"

APP_NAME="${APP_NAME:?APP_NAME is required}"
DEPLOY_ENV="${DEPLOY_ENV:?DEPLOY_ENV is required}"

IMAGE_REPOSITORY="${IMAGE_REPOSITORY:?IMAGE_REPOSITORY is required}"
IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
IMAGE_FULL_NAME="${IMAGE_REPOSITORY}:${IMAGE_TAG}"

DEPLOYMENT_FILE="${DEPLOYMENT_FILE:?DEPLOYMENT_FILE is required}"
CONFIGMAP_FILE="${CONFIGMAP_FILE:?CONFIGMAP_FILE is required}"

WORK_DIR="$(mktemp -d)"
NETRC_FILE="${HOME}/.netrc"

cleanup() {
  rm -rf "${WORK_DIR}"
  rm -f "${NETRC_FILE}"
}

trap cleanup EXIT

if [ "${DEPLOY_ENV}" = "prod" ] && [ "${IMAGE_TAG}" = "latest" ]; then
  echo "ERROR: 生产环境禁止使用 latest"
  exit 1
fi

cat > "${NETRC_FILE}" <<EOF
machine ${GIT_HOST}
login ${GIT_USERNAME}
password ${GIT_TOKEN}
EOF

chmod 600 "${NETRC_FILE}"

git clone \
  --branch "${GITOPS_BRANCH}" \
  "${GITOPS_REPO_URL}" \
  "${WORK_DIR}/gitops-config"

cd "${WORK_DIR}/gitops-config"

test -f "${DEPLOYMENT_FILE}"
test -f "${CONFIGMAP_FILE}"

OLD_IMAGE="$(yq '.spec.template.spec.containers[0].image' "${DEPLOYMENT_FILE}")"

echo "OLD_IMAGE=${OLD_IMAGE}"
echo "NEW_IMAGE=${IMAGE_FULL_NAME}"

IMAGE_FULL_NAME="${IMAGE_FULL_NAME}" \
  yq -i \
  '.spec.template.spec.containers[0].image = strenv(IMAGE_FULL_NAME)' \
  "${DEPLOYMENT_FILE}"

IMAGE_TAG="${IMAGE_TAG}" \
  yq -i \
  '.data.APP_VERSION = strenv(IMAGE_TAG)' \
  "${CONFIGMAP_FILE}"

git diff -- "${DEPLOYMENT_FILE}" "${CONFIGMAP_FILE}"

if git diff --quiet; then
  echo "GitOps 配置没有变化,无需提交"
  exit 0
fi

git config user.name "Harness GitOps Bot"
git config user.email "harness-gitops-bot@company.com"

git add "${DEPLOYMENT_FILE}" "${CONFIGMAP_FILE}"

git commit -m "deploy(${DEPLOY_ENV}): ${APP_NAME} ${IMAGE_TAG}"

git push origin "${GITOPS_BRANCH}"

echo "GitOps Repository 更新完成"
echo "IMAGE_FULL_NAME=${IMAGE_FULL_NAME}"

三十三:在 Pipeline 中运行更新脚本

建议使用包含以下工具的企业内部镜像:

git yq bash ca-certificates

例如:

harbor.company.com/library/git-yq:latest

Run Step:

chmod +x scripts/update-gitops-image.sh

GITOPS_REPO_URL="<+pipeline.variables.gitops_repo_url>" \
GITOPS_BRANCH="<+pipeline.variables.gitops_branch>" \
GIT_HOST="gitlab.company.com" \
GIT_USERNAME="<+secrets.getValue('gitops_bot_username')>" \
GIT_TOKEN="<+secrets.getValue('gitops_bot_token')>" \
APP_NAME="<+pipeline.variables.app_name>" \
DEPLOY_ENV="<+pipeline.variables.deploy_env>" \
IMAGE_REPOSITORY="<+pipeline.variables.image_repository>" \
IMAGE_TAG="<+pipeline.variables.image_tag>" \
DEPLOYMENT_FILE="<+pipeline.variables.gitops_manifest_path>" \
CONFIGMAP_FILE="<+pipeline.variables.gitops_configmap_path>" \
scripts/update-gitops-image.sh

不要开启:

set -x

否则 Secret 有被输出到日志的风险。


三十四:生产环境不要直接推 main

为了简化实验,dev 可以让 Pipeline 直接推送到配置仓库。

生产推荐:

Pipeline 创建发布分支 ↓ 修改生产 Manifest ↓ 创建 Merge Request ↓ 质量门检查 ↓ 生产负责人审批 ↓ 合并 main ↓ GitOps Sync

生产配置仓库应启用:

保护分支 禁止 Force Push 至少一人或两人 Review CODEOWNERS 提交签名,可选 敏感文件扫描 YAML 校验 OPA/Kyverno 策略检查


三十五:在 Pipeline 中添加 GitOpsSync

创建 Deployment Stage,并选择与 Application 一致的:

Service: harness-gitops-demo

Environment: dev

Cluster: in-cluster

进入 Execution:

Add Step → GitOpsSync

配置:

Application Selection: Application Name

Application: harness-gitops-demo-dev

Wait Until Healthy: Enabled

Fail If Step Times Out: Enabled

Timeout: 10m 或 15m

初次实验建议:

Prune: Disabled

Force: Disabled

Replace: Disabled

具体可见选项会随 Harness 版本和 Application 配置变化。


三十六:GitOpsSync YAML 参考

GitOpsSync 的 YAML 字段可能随 Harness 版本、Application 选择方式和 Sync Options 变化。

建议先在 Visual Editor 配置成功,再导出实际 YAML。

结构示意:

- step:
    type: GitOpsSync
    name: Sync GitOps Application
    identifier: sync_gitops_application
    timeout: 15m
    spec: {}

不要根据示意 YAML 猜测完整字段。

在 UI 中重点确认:

应用选择正确 Service、Environment、Cluster 与 Application 一致 Wait Until Healthy 已开启 Fail If Step Times Out 已开启 同步超时时间合理


三十七:为什么要开启 Wait Until Healthy

只完成 Sync,不等于业务已经正常。

例如:

Manifest 已成功提交到 Kubernetes Deployment 已创建 Pod 仍然 ImagePullBackOff readinessProbe 失败 应用一直 CrashLoopBackOff

如果不等待 Healthy,Pipeline 可能在业务不可用时显示成功。

推荐:

dev/test: Wait Until Healthy = true

pre/prod: Wait Until Healthy = true Fail If Step Times Out = true


三十八:验证 Pipeline 发布结果

Pipeline 完成后检查 Git:

git log --oneline -5

检查 Manifest:

grep image: \
  applications/harness-gitops-demo/dev/deployment.yaml

检查 Kubernetes:

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev \
  -o wide

kubectl get pods \
  -n gitops-dev \
  -l app=harness-gitops-demo

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev \
  -o jsonpath='{.spec.template.spec.containers[0].image}'

检查业务:

kubectl port-forward \
  service/harness-gitops-demo \
  18080:80 \
  -n gitops-dev

另一个终端:

curl -f http://127.0.0.1:18080/health
curl -f http://127.0.0.1:18080/

三十九:GitOps 状态说明

Synced + Healthy

Git 与集群状态一致 资源运行正常

这是正常状态。


OutOfSync + Healthy

业务当前可以运行 但集群状态与 Git 不一致

常见原因:

Git 已修改但尚未同步 有人手工修改集群 外部 Controller 修改了资源


Synced + Progressing

配置已经应用 但 Deployment 正在发布


Synced + Degraded

配置已经应用 但业务资源运行异常

常见原因:

镜像不存在 镜像拉取失败 容器启动失败 readinessProbe 失败 资源限制不足 应用依赖不可用


Unknown

Agent 无法完整读取 Git 或 Cluster 状态

常见原因:

Git Repository 不可访问 Cluster 凭证失效 Agent 异常 Repo Server 异常 网络超时


四十:测试 Drift Detection

先确认 Git 中:

replicas: 2

手工修改集群:

kubectl scale deployment \
  harness-gitops-demo \
  --replicas=1 \
  -n gitops-dev

检查:

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev

回到 Harness Application 页面,执行 Refresh。

预期:

Application = OutOfSync

如果 Self Heal 未开启,副本数会暂时保持为 1。

执行 Sync 后:

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev

副本数应重新恢复到 2。

开启 Self Heal 后再次测试,Controller 应能自动纠正漂移。


四十一:GitOps 正确回滚方式

传统 Kubernetes 回滚可能使用:

kubectl rollout undo deployment/harness-gitops-demo

但在 GitOps 中,这不是推荐的最终回滚方式。

原因:

kubectl rollout undo 只修改集群 Git 仍然指向新版本 Application 会变成 OutOfSync 下一次 Sync 可能再次部署新版本

GitOps 推荐:

找到修改镜像的 Git Commit ↓ git revert ↓ 推送回配置仓库 ↓ GitOpsSync ↓ 集群恢复旧版本


四十二:Git revert 回滚示例

查看历史:

git log --oneline -10

假设错误发布 Commit:

abc1234 deploy(dev): harness-gitops-demo v1.2.0

执行:

git revert abc1234
git push origin main

然后重新运行 GitOpsSync。

验证:

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev \
  -o jsonpath='{.spec.template.spec.containers[0].image}'

这样 Git 历史会保留:

发布 v1.2.0 回滚 v1.2.0 恢复到上一版本

整个过程可审计、可复现。


四十三:Pipeline 自动回滚到上一 Git Commit

可以在 Pipeline 中准备一个人工回滚流程:

输入 rollback_commit ↓ 创建 Revert Commit ↓ 推送 GitOps Repository ↓ GitOpsSync ↓ 等待 Healthy

示例脚本:

#!/usr/bin/env bash
set -euo pipefail

ROLLBACK_COMMIT="${ROLLBACK_COMMIT:?ROLLBACK_COMMIT is required}"

git revert \
  --no-edit \
  "${ROLLBACK_COMMIT}"

git push origin main

生产环境不要让流水线任意执行:

git reset --hard
git push --force

Force Push 会破坏审计历史。


四十四:自动同步与手动同步如何选择

dev

推荐:

Automatic Sync: Enabled

Self Heal: Enabled

Prune: 验证后开启

适合快速反馈。


test

推荐:

Automatic Sync: 可选

Self Heal: Enabled

Prune: 谨慎开启


pre

推荐:

Manual Sync 或 Pipeline GitOpsSync 必须审批 Wait Until Healthy


prod

推荐:

配置变更必须 MR 合并前必须审批 通过 Pipeline GitOpsSync 同步 Wait Until Healthy Fail If Step Times Out Prune 需要严格治理

不要只依赖“任何 main Commit 自动进入生产”。


四十五:GitOps 配置仓库校验

建议为 GitOps Repository 增加 CI。

检查 YAML:

find applications \
  -name "*.yaml" \
  -o -name "*.yml" \
  | xargs -r yamllint -d relaxed

执行客户端 Dry Run:

kubectl apply \
  --dry-run=client \
  -f applications/harness-gitops-demo/dev

使用 kubeconform:

kubeconform \
  -strict \
  -summary \
  applications/harness-gitops-demo/dev/*.yaml

检查生产 latest:

if grep -RIn 'image:.*:latest' applications/*/prod; then
  echo "ERROR: prod 禁止使用 latest"
  exit 1
fi

检查明文 Secret:

grep -RInE \
  'password:|token:|secretKey:|accessKey:' \
  applications \
  && exit 1 || true

四十六:GitOps 仓库权限设计

GitOps Agent 读取账号

权限:

只读配置仓库

Harness Pipeline Bot

dev 可配置:

允许推送 dev 配置

生产推荐:

只能创建分支和 Merge Request 不能直接推送保护分支

开发人员

建议:

可以修改自己服务目录 不能修改其他服务 生产目录需要 CODEOWNERS

平台团队

负责:

目录规范 同步策略 Application Agent Cluster RBAC 基础策略


四十七:Agent 权限设计

基础实验中可能使用较高权限,但生产应收紧。

推荐按以下边界拆分:

dev Agent: 只管理 dev Namespace 或 dev Cluster

test Agent: 只管理 test Namespace 或 test Cluster

prod Agent: 只管理 prod Cluster

不要让一个开发环境 Agent 同时拥有:

所有生产集群 cluster-admin

如果使用 Namespaced Agent,需要确认:

Agent 访问范围 CRD 是否已安装 目标 Namespace Repository 和 Cluster 配置 Application 是否只管理允许的资源


四十八:国内网络环境问题

1. Agent 镜像拉取失败

表现:

ImagePullBackOff ErrImagePull i/o timeout

解决:

把 Agent 和 Argo CD 镜像同步到 Harbor 配置私有镜像地址 创建 imagePullSecret 检查节点到 Harbor 的网络 配置企业 CA


2. GitLab 连接失败

表现:

repository not found authentication required x509 unknown authority connection timeout

排查:

kubectl exec \
  deployment/argocd-repo-server \
  -n harness-gitops \
  -- sh

容器内检查:

wget -S -O - https://gitlab.company.com 2>&1 | head

更推荐直接查看 Repo Server 日志:

kubectl logs \
  deployment/argocd-repo-server \
  -n harness-gitops \
  --tail=300

3. Harbor 镜像拉取失败

检查:

kubectl describe pod POD_NAME -n gitops-dev

kubectl get secret \
  harbor-pull-secret \
  -n gitops-dev

常见原因:

Secret 不在目标 Namespace Robot Token 失效 镜像 Tag 不存在 节点不信任 Harbor CA


4. Harness SaaS 连接失败

查看 Agent 日志:

kubectl logs \
  deployment/gitops-agent \
  -n harness-gitops \
  --tail=300

检查:

企业防火墙 HTTPS 代理 DNS NO_PROXY 系统时间 证书链


5. Application 一直 OutOfSync

检查:

Repository Revision 是否正确 Path 是否正确 Namespace 是否正确 App Diff 具体内容 是否有 Mutating Webhook 修改字段 是否有 HPA 修改 replicas 是否有其他 Controller 修改资源

如果 HPA 管理副本数,应考虑忽略由 HPA 管理的差异,而不是反复让两个 Controller 互相修改。


四十九:常见问题排查

1. Agent 状态不健康

kubectl get pods -n harness-gitops
kubectl get events -n harness-gitops \
  --sort-by=.metadata.creationTimestamp

逐个查看:

kubectl logs deployment/gitops-agent -n harness-gitops
kubectl logs deployment/argocd-repo-server -n harness-gitops
kubectl logs statefulset/argocd-application-controller -n harness-gitops

2. Application 显示 Missing

可能原因:

资源被手工删除 目标 Namespace 错误 Application Path 中已删除资源 集群访问权限不足

执行 Refresh 后查看 App Diff。


3. Sync 成功但 Pipeline 超时

可能是:

Application 已同步 但一直没有达到 Healthy

检查:

kubectl get pods -n gitops-dev
kubectl describe deployment harness-gitops-demo -n gitops-dev
kubectl get events -n gitops-dev \
  --sort-by=.metadata.creationTimestamp

通常原因是:

镜像拉取失败 readinessProbe 错误 资源不足 应用启动过慢 依赖服务不可用


4. Pipeline 更新 Git 后 Application 没变化

检查:

Application Target Revision Application Path Pipeline 推送的分支 Git Commit 是否真正成功 Repository 是否读取到新 Commit

在 Harness Application 页面执行:

Refresh

Refresh 只刷新状态,不等同于 Sync。


五十:企业最佳实践

1. 应用仓库与配置仓库分离

推荐:

应用仓库: 源码、测试、Dockerfile

配置仓库: Kubernetes、Helm、Kustomize、环境配置


2. 镜像 Tag 必须不可变

推荐:

v1.2.0 main-a1b2c3d-102 release-20260715-001

禁止生产使用:

latest prod stable


3. 生产通过 MR 更新 GitOps 仓库

推荐:

Build ↓ Scan ↓ 创建 GitOps MR ↓ 审批 ↓ 合并 ↓ GitOpsSync


4. 不允许多个系统同时管理同一资源

不要同时使用:

Harness K8sRollingDeploy Argo CD GitOps Sync 手工 kubectl apply Helm CLI

管理同一个 Deployment。

每个资源应明确唯一控制者。


5. 回滚必须回到 Git

短期紧急操作可以在集群中止损,但最终必须:

把正确状态提交回 Git

否则 GitOps Controller 后续仍会按 Git 重新同步。


6. Application 必须设置健康检查

Deployment 应配置:

readinessProbe livenessProbe resources

否则 Application 的 Healthy 状态不能完整代表业务可用。


7. 监控 Agent

至少监控:

Agent Connected 状态 Repo Server 错误率 Application Controller 状态 同步失败次数 OutOfSync Application 数量 Degraded Application 数量 Redis 状态 Agent Pod 重启次数


五十一:练习 1:安装 GitOps Agent

目标:

Agent 在 harness-gitops Namespace 正常运行。

步骤:

  1. 在 Harness 创建 Agent
  2. 下载 override.yaml 或 gitops-agent.yaml
  3. 使用 Helm 或 kubectl 安装
  4. 检查 Pod
  5. 在 Harness 确认 Healthy 和 Connected

验收:

kubectl get pods -n harness-gitops

所有核心组件正常运行。


五十二:练习 2:创建 Repository 和 Application

目标:

创建 harness-gitops-demo-dev Application。

步骤:

  1. 创建 GitOps Repository
  2. 使用 in-cluster
  3. 创建 Service 和 Environment
  4. 创建 Application
  5. 设置 main 分支
  6. 设置 dev Manifest 路径
  7. 手工 Sync

验收:

Application = Synced Application = Healthy


五十三:练习 3:Pipeline 更新镜像并同步

目标:

Pipeline 把镜像从 v1.0.0 更新到 v1.1.0。

步骤:

  1. 构建 v1.1.0 镜像
  2. 推送到 Harbor
  3. 更新 Deployment image
  4. 提交 GitOps Repository
  5. 执行 GitOpsSync
  6. 等待 Healthy

验收:

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev \
  -o jsonpath='{.spec.template.spec.containers[0].image}'

输出为:

harbor.company.com/devops/harness-gitops-demo:v1.1.0


五十四:练习 4:验证 Drift Correction

目标:

手工修改副本数,并让 GitOps 恢复期望状态。

执行:

kubectl scale deployment \
  harness-gitops-demo \
  --replicas=1 \
  -n gitops-dev

观察:

Application 变成 OutOfSync

执行 Sync 或开启 Self Heal。

验收:

kubectl get deployment \
  harness-gitops-demo \
  -n gitops-dev

副本数重新恢复为 Git 中声明的数量。


五十五:练习 5:Git revert 回滚

目标:

把错误镜像版本回滚到上一版本。

步骤:

  1. 找到镜像更新 Commit
  2. 执行 git revert
  3. 推送 main
  4. 执行 GitOpsSync
  5. 等待 Healthy

验收:

Git 中为旧镜像 集群中为旧镜像 Application = Synced Application = Healthy


五十六:验收标准

完成本文后,应达到:

已理解 GitOps 基本原理 已理解 Desired State 和 Live State 已理解 Synced、OutOfSync、Healthy、Degraded 已能安装 Harness GitOps Agent 已能检查 Agent 和 Argo CD 组件 已能添加 GitOps Repository 已能使用 in-cluster 或配置目标 Cluster 已能创建 Service、Environment 和 Application 已能手工执行 Sync 已能在 Pipeline 中更新 GitOps 配置仓库 已能配置 GitOpsSync 已能等待 Application Healthy 已能验证 Drift Correction 已能通过 git revert 完成回滚 已能处理国内网络和私有仓库问题


五十七:本篇总结

本篇完成了 Harness GitOps 的基础落地。

需要重点记住:

Git 是期望状态的单一事实来源 Pipeline 负责构建、测试和更新 Git GitOps Agent 与 Argo CD 负责同步集群 GitOps Agent 不等于 Harness Delegate Application 连接 Repository、Cluster 和 Agent Refresh 只刷新状态,Sync 才应用变更 Synced 不一定等于 Healthy Pipeline 中应开启 Wait Until Healthy 不要让 GitOps 和普通 CD 同时管理同一资源 生产配置应通过 Merge Request 变更 GitOps 回滚应使用 git revert Self Heal 可以纠正手工集群漂移 Prune 可能删除资源,生产开启前必须严格治理 国内环境要提前解决镜像、代理、证书和私有 Git 访问

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐