Skip to content
Codeloom
DevOps

GitOps with ArgoCD: Deploy Kubernetes Apps Automatically

Learn GitOps principles and deploy Kubernetes applications with ArgoCD. Covers installation, app configuration, sync policies, multi-environment setups, and rollbacks.

·7 min read · By Codeloom
Intermediate 15 min read

What you'll learn

  • Core GitOps principles and why they matter
  • Installing and configuring ArgoCD on Kubernetes
  • Creating and syncing applications from Git repositories
  • Managing multiple environments with ArgoCD

Prerequisites

  • A running Kubernetes cluster (minikube, kind, or managed)
  • kubectl installed and configured
  • Basic understanding of Kubernetes manifests
  • A Git repository for your application manifests

What Is GitOps?

GitOps is an operational framework where Git is the single source of truth for your infrastructure and application configuration. Rather than running kubectl apply manually or building complex CI/CD pipelines that push changes to clusters, GitOps uses a pull-based model: an agent running inside the cluster continuously watches a Git repository and automatically reconciles the cluster state to match what is in Git.

The core principles are straightforward:

  1. Declarative: The entire system is described declaratively in Git.
  2. Versioned: Git provides the complete history of every change.
  3. Automated: Approved changes are applied automatically.
  4. Self-healing: The agent corrects any drift between the cluster and Git.

ArgoCD is the most popular GitOps tool for Kubernetes. It watches your Git repositories, detects when manifests change, and syncs those changes to your cluster.

Installing ArgoCD

Install ArgoCD into its own namespace:

kubectl create namespace argocd
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 pod -l app.kubernetes.io/part-of=argocd -n argocd --timeout=120s

Install the ArgoCD CLI:

# macOS
brew install argocd

# Linux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd && sudo mv argocd /usr/local/bin/

Access the ArgoCD UI by port-forwarding:

kubectl port-forward svc/argocd-server -n argocd 8080:443

Get the initial admin password:

argocd admin initial-password -n argocd

Log in via CLI:

argocd login localhost:8080 --username admin --password <initial-password> --insecure

Change the default password immediately:

argocd account update-password

Preparing Your Git Repository

ArgoCD watches a Git repository containing Kubernetes manifests. A typical structure looks like this:

k8s-manifests/
├── apps/
│   ├── frontend/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── ingress.yaml
│   └── backend/
│       ├── deployment.yaml
│       ├── service.yaml
│       └── configmap.yaml
└── environments/
    ├── dev/
    │   └── kustomization.yaml
    ├── staging/
    │   └── kustomization.yaml
    └── prod/
        └── kustomization.yaml

Here is a sample deployment manifest at apps/frontend/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  labels:
    app: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
        - name: frontend
          image: myregistry/frontend:v1.2.0
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 250m
              memory: 256Mi
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 30

And a service at apps/frontend/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  selector:
    app: frontend
  ports:
    - port: 80
      targetPort: 3000
  type: ClusterIP

Creating Your First ArgoCD Application

You can create an ArgoCD application via the CLI or declaratively. The declarative approach is preferred because the application definition itself lives in Git.

Declarative Application

Create argocd-apps/frontend.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: frontend
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/k8s-manifests.git
    targetRevision: main
    path: apps/frontend
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Apply it:

kubectl apply -f argocd-apps/frontend.yaml

CLI Approach

argocd app create frontend \
  --repo https://github.com/your-org/k8s-manifests.git \
  --path apps/frontend \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace production \
  --sync-policy automated \
  --auto-prune \
  --self-heal

Understanding Sync Policies

ArgoCD sync policies control how and when changes are applied:

Manual sync: ArgoCD detects the difference between Git and the cluster but waits for you to click “Sync” in the UI or run argocd app sync frontend. Good for production environments where you want human approval.

Automated sync: ArgoCD automatically applies changes when it detects drift. Set this with syncPolicy.automated.

Self-heal: When enabled, ArgoCD reverts manual changes made directly to the cluster. If someone runs kubectl edit to change a replica count, ArgoCD will revert it to match Git. This enforces Git as the single source of truth.

