How to Set Up ArgoCD for GitOps Deployment
How to Set Up ArgoCD for GitOps Deployment
Kubernetes deployments fail when the cluster state drifts from what you intended to deploy. A developer manually patches a deployment to test something, forgets to revert it, and now production runs different code than staging despite both supposedly deploying from the same git commit. Or someone applies a hotfix with kubectl during an incident, and that change never makes it back to the git repository, so the next deployment overwrites the fix and reintroduces the bug.
ArgoCD solves this by making git the single source of truth for cluster state. Your Kubernetes manifests live in git, ArgoCD monitors both the git repository and the cluster, and automatically syncs the cluster to match git. Manual kubectl changes get detected as drift and either auto-corrected or flagged for review. This article shows you exactly how to install ArgoCD on a Kubernetes cluster, connect it to your git repositories, configure automated and manual sync policies, and set up multi-environment deployments.
You'll learn the initial installation process, repository authentication strategies, application configuration patterns, sync wave ordering for complex deployments, and the specific RBAC configurations needed for production use. These instructions work on managed Kubernetes services (EKS, GKE, AKS) and self-hosted clusters (kubeadm, k3s, kind).
Why ArgoCD Over kubectl apply
The traditional deployment workflow uses kubectl apply from CI pipelines or developer machines. CI builds your application, generates Kubernetes manifests (or renders Helm charts), then applies them to the cluster. This works until you need to answer: what exactly is running in production right now? You check the git repository, but someone ran kubectl edit to adjust resource limits last week, and that change exists only in the cluster.
ArgoCD inverts the relationship. Instead of pushing changes to the cluster, the cluster pulls changes from git. ArgoCD runs inside your cluster, watches your git repositories for manifest changes, and applies those changes automatically. Every change goes through git first—no exceptions. Want to update a deployment? Commit the manifest change to git, and ArgoCD syncs it within seconds.
This model provides three critical capabilities that kubectl-based workflows lack: drift detection (ArgoCD knows when cluster state doesn't match git), audit trails (every change is a git commit with author and timestamp), and declarative rollback (reverting a change means git revert, not reconstructing what the previous state was from memory).
The Drift Detection Advantage
Manual kubectl changes are the primary source of environment inconsistency. During incident response, someone patches a deployment to add debug logging, and that change works so well it should stay—but nobody remembers to update the manifest files. The next deployment removes the debug logging because it's not in git.
ArgoCD detects this automatically. Its UI shows which resources have drifted from git, displays the exact diff between git and cluster state, and lets you decide: revert the cluster to match git, or update git to match the cluster. This visibility alone catches configuration drift that would otherwise stay hidden until it causes production incidents.
Installing ArgoCD on Kubernetes
ArgoCD consists of several components: the API server (provides the UI and CLI API), the repository server (fetches manifest files from git), the application controller (monitors applications and syncs state), and the Redis cache. All components run as Kubernetes deployments in a dedicated namespace.
Standard Installation
# Create ArgoCD namespace
kubectl create namespace argocd
# Install ArgoCD components
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for all pods to be ready
kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s
# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Port-forward to access UI (or configure ingress)
kubectl port-forward svc/argocd-server -n argocd 8080:443
This installs ArgoCD with default settings suitable for evaluation. For production, you'll want to customize the installation—particularly around high availability, resource limits, and ingress configuration. But this default installation works immediately and lets you experiment with GitOps workflows before committing to specific architecture decisions.
Production Installation with HA
High availability requires running multiple replicas of the API server and application controller. The standard manifest file uses single replicas; for HA, use the ha-install.yaml manifest instead:
# Install ArgoCD in HA mode
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/ha/install.yaml
HA mode runs three API server replicas and two application controller replicas. This tolerates pod failures and node outages without disrupting deployments. The tradeoff is increased resource consumption—HA mode uses approximately 3x more CPU and memory than single-replica mode. For production clusters, this is worthwhile; for development clusters, standard installation suffices.
Configuring Ingress for ArgoCD UI
Port-forwarding works for initial setup but not for production use. Configure an Ingress resource to expose ArgoCD's UI and API over HTTPS with a proper domain name. ArgoCD's server component serves traffic on port 443 with self-signed certificates by default—you'll want to terminate TLS at the ingress controller instead.
Nginx Ingress Configuration
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-ingress
namespace: argocd
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
rules:
- host: argocd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 443
tls:
- hosts:
- argocd.example.com
secretName: argocd-server-tls
This configuration assumes you're using cert-manager for automatic TLS certificate provisioning via Let's Encrypt. The ssl-passthrough annotation tells nginx to pass encrypted traffic directly to ArgoCD instead of terminating TLS at the ingress—ArgoCD handles TLS termination internally. If you prefer ingress-level TLS termination, remove ssl-passthrough and configure ArgoCD to serve HTTP by setting server.insecure: true in the argocd-cmd-params-cm ConfigMap.
DNS Configuration
Point your DNS record (argocd.example.com) to your ingress controller's external IP. For cloud load balancers, this is typically a cloud provider's load balancer DNS name:
# Get the ingress external IP or hostname
kubectl get svc -n ingress-nginx ingress-nginx-controller
# Create DNS A record (or CNAME for cloud LB)
# argocd.example.com ->
Once DNS propagates, you can access ArgoCD at https://argocd.example.com. Log in with username "admin" and the password retrieved during installation. The first task should be creating additional user accounts with appropriate RBAC permissions—running production operations with the admin account is poor practice.
Connecting Git Repositories
ArgoCD needs read access to your git repositories containing Kubernetes manifests. For public repositories, no authentication is required. For private repositories, ArgoCD supports HTTPS with username/password, SSH keys, or GitHub App credentials.
HTTPS Repository Authentication
# Using ArgoCD CLI
argocd repo add https://github.com/yourorg/k8s-manifests \
--username your-username \
--password your-personal-access-token
# Or via UI: Settings -> Repositories -> Connect Repo
HTTPS authentication works with personal access tokens (PAT) on GitHub, GitLab, and Bitbucket. Create a PAT with read-only repository access—ArgoCD only needs to clone and pull, never push. Store the credentials in ArgoCD, which encrypts them in a Kubernetes secret.
SSH Key Authentication
SSH keys provide better security than HTTPS tokens because they're revocable independently and don't grant access to other repositories in the same organization. Generate a deploy key specifically for ArgoCD:
# Generate SSH key pair
ssh-keygen -t ed25519 -C "argocd@cluster" -f argocd-deploy-key
# Add public key to GitHub repository
# Settings -> Deploy keys -> Add deploy key
# Paste contents of argocd-deploy-key.pub
# Add private key to ArgoCD
argocd repo add [email protected]:yourorg/k8s-manifests.git \
--ssh-private-key-path argocd-deploy-key
Deploy keys grant read-only access to a single repository. If ArgoCD needs access to multiple repositories, create separate deploy keys for each repository or use a machine account with read access to all necessary repositories.
Creating Your First Application
ArgoCD applications represent a git repository (or directory within a repository) containing Kubernetes manifests that should be synced to a cluster. The application configuration specifies the source repository, target cluster, and sync policy.
Declarative Application Definition
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: example-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/yourorg/k8s-manifests
targetRevision: main
path: apps/example-app
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
This Application manifest tells ArgoCD to sync Kubernetes manifests from the apps/example-app directory in the specified git repository to the production namespace in the cluster. The automated sync policy with prune and selfHeal means ArgoCD automatically applies git changes and reverts manual cluster modifications.
Sync Policy Options
| Policy | Behavior | Use Case |
|---|---|---|
| Manual sync | Changes require explicit sync button click | Production deployments requiring approval |
| Automated sync | Git changes deploy automatically | Development and staging environments |
| Prune enabled | Resources removed from git are deleted from cluster | Preventing abandoned resources |
| SelfHeal enabled | Manual cluster changes are auto-reverted | Enforcing strict GitOps |
Production deployments typically use manual sync to require human approval before changes deploy. Development environments use automated sync with selfHeal to maintain strict git alignment. The prune option is controversial—it automatically deletes resources removed from git, which is safe for managed resources but risky if developers create test resources manually.
Repository Structure Patterns
How you organize Kubernetes manifests in git significantly impacts ArgoCD usability. The two primary patterns are mono-repo (all applications in one repository) and multi-repo (each application in its own repository). Both work; the choice depends on team structure and access control requirements.
Mono-Repo Structure
k8s-manifests/
├── apps/
│ ├── frontend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── ingress.yaml
│ ├── backend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── configmap.yaml
│ └── worker/
│ ├── deployment.yaml
│ └── configmap.yaml
├── infrastructure/
│ ├── ingress-nginx/
│ ├── cert-manager/
│ └── prometheus/
└── environments/
├── staging/
│ ├── frontend-values.yaml
│ └── backend-values.yaml
└── production/
├── frontend-values.yaml
└── backend-values.yaml
Mono-repo works well when one team manages all deployments and you want simplified dependency tracking. All infrastructure and application manifests live in one place, making it easy to understand the complete system state. The downside is that every team needs read access to the entire repository, even if they only care about their specific application.
Multi-Repo Structure
Multi-repo gives each application team ownership of their deployment manifests. The platform team maintains a separate repository for shared infrastructure (ingress controllers, monitoring, service mesh), while application teams maintain their own repositories:
# Platform repo: k8s-infrastructure
infrastructure/
├── ingress-nginx/
├── cert-manager/
└── prometheus/
# App team repo: frontend-app
k8s/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── staging/
│ └── kustomization.yaml
└── production/
└── kustomization.yaml
This structure scales better for large organizations because access control happens at the repository level. Frontend developers have write access to the frontend-app repository but only read access to the infrastructure repository. The tradeoff is coordination complexity—cross-application changes require coordinating commits across multiple repositories.
Managing Multiple Environments
Most teams deploy to multiple environments (development, staging, production) with slight variations in configuration—different replica counts, resource limits, or external service endpoints. ArgoCD handles this through Kustomize overlays, Helm values files, or directory-based separation.
Kustomize Overlay Pattern
# Base configuration
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
template:
spec:
containers:
- name: frontend
image: myapp:v1.0.0
resources:
requests:
memory: "128Mi"
cpu: "100m"
# Staging overlay
# overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: staging
replicas:
- name: frontend
count: 1
# Production overlay
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: production
replicas:
- name: frontend
count: 3
patches:
- patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources/requests/memory
value: 256Mi
target:
kind: Deployment
name: frontend
Kustomize overlays let you define base configurations shared across environments, then patch specific values per environment. ArgoCD natively supports Kustomize—just point the application's source.path to the overlay directory (overlays/staging or overlays/production).
Creating Environment-Specific Applications
# Staging application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend-staging
namespace: argocd
spec:
source:
repoURL: https://github.com/yourorg/frontend-app
targetRevision: main
path: k8s/overlays/staging
destination:
server: https://kubernetes.default.svc
namespace: staging
syncPolicy:
automated:
prune: true
selfHeal: true
# Production application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend-production
namespace: argocd
spec:
source:
repoURL: https://github.com/yourorg/frontend-app
targetRevision: main
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated: false # Manual sync for production
This creates two ArgoCD applications tracking different Kustomize overlays from the same repository. Commits to the repository trigger re-sync in both environments, but staging auto-deploys while production requires manual sync. This gives you automatic testing in staging with controlled production rollout.
Sync Waves and Resource Ordering
Some resources must deploy before others—namespaces before deployments, CRDs before custom resources, databases before applications. ArgoCD's default sync behavior applies resources in arbitrary order, which breaks when dependencies exist. Sync waves solve this by defining explicit ordering.
Annotating Resources with Sync Waves
# Wave 0: Namespace (deploys first)
apiVersion: v1
kind: Namespace
metadata:
name: production
annotations:
argocd.argoproj.io/sync-wave: "0"
# Wave 1: ConfigMap and Secret
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "1"
# Wave 2: Database deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "2"
# Wave 3: Application deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "3"
ArgoCD processes resources in wave order, waiting for wave N to complete (all resources healthy) before starting wave N+1. This ensures PostgreSQL starts before the backend application, which depends on database availability. Without sync waves, ArgoCD might start the backend first, causing crash loops until PostgreSQL becomes available.
Common Sync Wave Patterns
| Wave | Resource Types | Reason |
|---|---|---|
| 0 | Namespaces, CRDs | Must exist before any namespaced resources |
| 1 | Secrets, ConfigMaps | Referenced by pods in later waves |
| 2 | Databases, message queues | Infrastructure services applications depend on |
| 3 | Backend applications | Core application logic |
| 4 | Frontend applications | Depend on backend API availability |
Keep wave numbers sequential with gaps (0, 2, 4, 6) rather than consecutive (0, 1, 2, 3). This leaves room to insert new waves later without renumbering everything. If you later need to add a resource between waves 2 and 4, you can use wave 3 without modifying existing resources.
RBAC and Multi-Tenancy
Production ArgoCD installations need RBAC to control which teams can deploy which applications. The default admin account has full cluster access—not appropriate when multiple teams share one ArgoCD instance. ArgoCD's RBAC system integrates with SSO providers (OIDC, SAML) and enforces permissions at the project and application level.
Creating Projects for Team Isolation
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: frontend-team
namespace: argocd
spec:
description: Frontend team applications
# Git repositories this project can deploy from
sourceRepos:
- https://github.com/yourorg/frontend-*
# Clusters and namespaces this project can deploy to
destinations:
- namespace: frontend-staging
server: https://kubernetes.default.svc
- namespace: frontend-production
server: https://kubernetes.default.svc
# Resource types this project can manage
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceWhitelist:
- group: 'apps'
kind: Deployment
- group: 'apps'
kind: StatefulSet
- group: ''
kind: Service
- group: ''
kind: ConfigMap
AppProjects create security boundaries. Applications in the frontend-team project can only deploy from frontend-* repositories to frontend-staging and frontend-production namespaces. They can't deploy cluster-wide resources (except namespaces) or access other teams' namespaces. This prevents the frontend team from accidentally modifying backend deployments or cluster infrastructure.
Configuring RBAC Policies
# argocd-rbac-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly
policy.csv: |
# Frontend team can manage applications in frontend-team project
p, role:frontend-developer, applications, get, frontend-team/*, allow
p, role:frontend-developer, applications, sync, frontend-team/*, allow
p, role:frontend-developer, applications, update, frontend-team/*, allow
# Backend team can manage applications in backend-team project
p, role:backend-developer, applications, get, backend-team/*, allow
p, role:backend-developer, applications, sync, backend-team/*, allow
# Platform team has full access
p, role:platform-admin, applications, *, */*, allow
p, role:platform-admin, clusters, *, *, allow
p, role:platform-admin, repositories, *, *, allow
# Map SSO groups to roles
g, [email protected], role:frontend-developer
g, [email protected], role:backend-developer
g, [email protected], role:platform-admin
RBAC policies use Casbin syntax. The p, lines define permissions: role:frontend-developer can get, sync, and update applications in the frontend-team project. The g, lines map SSO groups (from your OIDC provider) to ArgoCD roles. When users from [email protected] log in via SSO, they automatically receive frontend-developer permissions.
Integrating with CI Pipelines
GitOps doesn't eliminate CI—it changes what CI does. Traditional CI builds your application, generates manifests, and deploys to Kubernetes. In GitOps, CI builds your application, generates manifests, and commits those manifests to git. ArgoCD then deploys from git.
Image Tag Update Pattern
# GitHub Actions workflow
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build -t myregistry/myapp:${{ github.sha }} .
docker push myregistry/myapp:${{ github.sha }}
- name: Update Kubernetes manifest
run: |
git clone https://github.com/yourorg/k8s-manifests
cd k8s-manifests
# Update image tag in deployment manifest
sed -i "s|image: myregistry/myapp:.*|image: myregistry/myapp:${{ github.sha }}|" \
apps/myapp/deployment.yaml
git config user.email "[email protected]"
git config user.name "CI Bot"
git add apps/myapp/deployment.yaml
git commit -m "Update myapp image to ${{ github.sha }}"
git push
This workflow builds a Docker image tagged with the git commit SHA, pushes it to your registry, then updates the Kubernetes deployment manifest in a separate git repository. ArgoCD detects the manifest change and deploys the new image version. The git commit in k8s-manifests provides a complete audit trail: which application version deployed when and by which CI run.
Using ArgoCD Image Updater
ArgoCD Image Updater automates the image tag update process. It watches container registries for new image tags and automatically updates manifests in git:
# Install ArgoCD Image Updater
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
# Annotate application to enable automatic updates
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: myapp=myregistry/myapp
argocd-image-updater.argoproj.io/myapp.update-strategy: latest
spec:
# ... rest of application spec
Image Updater polls your container registry, detects new tags, and updates the image reference in your git repository automatically. This closes the GitOps loop without CI needing to interact with the k8s-manifests repository. Your CI pipeline only needs to build and push Docker images; Image Updater handles deployment.
Monitoring and Alerting
ArgoCD provides a webhook endpoint that emits events for sync status changes. Integrate this with Slack, PagerDuty, or custom alerting systems to notify teams when deployments succeed, fail, or detect drift.
Slack Notification Configuration
# argocd-notifications-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
template.app-deployed: |
message: |
Application {{.app.metadata.name}} deployed successfully.
Revision: {{.app.status.sync.revision}}
Author: {{.app.status.operationState.operation.initiatedBy.username}}
template.app-health-degraded: |
message: |
Application {{.app.metadata.name}} has degraded health.
Status: {{.app.status.health.status}}
Message: {{.app.status.health.message}}
trigger.on-deployed: |
- when: app.status.operationState.phase in ['Succeeded']
send: [app-deployed]
trigger.on-health-degraded: |
- when: app.status.health.status == 'Degraded'
send: [app-health-degraded]
# Subscribe application to notifications
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: deployments-channel
notifications.argoproj.io/subscribe.on-health-degraded.slack: alerts-channel
spec:
# ... application spec
This configuration sends Slack notifications to #deployments-channel when applications deploy successfully and to #alerts-channel when application health degrades. You can customize triggers to notify on any ArgoCD event: sync failures, out-of-sync detection, or resource deletion.
Disaster Recovery and Backup
ArgoCD's configuration (applications, projects, repository credentials, RBAC policies) lives in Kubernetes resources in the argocd namespace. Losing this configuration means losing visibility into which applications are deployed and how. Regular backups are essential.
Backup Strategy
# Export all ArgoCD applications
kubectl get applications -n argocd -o yaml > argocd-applications-backup.yaml
# Export all AppProjects
kubectl get appprojects -n argocd -o yaml > argocd-projects-backup.yaml
# Export repository credentials
kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository \
-o yaml > argocd-repo-creds-backup.yaml
# Full namespace backup using Velero
velero backup create argocd-backup --include-namespaces argocd
Store these backups in version control (for non-sensitive resources) or encrypted storage (for secrets). Test recovery periodically by spinning up a new cluster and restoring ArgoCD configuration—backups you haven't tested are worthless.
FAQ
What's the difference between ArgoCD and Flux?
Both implement GitOps for Kubernetes. ArgoCD provides a UI and CLI, making it easier to visualize application state and manually trigger syncs. Flux is more lightweight and CLI-focused, with stronger support for multi-tenancy via Flux's Kustomization and HelmRelease CRDs. Choose ArgoCD if you want a UI, Flux if you prefer pure declarative configuration.
Can ArgoCD deploy to multiple clusters?
Yes. ArgoCD can manage applications across multiple Kubernetes clusters. Install ArgoCD in one cluster (the control plane), then register other clusters as deployment targets using the argocd cluster add command. This centralized model lets one ArgoCD instance manage development, staging, and production clusters.
How does ArgoCD handle secrets?
ArgoCD doesn't solve secret management—it deploys whatever is in git. Use external secret management tools like Sealed Secrets, External Secrets Operator, or SOPS to encrypt secrets before committing to git. ArgoCD deploys these tools, which then fetch and decrypt actual secrets from secure storage (Vault, AWS Secrets Manager, etc.).
What happens if ArgoCD is down?
Your applications keep running normally. ArgoCD only manages deployment and sync—it's not in the data path for application traffic. If ArgoCD is unavailable, you lose the ability to deploy changes or detect drift, but running applications are unaffected. This is a key advantage over push-based CD systems where outages can prevent emergency deployments.
Can I use ArgoCD with Helm charts?
Yes. ArgoCD natively supports Helm charts from git repositories or Helm registries. Specify the chart location in the source.chart field and override values using source.helm.values. ArgoCD renders the chart with your values and deploys the resulting manifests.
How do I rollback a deployment?
Revert the git commit that introduced the problematic change and push to the repository. ArgoCD detects the revert and syncs the cluster back to the previous state. This is faster and more auditable than manual kubectl rollback commands because the entire operation is tracked in git history.
Should I enable automated sync or manual sync?
Use automated sync for development and staging environments to get immediate feedback on manifest changes. Use manual sync for production to require explicit approval before deployments. Some teams use automated sync even in production with protection via merge request approvals on the git side—changes can't reach production without approval, but once merged they deploy automatically.
How does ArgoCD handle large manifests?
ArgoCD has a maximum manifest size (default 1MB). If your rendered manifests exceed this, increase the limit via controller.repo.server.max.combined.directory.manifests.size in the argocd-cm ConfigMap. For extremely large manifests (10+ MB), consider splitting into multiple applications or using Helm/Kustomize to reduce duplication.
Can I deploy CRDs with ArgoCD?
Yes, but use sync waves carefully. CRDs must deploy and become ready before custom resources that use them. Set CRD resources to sync wave 0 and dependent resources to higher waves. Without this, ArgoCD may try to create custom resources before the CRD exists, causing sync failures.
How do I troubleshoot sync failures?
Check the ArgoCD UI's application details page, which shows the sync status and error messages for each resource. Common causes: invalid manifest syntax (run kubectl apply --dry-run locally), insufficient RBAC permissions (check ArgoCD's service account permissions), or resource conflicts (another controller modifying the same resources).
Conclusion
ArgoCD transforms Kubernetes deployments from push-based CI operations to pull-based git synchronization. This shift makes git the authoritative source of truth, enables automatic drift detection, and provides clear audit trails through git history. The initial setup—installing ArgoCD, connecting git repositories, and creating applications—takes an hour. The long-term benefits compound as your cluster and team scale.
Start with a single non-critical application using manual sync. Verify that git changes deploy correctly and rollbacks work as expected. Once comfortable, expand to automated sync for development environments and add more applications. The pattern scales from one application on one cluster to hundreds of applications across multiple clusters using the same core concepts.
The key insight GitOps provides is this: when your cluster state diverges from git, you have one question to answer instead of two. Traditional deployments force you to ask "what's actually running in production?" and "what should be running in production?" With GitOps, those questions have the same answer: whatever is in git.