Consider the fragility of a traditional CI/CD pipeline deploying to Kubernetes. The CI server builds an artifact, authenticates against the cluster, and executes kubectl apply. This "Push" model introduces a critical security vulnerability: the CI environment requires write access to the production cluster. Furthermore, it creates a split-brain scenario where the cluster's actual state can drift from the configuration stored in version control due to manual ad-hoc changes. If a developer runs kubectl edit deployment directly to hotfix an issue, the Git repository becomes obsolete immediately. GitOps eliminates this divergence by inverting the workflow.
The Pull Model Architecture
ArgoCD functions as a Kubernetes controller that continuously monitors running applications and compares their live state against the desired state defined in a Git repository. This control loop ensures that Git remains the Single Source of Truth (SSOT). Unlike the Push model, ArgoCD runs inside the cluster (or manages it remotely) and pulls changes. This architecture removes the need for external CI systems to hold cluster credentials.
When a divergence—or "Configuration Drift"—is detected, ArgoCD marks the application as OutOfSync. Depending on the syncPolicy, it can automatically revert the cluster to match Git, effectively self-healing unauthorized manual changes.
Latency & Polling: By default, ArgoCD polls the Git repository every 3 minutes. For near-real-time synchronization, configure a Webhook in the Git provider (GitHub/GitLab) to trigger the ArgoCD API server immediately upon a push event.
Defining State with Application CRDs
The core abstraction in ArgoCD is the Application Custom Resource Definition (CRD). This resource maps a source (Git path, Helm chart, Kustomize overlay) to a destination (Cluster URL, Namespace). For production environments utilizing Helm Charts and Kustomize, the manifest must explicitly define value overrides and pathing to ensure deterministic deployments.
Below is a production-grade Application manifest that enables automated synchronization and pruning of orphaned resources.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payment-service-prod
namespace: argocd
spec:
project: default
# Source of Truth
source:
repoURL: 'https://github.com/org/payment-service-deploy.git'
targetRevision: HEAD
path: k8s/overlays/production
# Kustomize specific configuration
kustomize:
namePrefix: prod-
commonLabels:
environment: production
# Destination Cluster
destination:
server: 'https://kubernetes.default.svc'
namespace: payment-backend
# Sync Policy ensuring strict consistency
syncPolicy:
automated:
prune: true # Deletes resources no longer in Git
selfHeal: true # Reverts manual kubectl changes
syncOptions:
- CreateNamespace=true
- PruneLast=true
Managing Secrets in a Public Git Context
One of the primary challenges in adopting GitOps is handling sensitive data. Since Git repositories—even private ones—should not store raw secrets (API keys, database passwords), a mechanism to encrypt secrets at rest in Git and decrypt them in the cluster is required. Sealed Secrets by Bitnami is the industry-standard solution compatible with ArgoCD.
The workflow involves a developer encrypting a Secret using a public key provided by the controller running in the cluster. The resulting SealedSecret CRD is safe to commit to Git. When ArgoCD syncs this resource, the Sealed Secrets controller decrypts it using the private key (stored only in the cluster) and creates a standard Kubernetes Secret.
Key Rotation: If the cluster is deleted or the private key is lost, all Sealed Secrets in Git become undecryptable. Ensure you back up the master key of the Sealed Secrets controller.
Multi-Cluster Management Strategy
In enterprise environments, a single ArgoCD instance often manages deployments across multiple clusters (e.g., dev, staging, prod-us-east, prod-eu-west). This is achieved by registering external clusters as destinations. The central ArgoCD instance requires a ServiceAccount with limited RBAC permissions in the target clusters.
This "Hub-and-Spoke" topology simplifies observability but introduces a single point of failure. If the central ArgoCD cluster goes down, deployment capability is lost across the fleet, although the applications themselves continue running. For high availability, consider a sharded approach where critical production clusters manage their own state.
Comparison: Traditional CI/CD vs. GitOps
Understanding the difference between GitOps and traditional CI/CD pipelines is crucial for justifying the architectural migration.
| Feature | Traditional CI/CD (Push) | ArgoCD GitOps (Pull) |
|---|---|---|
| Cluster Access | CI Server requires admin/write credentials |
Agent runs inside cluster; no external creds |
| Drift Detection | None (State known only at deploy time) | Continuous monitoring (Live vs. Git) |
| Rollback | Re-run old CI pipeline (Error prone) | git revert or argocd app rollback |
| Disaster Recovery | Manual reconstruction of state | Apply Git repo to new cluster |
Addressing the ApplicationSet Pattern
Managing hundreds of microservices manually with individual Application manifests is not scalable. The ApplicationSet controller automates the generation of Application resources based on templates. It can traverse a Git repository structure (e.g., directories per app) or use a list of clusters defined in secrets to dynamically deploy workloads across a fleet.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: global-guestbook
spec:
generators:
- list:
elements:
- cluster: engineering-dev
url: https://1.2.3.4
- cluster: engineering-prod
url: https://5.6.7.8
template:
metadata:
name: '{{cluster}}-guestbook'
spec:
project: default
source:
repoURL: https://github.com/infra/guestbook.git
targetRevision: HEAD
path: guestbook
destination:
server: '{{url}}'
namespace: guestbook
By shifting from imperative commands to a declarative state model, organizations achieve higher velocity and stricter compliance. The system becomes audit-friendly by default, as every change to the infrastructure is recorded as a commit in the version control history.
Post a Comment