Prune: When enabled, ArgoCD deletes resources from the cluster that no longer exist in Git. Without prune, removing a manifest from Git leaves the resource orphaned in the cluster.

Check application status:

# List all applications
argocd app list

# Get detailed status
argocd app get frontend

# View sync history
argocd app history frontend

# Manually trigger a sync
argocd app sync frontend

# Rollback to a previous version
argocd app rollback frontend 2

Multi-Environment Setup with Kustomize

ArgoCD works natively with Kustomize, letting you manage multiple environments from a single base. Create an overlay structure:

# apps/frontend/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
# environments/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../apps/frontend/base
namespace: dev
patches:
  - patch: |
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: frontend
      spec:
        replicas: 1
        template:
          spec:
            containers:
              - name: frontend
                image: myregistry/frontend:dev-latest
                resources:
                  requests:
                    cpu: 50m
                    memory: 64Mi
                  limits:
                    cpu: 100m
                    memory: 128Mi
# environments/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../apps/frontend/base
namespace: production
patches:
  - patch: |
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: frontend
      spec:
        replicas: 5

Create separate ArgoCD applications for each environment:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: frontend-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/k8s-manifests.git
    targetRevision: main
    path: environments/dev
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Using Helm Charts with ArgoCD

ArgoCD can deploy Helm charts directly from a chart repository or from a Git repository containing chart source:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: redis
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: redis
    targetRevision: 18.6.1
    helm:
      values: |
        architecture: standalone
        auth:
          enabled: true
          password: "changeme"
        master:
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
  destination:
    server: https://kubernetes.default.svc
    namespace: redis
  syncPolicy:
    automated:
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

ArgoCD Projects for Access Control

Projects let you restrict what an ArgoCD application can do:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-backend
  namespace: argocd
spec:
  description: "Backend team applications"
  sourceRepos:
    - "https://github.com/your-org/backend-manifests.git"
  destinations:
    - namespace: "backend-*"
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: ""
      kind: Namespace
  namespaceResourceBlacklist:
    - group: ""
      kind: ResourceQuota
    - group: ""
      kind: LimitRange
  roles:
    - name: developer
      description: "Backend developers"
      policies:
        - p, proj:team-backend:developer, applications, get, team-backend/*, allow
        - p, proj:team-backend:developer, applications, sync, team-backend/*, allow

This project limits the backend team to specific repositories, namespaces, and operations.

The GitOps Deployment Workflow

With ArgoCD configured, the deployment workflow becomes:

  1. A developer pushes code changes and opens a pull request.
  2. CI runs tests and builds a new container image (e.g., myregistry/frontend:v1.3.0).
  3. CI or a bot updates the image tag in the Git manifests repository.
  4. The pull request to the manifests repo is reviewed and merged.
  5. ArgoCD detects the change and syncs it to the cluster.
  6. If something goes wrong, revert the Git commit and ArgoCD rolls back automatically.

This separation of application code and deployment manifests into different repositories is a common best practice. It keeps the deployment history clean and allows different access controls.

Monitoring and Notifications

ArgoCD can send notifications when application status changes. Install the ArgoCD Notifications controller and configure a Slack integration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.slack: |
    token: $slack-token
  template.app-sync-status: |
    message: |
      Application {{.app.metadata.name}} sync status: {{.app.status.sync.status}}
      Health: {{.app.status.health.status}}
  trigger.on-sync-failed: |
    - when: app.status.sync.status == 'OutOfSync'
      send: [app-sync-status]

Wrapping Up

GitOps with ArgoCD gives you a reliable, auditable, and automated deployment pipeline for Kubernetes. Git becomes the single source of truth, every change is tracked and reviewable, and the cluster self-heals to match your desired state. Start with a single application using manual sync, then graduate to automated sync with self-heal as you build confidence. From here, explore ArgoCD ApplicationSets for managing many similar applications, progressive delivery with Argo Rollouts for canary deployments, and integrating ArgoCD with your existing CI pipeline for a complete GitOps workflow.