ArgoCD in OpenShift Container Platform (OCP)
ArgoCD is a declarative, GitOps-based continuous delivery tool for Kubernetes. In OpenShift, it is available as the OpenShift GitOps operator — a Red Hat supported, enterprise-grade distribution of ArgoCD that integrates natively with OCP’s RBAC, SSO, and multi-cluster capabilities.
What is GitOps?
ArgoCD implements the GitOps pattern — Git is the single source of truth for all cluster state:
Traditional CD: GitOps with ArgoCD:Pipeline pushes to cluster Git repo defines desired state ↓ ↓Imperative: "run this command" ArgoCD pulls + compares continuously ↓ ↓No drift detection Detects and corrects drift automatically ↓ ↓Audit trail in pipeline logs Full audit trail in Git history ↓ ↓Hard to reproduce state Cluster state is always reproducible
Installing ArgoCD on OCP — OpenShift GitOps Operator
# Install via OperatorHub (or apply YAML directly)cat <<EOF | oc apply -f -apiVersion: operators.coreos.com/v1alpha1kind: Subscriptionmetadata: name: openshift-gitops-operator namespace: openshift-operatorsspec: channel: latest name: openshift-gitops-operator source: redhat-operators sourceNamespace: openshift-marketplaceEOF# Operator automatically creates:# - openshift-gitops namespace# - ArgoCD instance: openshift-gitops# - Route for ArgoCD UI# - ClusterRoleBinding for ArgoCD to manage the cluster# Get ArgoCD UI URLoc get route openshift-gitops-server \ -n openshift-gitops \ -o jsonpath='{.spec.host}'# Get initial admin passwordoc extract secret/openshift-gitops-cluster \ -n openshift-gitops \ --to=-
Core ArgoCD Concepts in OCP
1. Application CRD
The Application is the fundamental ArgoCD resource — it links a Git source to a cluster destination:
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: payment-service namespace: openshift-gitops # always in ArgoCD namespace finalizers: - resources-finalizer.argocd.argoproj.io # cascade deletespec: project: team-payments # AppProject for RBAC source: repoURL: https://github.com/contoso/gitops-repo targetRevision: main # branch, tag, or commit SHA path: apps/payment-service/overlays/production destination: server: https://kubernetes.default.svc # local cluster namespace: payments-prod syncPolicy: automated: prune: true # delete resources removed from Git selfHeal: true # revert manual changes to cluster syncOptions: - CreateNamespace=true # create namespace if missing - PrunePropagationPolicy=foreground - ApplyOutOfSyncOnly=true # only apply changed resources retry: limit: 5 backoff: duration: 5s factor: 2 maxDuration: 3m
2. AppProject CRD — Multi-team RBAC
AppProject restricts what an ArgoCD application can do — which repos, which clusters, which namespaces. Essential for multi-team environments:
apiVersion: argoproj.io/v1alpha1kind: AppProjectmetadata: name: team-payments namespace: openshift-gitopsspec: description: "Payment team GitOps project" # Which Git repos this project can use sourceRepos: - https://github.com/contoso/payment-manifests - https://github.com/contoso/shared-helm-charts # Which clusters and namespaces this project can deploy to destinations: - server: https://kubernetes.default.svc namespace: payments-* # wildcard — any payments namespace - server: https://aro-prod.eastus.aroapp.io:6443 namespace: payments-prod # Which resource types this project can manage clusterResourceWhitelist: - group: "" kind: Namespace namespaceResourceWhitelist: - group: "apps" kind: Deployment - group: "" kind: Service - group: "route.openshift.io" kind: Route # Deny dangerous operations namespaceResourceBlacklist: - group: "" kind: ResourceQuota # only platform team can set quotas # Who can manage apps in this project roles: - name: payment-developer description: "Deploy to dev only" policies: - p, proj:team-payments:payment-developer, applications, sync, team-payments/*, allow - p, proj:team-payments:payment-developer, applications, get, team-payments/*, allow groups: - contoso:payment-developers # maps to Entra ID / LDAP group - name: payment-lead description: "Full access to payment project" policies: - p, proj:team-payments:payment-lead, applications, *, team-payments/*, allow groups: - contoso:payment-leads
3. ApplicationSet CRD — Generate Apps at Scale
ApplicationSet generates multiple Application resources from a template — used for multi-cluster, multi-environment deployments:
apiVersion: argoproj.io/v1alpha1kind: ApplicationSetmetadata: name: payment-service-all-envs namespace: openshift-gitopsspec: generators: # Git directory generator — one app per folder in repo - git: repoURL: https://github.com/contoso/gitops-repo revision: main directories: - path: apps/*/overlays/* # matches apps/payment/overlays/dev, etc. # List generator — explicit env/cluster matrix - list: elements: - env: dev cluster: https://aro-dev.eastus.aroapp.io:6443 namespace: payments-dev - env: staging cluster: https://aro-staging.eastus.aroapp.io:6443 namespace: payments-staging - env: prod cluster: https://aro-prod.eastus.aroapp.io:6443 namespace: payments-prod # Cluster generator — deploy to ALL registered clusters - clusters: selector: matchLabels: environment: production template: metadata: name: "payment-service-{{env}}" namespace: openshift-gitops spec: project: team-payments source: repoURL: https://github.com/contoso/gitops-repo targetRevision: main path: "apps/payment-service/overlays/{{env}}" destination: server: "{{cluster}}" namespace: "{{namespace}}" syncPolicy: automated: prune: true selfHeal: true
Source Types — Helm, Kustomize, Plain YAML
Helm chart source
spec: source: repoURL: https://charts.bitnami.com/bitnami chart: postgresql targetRevision: 12.5.6 helm: releaseName: postgresql-prod values: | primary: persistence: size: 100Gi storageClass: managed-premium-zrs auth: database: payments existingSecret: postgresql-credentials valueFiles: - values-production.yaml
Kustomize overlay source (most common in OCP)
gitops-repo/ apps/payment-service/ base/ deployment.yaml service.yaml route.yaml kustomization.yaml overlays/ dev/ kustomization.yaml ← patches for dev replica-patch.yaml staging/ kustomization.yaml ← patches for staging production/ kustomization.yaml ← patches for production hpa.yaml
# overlays/production/kustomization.yamlapiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationnamespace: payments-prodresources: - ../../base - hpa.yamlimages: - name: payment-service newTag: v2.4.1 # update image tag per envpatches: - path: replica-patch.yamlpatchesStrategicMerge: - |- apiVersion: apps/v1 kind: Deployment metadata: name: payment-service spec: replicas: 5 # production: 5 replicas template: spec: containers: - name: payment-service resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2000m memory: 2Gi
Sync Policies — Manual vs Automated
# MANUAL sync (production best practice)# Human must approve each sync in UI or CLIsyncPolicy: {} # no automated block# AUTOMATED sync (dev/staging)syncPolicy: automated: prune: true # delete resources removed from Git — CAREFUL in prod selfHeal: true # revert kubectl/oc edits that drift from Git# Automated with safeguards (staging)syncPolicy: automated: prune: false # never auto-delete — require manual prune selfHeal: true # revert config drift but don't delete
Sync operations in ArgoCD:
# Sync via CLIargocd app sync payment-service# Sync specific resources onlyargocd app sync payment-service \ --resource apps:Deployment:payment-service# Dry run — see what would changeargocd app diff payment-service# Force sync (ignore resource version conflicts)argocd app sync payment-service --force# Sync with replace (use kubectl replace instead of apply)argocd app sync payment-service --replace
OCP-Specific Integration
OpenShift OAuth SSO
ArgoCD on OCP uses Dex to federate authentication through OpenShift OAuth — users log in with their OCP credentials:
# ArgoCD instance with OCP OAuth (managed by GitOps operator)apiVersion: argoproj.io/v1alpha1kind: ArgoCDmetadata: name: openshift-gitops namespace: openshift-gitopsspec: dex: openShiftOAuth: true # use OCP OAuth automatically rbac: defaultPolicy: role:readonly policy: | # Map OCP groups to ArgoCD roles g, contoso:platform-admins, role:admin g, contoso:developers, role:readonly g, contoso:payment-leads, proj:team-payments:payment-lead scopes: '[groups]' # include group membership in token
OpenShift Routes
ArgoCD manages OpenShift Routes as native resources — no special config needed since ArgoCD uses the full OCP API:
# In your Git repo — ArgoCD applies this to OCPapiVersion: route.openshift.io/v1kind: Routemetadata: name: payment-api namespace: payments-prodspec: host: payment-api.apps.cluster.eastus.aroapp.io to: kind: Service name: payment-service tls: termination: edge insecureEdgeTerminationPolicy: Redirect
SCC Management
ArgoCD can manage SecurityContextConstraints — but needs cluster-level RBAC:
# Grant ArgoCD permission to manage SCCsapiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: argocd-scc-managerroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:openshift:scc:anyuidsubjects: - kind: ServiceAccount name: openshift-gitops-argocd-application-controller namespace: openshift-gitops
Health Checks and Application Status
ArgoCD tracks two dimensions for every application:
Sync status: Synced → cluster matches Git exactly OutOfSync → cluster differs from Git Unknown → cannot determineHealth status: Healthy → all resources ready Progressing → rolling update in progress Degraded → pods crashing, deployment stalled Missing → resource not found in cluster Suspended → resource intentionally paused Unknown → health not determinable
Custom health checks for OpenShift resources:
# argocd-cm ConfigMap — add custom health checksdata: resource.customizations.health.route.openshift.io_Route: | hs = {} hs.status = "Progressing" hs.message = "" if obj.status ~= nil then for i, condition in ipairs(obj.status.conditions) do if condition.type == "Admitted" and condition.status == "True" then hs.status = "Healthy" return hs end if condition.type == "Admitted" and condition.status == "False" then hs.status = "Degraded" hs.message = condition.message return hs end end end return hs
Multi-Environment Promotion Pattern
The standard GitOps promotion pattern in OCP — no direct cluster access needed:
Developer workflow: 1. Write code → push to feature branch 2. CI pipeline (Tekton) runs tests + builds image 3. CI updates image tag in dev overlay: sed -i "s/newTag:.*/newTag: v2.4.1/" overlays/dev/kustomization.yaml git commit + push → main 4. ArgoCD auto-syncs dev environment 5. QA tests in dev 6. Developer opens PR: "promote v2.4.1 to staging" → updates staging/kustomization.yaml 7. Tech lead reviews + merges PR 8. ArgoCD auto-syncs staging environment 9. QA signs off staging 10. Release PR: "promote v2.4.1 to production" → updates production/kustomization.yaml 11. Platform team reviews + merges 12. ArgoCD detects OutOfSync on production 13. Platform team manually syncs in ArgoCD UI (with approval) 14. Production updated — full audit trail in Git history
Notifications — Slack/Teams on Sync Events
# argocd-notifications-cm ConfigMapapiVersion: v1kind: ConfigMapmetadata: name: argocd-notifications-cm namespace: openshift-gitopsdata: service.slack: | token: $slack-token template.app-sync-succeeded: | slack: attachments: | [{ "color": "good", "title": "✅ {{.app.metadata.name}} synced", "text": "Deployed to {{.app.spec.destination.namespace}}\nRevision: {{.app.status.sync.revision}}" }] template.app-sync-failed: | slack: attachments: | [{ "color": "danger", "title": "❌ {{.app.metadata.name}} sync FAILED", "text": "{{.app.status.operationState.message}}" }] trigger.on-sync-succeeded: | - when: app.status.operationState.phase in ['Succeeded'] send: [app-sync-succeeded] trigger.on-sync-failed: | - when: app.status.operationState.phase in ['Error', 'Failed'] send: [app-sync-failed]
Key ArgoCD CLI Commands
# Loginargocd login openshift-gitops-server-openshift-gitops.apps.cluster.aroapp.io \ --sso # use OCP SSO --insecure # skip TLS verify (dev only)# Application managementargocd app listargocd app get payment-serviceargocd app diff payment-serviceargocd app sync payment-serviceargocd app history payment-serviceargocd app rollback payment-service 3 # rollback to revision 3argocd app delete payment-service# Register remote clusterargocd cluster add aro-prod-context \ --name aro-prod# Project managementargocd proj listargocd proj get team-payments# Repo managementargocd repo add https://github.com/contoso/gitops-repo \ --ssh-private-key-path ~/.ssh/gitops-key# Force refresh (re-pull from Git now)argocd app get payment-service --refresh
Key Takeaway
ArgoCD on OCP implements GitOps as a first-class citizen — your Git repository becomes the control plane for all cluster state, every change is auditable, every deployment is reproducible, and drift from the desired state is automatically detected and optionally corrected. The OpenShift GitOps operator integrates it natively with OCP OAuth for SSO, OpenShift RBAC for multi-team access control, and OpenShift-specific resources like Routes and SCCs — making it the standard CD platform for enterprise OCP and ARO deployments.