Argo CD and GitOps Deployment
Use Argo CD to continuously deploy Kubernetes applications from Git: install, Application manifests, sync policies, app of apps and common pitfalls.
What it is and when to use it
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. It runs inside your cluster, watches a Git repository, and keeps the live cluster state equal to what Git describes. When someone merges a change, Argo CD notices the difference and syncs it. If someone edits the cluster by hand, Argo CD reports drift and can revert it.
Use it when you want Git to be the single source of truth, auditable deployments through pull requests, easy rollback by reverting a commit, and a clear view of what is running on many clusters. It supports plain YAML, Helm, Kustomize and Jsonnet.
Quick start
Install into its own namespace and reach the UI.
kubectl create namespace argocd
kubectl apply -n argocd --server-side -f \
https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl port-forward svc/argocd-server -n argocd 8080:443
argocd admin initial-password -n argocd
argocd login localhost:8080 --username admin --insecure
Change the initial admin password after first login and delete the initial secret. Then register an application, either with the CLI or with a manifest.
argocd app create guestbook \
--repo https://github.com/argoproj/argocd-example-apps.git \
--path guestbook \
--dest-server https://kubernetes.default.svc \
--dest-namespace demo
argocd app sync guestbook
argocd app get guestbook
Core concepts
Application is a custom resource that links a source (repo, revision, path) to a destination (cluster and namespace). Declaring it in YAML means Argo CD itself is managed by GitOps.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/example/deploy-config.git
targetRevision: main
path: apps/myapp/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: myapp
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Sync status and health. Synced means live state matches Git. Health reflects whether resources, such as Deployments, are actually running. An application can be Synced yet Degraded.
Sync policy. Manual sync gives a human gate. Automated sync applies commits as they arrive. The prune option deletes resources removed from Git, and selfHeal reverts manual cluster changes.
Projects (AppProject) restrict which repos, clusters and namespaces a team can deploy to, which is the basis of multi-tenancy.
Helm and Kustomize sources. For Helm, point the path at a chart and set values in the source block.
source:
repoURL: https://github.com/example/charts.git
path: charts/myapp
targetRevision: v1.4.2
helm:
valueFiles:
- values-prod.yaml
App of apps and ApplicationSet. A root Application can point at a directory containing other Application manifests, bootstrapping a whole cluster. ApplicationSet generates many Applications from templates, for example one per cluster or per directory.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: envs
namespace: argocd
spec:
generators:
- list:
elements:
- env: staging
- env: prod
template:
metadata:
name: myapp-env
spec:
project: default
source:
repoURL: https://github.com/example/deploy-config.git
targetRevision: main
path: apps/myapp/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: myapp
In a real set, the template uses the env parameter inside double braces so each element yields its own name, path and namespace.
Sync waves and hooks order resources using the argocd.argoproj.io/sync-wave annotation, and run Jobs before or after a sync.
Pitfalls
- Do not store application source code and deployment config in the same repo if every code commit would trigger config churn. A separate config repo is the usual pattern.
- Secrets cannot sit in Git unencrypted. Use Sealed Secrets, External Secrets Operator or SOPS.
- Automated prune with a wrong path can delete workloads. Test on staging, and protect critical resources with the Prune=false annotation.
- Fields mutated by controllers, such as replica counts under an autoscaler, cause perpetual OutOfSync. Use ignoreDifferences.
- Pin targetRevision to tags or commits for production rather than a moving branch when you need strict promotion.
- Lock down RBAC and the admin account, and use SSO for real teams.
How it fits an architecture
A typical flow: CI in GitHub Actions builds and tests an image, pushes it, and opens a commit or pull request that bumps the image tag in the config repo. Argo CD detects the merge and rolls it out. Terraform creates the cluster and installs Argo CD once; from then on Argo CD manages everything else, including Helm releases, ingress and mesh configuration. Rollback is a git revert.
Key takeaways
- Argo CD pulls from Git into the cluster, so CI never needs cluster credentials.
- Application resources define source, destination and sync behavior declaratively.
- Enable selfHeal and prune only once you trust your repo layout.
- Use ApplicationSet and app of apps to scale across clusters and environments.
- Keep secrets encrypted and use projects and RBAC for team isolation.