OpenShift GitOps:从 Operator 安装到 Argo CD 多集群治理
一个 OpenShift 集群升级后,GitOps Operator 的 CSV 显示 Succeeded,默认 Argo CD 的 Pod 也全部 Ready,几个 Application 却同时变成 Unknown。排查发现 Subscription 跟随宽泛 channel 自动批准了新 InstallPlan,ApplicationSet 引用的 SCM Secret 没有新版本要求的类型标签。Operator 安装成功只证明 OLM 完成了更新图中的动作,并不证明仓库渲染、目标权限与应用调谐仍然兼容。
另一次下线更具迷惑性。管理员从 OperatorHub 卸载了 GitOps Operator,期待所有组件随之消失,结果 openshift-gitops 中的 Argo CD instance 和已管理的应用仍在。随后人工删除 CRD,又让带 finalizer 的 Application 失去正常收尾机会。Operator、operand、Application 所有权和下游资源是不同生命周期,必须按顺序停写、转交、撤销凭证,再清理平台对象。
把 Operator 层和 Argo CD 层分开观察
Red Hat OpenShift GitOps 是以 Argo CD 为声明式引擎的 Red Hat 下游 Operator 产品,并与 OpenShift Container Platform 独立发版。OLM 层的 CatalogSource、OperatorGroup、Subscription、InstallPlan 和 ClusterServiceVersion(CSV)负责选择 channel、解析升级图、安装 Operator 及 CRD/RBAC。GitOps Operator 再读取 GitOpsService 与 ArgoCD CR,生成 application-controller、repo-server、server、Redis、ApplicationSet、SSO、Route 等 operand。产品说明把它定义为 OpenShift 上受支持的 GitOps 产品,而不是一份上游 Argo CD 安装脚本。上游 Argo CD 已有某项能力,不等于当前 GitOps channel 已打包、启用或支持;反过来,Red Hat 的 Operator、OAuth、Route、RHACM 与 Agent 集成也不能作为上游 Argo CD 的通用行为。
Argo CD 层中,Application 把 repo/path/revision/renderer 与 destination cluster/namespace 绑定为持续调谐单元;AppProject 限制 source、destination、资源种类、角色与同步窗口;ApplicationSet 用 generator/template 批量生成 Application,本身不执行最终 apply。repository Secret 和 cluster Secret 分别保存源与传统 push 目标的凭证。Operator 生成 operand,ApplicationSet 生成 Application,Application 再拥有目标资源 inventory;这些派生层各有自己的 owner、generation、condition 与删除传播,不能把最上层绿色状态当成下层已经收敛。理解这些层级后,故障定位才不会从 CSV Succeeded 直接跳到业务结论。
默认 Operator namespace 是 openshift-gitops-operator,默认 cluster-scoped Argo CD instance 位于 openshift-gitops。默认实例拥有额外的集群级能力;用户自建 instance 默认只管理自身 namespace。对 Argo CD namespace 中 Secret、Pod 或 exec 的访问几乎等价于高权限 Argo CD 管理能力,不能仅依赖 Argo CD UI 的角色隐藏风险。Argo CD instance说明了默认与自建实例的差异。
用明确 channel 和 Manual approval 安装
安装者需要 OpenShift 管理员权限,并确保 Marketplace capability 可用,或已手工配置 Red Hat Operator CatalogSource。若集群中存在 Community Argo CD Operator,应先移除并确认其 operand/CRD 所有权,避免两个 Operator 同时调谐相同 API。生产安装使用明确 minor channel 与 Manual approval,先审阅 InstallPlan 中的 CSV、RBAC 和 CRD 变化,再批准;latest 与自动批准不适合作为长期锁定策略。安装指南给出了 OperatorHub 与 CLI 入口。
下面示例固定到 GitOps 1.21 channel。该 channel 只代表 Red Hat OpenShift GitOps 发行线,不能推导任意上游 Argo CD 或其他 OpenShift 版本的兼容性:
apiVersion: v1
kind: Namespace
metadata:
name: openshift-gitops-operator
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: openshift-gitops-operator
namespace: openshift-gitops-operator
spec:
upgradeStrategy: Default
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: openshift-gitops-operator
namespace: openshift-gitops-operator
spec:
channel: gitops-1.21
installPlanApproval: Manual
name: openshift-gitops-operator
source: redhat-operators
sourceNamespace: openshift-marketplaceoc apply -f subscription.yaml
oc -n openshift-gitops-operator get subscription,installplan,csv
oc -n openshift-gitops-operator get installplan <install-plan> -o yaml
oc -n openshift-gitops-operator patch installplan <install-plan> \
--type merge -p '{"spec":{"approved":true}}'
oc -n openshift-gitops-operator get csv
oc get crd | grep -E 'argoproj.io|pipelines.openshift.io'
oc -n openshift-gitops get argocd,pod,route批准前应保存 CSV requested permissions、owned CRD 与目标 release notes;批准后确认 Subscription Up to date、CSV Succeeded、CRD Established、Operator Pod Ready,并继续确认 GitOpsService cluster 与默认 ArgoCD instance 的生成链。OLM 的成功状态只覆盖安装事务,不覆盖 repo render、sync、SSO、target RBAC 或业务响应。Operator 用户任务也提醒自动批准会跳过人工审查权限变化。
用 ArgoCD CR 定义实例而不是手改生成资源
平台团队通常为不同租户或故障域创建独立 Argo CD instance,而不是把所有仓库、cluster credential 和管理员放进默认实例。ArgoCD CR 声明组件、副本、资源限制、Route、SSO、RBAC 和 ApplicationSet 等能力;Operator 会把声明持续调谐到 Deployment、Service、Role、ConfigMap 与 Secret。直接修改 Operator 生成的 Role、ClusterRole 或 Deployment,下一轮 reconcile 会把它改回去。
apiVersion: v1
kind: Namespace
metadata:
name: team-orders-gitops
---
apiVersion: argoproj.io/v1beta1
kind: ArgoCD
metadata:
name: orders
namespace: team-orders-gitops
spec:
server:
route:
enabled: true
rbac:
defaultPolicy: role:readonly
policy: |
p, role:orders-admin, applications, *, orders/*, allow
g, orders-platform-admins, role:orders-admin
applicationSet:
enabled: true创建后观察 ArgoCD conditions、各组件 Deployment 的 observed generation 和 Operator 日志。需要 cluster-scoped 权限时,应新建独立 ClusterRole/ClusterRoleBinding 绑定该 instance 的 application-controller ServiceAccount,而不是改生成对象。默认 instance 也不是无条件 cluster-admin,它只内建了特定集群级资源能力。声明式集群配置展示了显式扩权方式。
如果不需要默认实例,可通过 DISABLE_DEFAULT_ARGOCD_INSTANCE=true 阻止它启动,但要先确认已有 Application、Route、SSO 与凭证的归属。把默认实例停掉并不会自动把这些对象迁入自建 instance。
用 AppProject 收紧仓库、目标与资源种类
default AppProject 若不收紧,通常允许广泛 source、destination 与资源种类。共享集群中应先建受限 AppProject,再让非管理员创建 Application。下面把 source 固定到一个仓库,把 destination 固定到本集群的 orders-dev,并拒绝所有 cluster-scoped 资源:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: orders
namespace: team-orders-gitops
spec:
sourceRepos:
- https://git.example.invalid/platform/orders-config.git
destinations:
- server: https://kubernetes.default.svc
namespace: orders-dev
clusterResourceBlacklist:
- group: '*'
kind: '*'
namespaceResourceWhitelist:
- group: '*'
kind: '*'
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: orders-dev
namespace: team-orders-gitops
spec:
project: orders
source:
repoURL: https://git.example.invalid/platform/orders-config.git
targetRevision: main
path: deploy/overlays/dev
destination:
server: https://kubernetes.default.svc
namespace: orders-dev
syncPolicy:
automated:
prune: false
selfHeal: true首次实验保持 prune: false,先证明 source、render、diff、apply 和 health,再单独审查删除语义。正向路径应创建 namespaced 对象并得到业务响应;反向路径分别把 repoURL 改成未授权仓库、namespace 改成 orders-prod、加入 ClusterRole,预期在 project policy 或 target RBAC 层失败。每次只改一个变量并保存 Application condition、controller 日志、目标对象存在性与真实请求。
Applications 或 ApplicationSets 放在 control-plane namespace 之外时,需要在 ArgoCD.spec.sourceNamespaces 与 spec.applicationSet.sourceNamespaces 显式开放,Operator 会据此创建 RoleBinding。argocd.argoproj.io/managed-by 也会形成 namespace 委派。宽泛 wildcard/regex 可能覆盖系统 namespace,而 namespace-admin 本身可修改 NetworkPolicy 等敏感对象,因此委派必须和 AppProject、目标 ServiceAccount 一起收紧。ApplicationSet 文档列出了这些 namespace 能力的 Feature Stage;其中 ApplicationSet in any namespace 在 GitOps 1.21 仍是 Technology Preview,不能因上游已有实现就宣称 Red Hat GA。
传统 push 与 Agent pull 是两种故障域
传统模式由 hub 上的 application-controller 直接调用下游 Kubernetes API,hub 保存 cluster credential Secret,也必须能连通下游 API。其优点是视图和执行集中,代价是下游凭证集中、网络暴露和中心 controller 故障域扩大。撤销目标 ServiceAccount 权限后,Application 应出现 permission condition;这类错误不能通过重建 repo-server 修复。
Argo CD Agent 模式把本地 Argo CD instance 放到 workload cluster,agent 与 principal 建立受控连接,control plane 不需要下游 kubeconfig 或 API access。managed mode 以 control plane 的 Application definitions 为权威,autonomous mode 则由 workload cluster 持有 Application source of truth。断开 agent/principal 链路时,要分别检查本地 reconcile 是否继续、中央 Application 状态是否陈旧,而不能把“中央不可见”误判为“业务已停止”。Agent 架构列出了 principal 非 HA、部分 ApplicationSet、日志终端与高级多租户等限制。
GitOps 1.21 支持矩阵把 Argo CD Agent 组件列为 GA,但该发行线新增的 hybrid Agent architecture 仍是 Technology Preview。组件阶段和具体架构阶段必须分别判断,GA 不表示与传统模式功能完全对等。1.21 release notes是这两个结论的同一版本依据。
RHACM 用 Placement 选择集群
OpenShift GitOps 自身没有 Fleet ClusterGroup 的同名对象。接入 Red Hat Advanced Cluster Management 后,cluster-scoped ManagedClusterSet 聚合集群,ManagedClusterSetBinding 把集合授权给 workload namespace,namespace-scoped Placement 按 label、predicate 与 prioritizer 产生 PlacementDecision,同 namespace 的 GitOpsCluster 再把选择结果注册到指定 GitOps instance,或启用 GitOps add-on。RHACM GitOps与Placement给出了这条对象链。
push 路径通常使用轮换的 ManagedServiceAccount token 访问目标;pull add-on 可在选中 cluster 安装 OpenShift GitOps Operator、本地 Argo CD instance,并可选 Argo CD Agent。启用 GitOpsCluster.spec.gitopsAddon 会为所有 Application 禁用 push model,不能把它理解为“额外安装一个 agent,原 push 仍然不变”。RHACM 还是额外产品路径,不会随 OpenShift GitOps Operator 自动出现。
实验时先记录 PlacementDecision 与注册产生的 cluster Secret 或 add-on 对象,再只修改一个 managed cluster label。预期被移出的 cluster 按注册/注销策略收敛,被加入的 cluster 得到新凭证或 add-on。反例是把 GitOpsCluster 放到另一个 namespace,预期无法正确引用 Placement。任何 selector 变化都先限制在 canary set,因为错误 Placement 可能同时撤销大量目标。
调谐证据必须一直走到真实请求
一次成功发布至少保存六层证据:Subscription/CSV 与 Operator 版本;ArgoCD CR generation 和组件版本;Application source revision 与 render 结果;desired/live diff 与 sync history;运行 Deployment 镜像 digest、ConfigMap/Secret 引用、Pod/Service 状态;带 request ID 的业务响应。Synced 只表示期望与 live 的比较结果,Healthy 是资源健康评估,二者都不验证业务依赖、数据兼容或真实用户路径。
遇到异常时从 condition 分型。repo fetch/auth 失败先查 repository Secret 与 repo-server;manifest generation 失败查 renderer 版本、插件和 schema;project deny 查 AppProject;apply permission deny 查 application-controller 或目标 ServiceAccount;对象已同步但 Progressing/Degraded 查工作负载 rollout;全部绿色而请求失败则查 Route、Service、依赖和应用日志。不要把不同层的错误汇总成一句“Argo CD 同步失败”。
ApplicationSet 的 generator 只决定生成哪些 Application。Progressive Sync 的 RollingSync 按生成 Application 的 labels 分组推进;未被任何 step selector 命中的 Application 不会自动更新。反向实验可故意遗漏 prod label 的 step,预期 dev 前进而 prod revision 不变。这个机制不是 RHACM Placement,也不是下游资源级 canary,真实业务验证仍要在每个 Application 之后完成。
四套 RBAC 共同形成租户边界
OpenShift/Kubernetes RBAC 控制谁能访问 Operator namespace、Argo CD namespace、Application/AppProject/ApplicationSet、repository/cluster Secret,以及 application-controller 在目标 cluster 的权限。Argo CD RBAC 控制 UI/API 中 application、project、cluster、repository 等动作。AppProject 再限制 source、destination、资源 allow/deny、project role 与 sync window。namespace delegation 最后决定哪些 namespace 可以提交 Application 或 ApplicationSet。这四套授权缺一不可。访问控制给出了产品侧配置入口。
不要依赖 application 名称前缀或 UI project filter 做隔离。不同租户使用独立 Argo CD instance、收紧的 AppProject 和最小 target ServiceAccount;cluster credential Secret 需要轮换、过期与撤销,RHACM 场景可使用 ManagedServiceAccount add-on 轮换 token。repository、SCM 与 PR generator Secret 不进入 Git,也不得出现在 diff、日志和支持包中。Secret 的 base64 不是加密,能读取 Argo CD namespace Secret、exec 进入 repo-server、读取 Redis 缓存或运行高权限配置管理插件的主体,可能直接接触仓库凭证或渲染后的明文;因此 Kubernetes RBAC、支持包脱敏和插件隔离要与 Argo CD RBAC 同时审查。
GitOps 1.21 中,当 ArgoCD.spec.applicationSet.sourceNamespaces 非空时,ApplicationSet tokenRef strict mode 默认开启,SCM Provider/PR generator 引用的 Secret 必须带 argocd.argoproj.io/secret-type: scm-creds 标签。这个要求是该发行线的升级门禁,不应泛化成所有上游 Argo CD 版本的固定规则。
按联合支持矩阵选择下游组合
OpenShift GitOps 的版本判断必须同时看 GitOps 发行线、OCP z-stream、内含组件版本和具体 Feature Stage。Red Hat GitOps 1.21.1 的支持信息列出 OCP 4.18 至 4.22;1.21.0 组件矩阵列出 Argo CD/CLI 3.4.3、Helm 3.19.4、Kustomize 5.8.1、Argo Rollouts 1.9.0、Dex 2.45.0、Agent 0.9.0 与 Image Updater 1.2.1。这些数字只描述该 Red Hat 产品发行线,具体 z-stream 仍要查兼容与支持矩阵,不能外推为上游或下一发行线承诺。
同一矩阵还区分 GA 与 Technology Preview:GitOps CLI 和 Image Updater 在 1.21 转为 GA,而 Progressive Sync、Applications/ApplicationSets in any namespace 等各有独立阶段。Keycloak-based authentication 从 GitOps 1.18 起不再受支持,应迁移到 Dex 或自管 Red Hat Build of Keycloak。支持状态会改变升级、事故支持和长期维护责任,不能只比较功能是否能开启。OpenShift Operator 生命周期用于判断产品支持周期。
升级前先扫描 breaking gate
先盘点 OCP、Subscription channel、CSV、全部 ArgoCD/GitOpsService/ApplicationSet/Application/AppProject/ImageUpdater、repository/cluster Secret、RHACM Placement/GitOpsCluster/add-on 与 Agent。根据目标 OCP 反查 GitOps compatibility matrix,确认存在有效 OLM update path;OpenShift minor 升级前,先把 Operators 放到与目标 OCP 兼容的版本。
Manual approval 下审阅 InstallPlan 与 CSV RBAC/CRD 变化,并在非生产 instance 验证 Operator reconcile、repo render、sync/diff/prune、SSO/RBAC、cluster credential、ApplicationSet generator、Agent 与 RHACM registration。GitOps 1.21 的具体预检还包括:SCM tokenRef Secret 类型标签;删除已废弃的 ImageUpdater.spec.namespace,改用 metadata.namespace;把 logformat 迁到 logFormat;停止依赖已弃用的 controller dynamic shard scaling。breaking changes是这些扫描项的版本依据。
预检可以故意保留一个未标记的 SCM Secret 和旧 ImageUpdater 字段,确认策略或 dry-run 能在批准前阻断;修复后再批准 InstallPlan。升级后不仅检查 CSV Succeeded,还要检查 Operator、Argo CD、Redis、repo-server、ApplicationSet、Agent Pod,CR Established,以及 Applications 是否出现新的 Unknown、OutOfSync 或 permission deny。下游按 cohort 验证断网恢复、credential rotation、orphan/prune、hook/finalizer 和真实请求。
迁移和清理从停止调谐开始
迁移前冻结新的 Application、ApplicationSet 与 GitOpsCluster 变更,关闭 automated sync/self-heal/prune,或先把 source authority 交给新 owner。逐 Application 决定 cascade delete 还是 orphan/转交,并在修改 finalizer 前记录资源 inventory。传统 push 模式先让新 controller 接管下游对象,再删除 cluster Secret 或 ManagedServiceAccount binding,并从审计日志证明 hub 不再访问下游 API。
Agent/add-on 模式先迁移 Application authority,停止 agent application 并同步最后状态,再删除 RHACM GitOpsCluster、相关 ManagedClusterAddOn/AddOnDeploymentConfig,最后卸载下游 Argo CD 与 Operator。RHACM add-on 的完整卸载要求先删 GitOpsCluster,再删除各 managed cluster namespace 的 ManagedClusterAddOn gitops-addon 并确认消失;它与单集群删除 GitOpsService cluster 是两条路径。
Red Hat 明确说明只卸载 GitOps Operator 不会删除其创建的 Argo CD instances。单集群应先删除用户自建与默认 Argo CD instances,等待 controller、repo-server、Redis、server、ApplicationSet/notifications、Route/Service、RBAC 与 finalizer 清理;再删除 GitOpsService cluster,最后卸载 Subscription/CSV。移除 GitOps给出了 Operator 与 operand 分离的关键顺序。
不要直接删除 CRD,除非所有 CR 与数据语义已经核销。最终还要撤销 Git/Helm/OCI/webhook/cluster/agent token,清理 namespace label、RoleBinding、ClusterRoleBinding、Route、PVC、Secret、monitoring rule、console plugin 与 orphan resource。以对象清单、凭证撤销记录、API 审计和真实请求共同证明新 owner 已接管或工作负载已删除,迁移才算结束。
