← Back to DevBytes

How to Set Up Continuous Deployment with ArgoCD

What is ArgoCD?

ArgoCD is a declarative, GitOps-based continuous delivery tool for Kubernetes. It monitors your application definitions stored in a Git repository and automatically synchronizes the desired state with the live state in your Kubernetes cluster. Unlike traditional push-based deployment pipelines, ArgoCD follows a pull-based model where it continuously watches your Git repository and applies changes to the cluster when differences are detected.

At its core, ArgoCD operates as a Kubernetes controller that reconciles the actual state of your cluster against the desired state declared in Git. It supports a wide variety of manifest formats including plain YAML, Helm charts, Kustomize overlays, Ksonnet, and Jsonnet. This flexibility makes it compatible with virtually any Kubernetes configuration management approach you may already be using.

Why Continuous Deployment with ArgoCD Matters

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Implementing continuous deployment with ArgoCD brings several critical advantages to your development workflow:

Prerequisites

Before you begin setting up ArgoCD, ensure you have the following:

Step-by-Step Setup Guide

1. Installing ArgoCD on Your Kubernetes Cluster

The recommended installation method is to apply the official ArgoCD namespace and installation manifests directly to your cluster. First, create the dedicated namespace:

kubectl create namespace argocd

Now apply the ArgoCD installation manifests. The stable release installs the core components including the API server, application controller, repo server, and Redis cache:

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

If you prefer a highly available installation with multiple replicas, use the HA manifests instead:

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/ha/install.yaml

Wait for all pods to become ready. You can monitor the progress with:

kubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s

Verify the installation by listing all ArgoCD pods:

kubectl get pods -n argocd

You should see pods for argocd-application-controller, argocd-repo-server, argocd-server, and argocd-redis, all in a Running state.

2. Accessing the ArgoCD API and UI

By default, the ArgoCD API server is not exposed externally. For local development, you can use port-forwarding to access both the CLI and the web UI:

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

Alternatively, you can expose the service via a LoadBalancer, Ingress, or NodePort. For an Ingress-based approach with TLS, create an ingress resource:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              name: https

Retrieve the initial admin password. The password is stored as a Kubernetes secret in the argocd namespace:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

The default username is admin. You can now log in using the ArgoCD CLI:

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

Change the admin password immediately after your first login:

argocd account update-password \
  --current-password <INITIAL_PASSWORD> \
  --new-password <NEW_STRONG_PASSWORD> \
  --server localhost:8080

3. Connecting Your Git Repository

ArgoCD needs access to your Git repository to fetch application manifests. You can add repositories via the CLI, UI, or declarative approach. Using the CLI, add a public repository:

argocd repo add https://github.com/your-org/your-config-repo.git --name my-config-repo

For private repositories, provide credentials:

argocd repo add https://github.com/your-org/private-config-repo.git \
  --username your-github-username \
  --password your-personal-access-token \
  --name private-config-repo

You can also store repository credentials as Kubernetes secrets. Create a secret and label it for ArgoCD discovery:

apiVersion: v1
kind: Secret
metadata:
  name: private-repo-creds
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
  url: https://github.com/your-org/private-config-repo.git
  username: your-github-username
  password: your-personal-access-token

Apply this secret to your cluster:

kubectl apply -f repo-secret.yaml -n argocd

4. Creating Your First Application

An ArgoCD Application is a custom resource that tells ArgoCD which Git repository to watch, where to find manifests, and which cluster and namespace to deploy to. You can create applications using the CLI, the web UI, or by applying a declarative YAML manifest. The declarative approach is strongly recommended for production setups because it allows you to version-control your application definitions.

Here is a complete example of an Application manifest that deploys a sample guestbook application from a public repository:

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

Let's break down each section of this manifest:

Apply this application manifest to your cluster:

kubectl apply -f guestbook-app.yaml -n argocd

Check the application status using the CLI:

argocd app get guestbook --server localhost:8080

You can also list all applications:

argocd app list --server localhost:8080

5. Understanding Sync Policies and Automation

ArgoCD offers three modes of synchronization. Manual sync requires an operator to explicitly trigger each sync via CLI or UI. Automated sync with self-heal enabled automatically corrects any drift between Git and the cluster. Automated sync without self-heal triggers a sync only when Git changes but does not automatically correct manual cluster modifications.

Here is a configuration example that enables fully automated sync with pruning:

syncPolicy:
  automated:
    prune: true
    selfHeal: true
    allowEmpty: false
  syncOptions:
    - CreateNamespace=true
    - PruneLast=true
    - ApplyOutOfSyncOnly=true
  retry:
    limit: 10
    backoff:
      duration: 10s
      factor: 2
      maxDuration: 10m

The PruneLast option ensures that resources are pruned only after new resources are applied, minimizing downtime. ApplyOutOfSyncOnly tells ArgoCD to only apply resources that are actually out of sync, speeding up large applications. The retry configuration with exponential backoff handles transient errors gracefully.

6. Working with Helm Charts

ArgoCD natively supports Helm charts. You can point to a chart repository or to a directory containing a Helm chart in your Git repository. Here is an application manifest for deploying a Helm chart from a Git repository with custom values:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-helm
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/helm-charts.git
    targetRevision: main
    path: charts/nginx
    helm:
      releaseName: my-nginx
      valueFiles:
        - values-prod.yaml
      values: |
        service:
          type: ClusterIP
        replicaCount: 3
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

For Helm chart repositories hosted on artifact hubs or private registries, use the chart field instead of path:

source:
  repoURL: https://helm.example.com/charts
  targetRevision: 2.5.1
  chart: nginx-ingress
  helm:
    values: |
      controller:
        metrics:
          enabled: true

7. Configuring Health Checks and Sync Hooks

ArgoCD evaluates the health of your deployed resources using built-in health checks for standard Kubernetes types and custom health checks defined via Lua scripts. You can define custom health checks in the argocd-cm ConfigMap. For example, to add a custom health check for a CRD:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.health.mycompany.io_v1_MyResource: |
    hs = {}
    hs.status = "Healthy"
    if obj.status.phase == "Error" then
      hs.status = "Degraded"
      hs.message = obj.status.errorMessage
    end
    return hs

Sync hooks allow you to run jobs before, during, or after a sync operation. Annotate your Kubernetes resources with specific hook annotations. Here is an example of a pre-sync hook that runs a database migration job:

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
      - name: migration
        image: your-db-migration-image:latest
        command: ["/bin/sh", "-c", "run-migrations.sh"]
      restartPolicy: Never
  backoffLimit: 2

Common hook types include PreSync (runs before the sync), Sync (runs during the sync), PostSync (runs after a successful sync), and SyncFail (runs when a sync fails). The hook-delete-policy annotation controls cleanup of the hook resource after execution.

8. Multi-Cluster Management

One of ArgoCD's most powerful features is its ability to manage multiple Kubernetes clusters from a single control plane. To add an external cluster, first register it with ArgoCD:

argocd cluster add my-cluster-context-name --name production-cluster

This command uses your local kubeconfig context to authenticate and register the cluster. You can also add clusters declaratively by creating a secret in the argocd namespace:

apiVersion: v1
kind: Secret
metadata:
  name: production-cluster-secret
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
  name: production-cluster
  server: https://prod-cluster-api.example.com
  config: |
    {
      "tlsClientConfig": {
        "insecure": false,
        "caData": "<BASE64_ENCODED_CA_CERT>",
        "certData": "<BASE64_ENCODED_CLIENT_CERT>",
        "keyData": "<BASE64_ENCODED_CLIENT_KEY>"
      }
    }

Once registered, you can target deployments to the remote cluster by specifying its server URL in your Application manifest's destination.server field.

Best Practices for ArgoCD Continuous Deployment

Keep Configuration Separate from Application Code

Maintain a dedicated Git repository for your Kubernetes manifests and ArgoCD application definitions, separate from your application source code. This separation ensures that code changes and infrastructure changes follow independent release cycles and approval workflows. It also prevents accidental deployment of untested infrastructure changes when application code is merged.

Implement Git Branching and Promotion Strategies

Use Git branches to model environment promotion. For example, maintain a staging branch and a production branch in your config repository. Point your staging ArgoCD application at the staging branch and your production application at the production branch. Promote changes by merging from staging to production after validation. This creates a clear, auditable promotion pipeline.

Secure Secrets Properly

Never store plain-text secrets in your Git repository. Use tools like Sealed Secrets, External Secrets Operator, or HashiCorp Vault with the ArgoCD Vault plugin. Here is an example of using Sealed Secrets with ArgoCD:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: database-credentials
  namespace: production
spec:
  encryptedData:
    username: AgA8bB...encrypted-base64...
    password: AgCBdD...encrypted-base64...

ArgoCD syncs the SealedSecret resource, and the Sealed Secrets controller decrypts it into a standard Kubernetes Secret inside the cluster.

Use Projects for Logical Isolation

Create separate ArgoCD projects for different teams or business units. Projects allow you to restrict which Git repositories, clusters, and resource types a team can deploy. Here is an example project definition with tight restrictions:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-frontend
  namespace: argocd
spec:
  description: Frontend team project
  sourceRepos:
    - https://github.com/my-org/frontend-configs.git
  destinations:
    - namespace: frontend-*
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: ""
      kind: Namespace
  namespaceResourceWhitelist:
    - group: ""
      kind: ConfigMap
    - group: apps
      kind: Deployment
    - group: networking.k8s.io
      kind: Ingress
  roles:
    - name: developer
      description: Standard developer role
      policies:
        - p, proj:team-frontend:developer, applications, sync, team-frontend/*, allow
      groups:
        - my-org:frontend-developers

Enable SSO and RBAC for Enterprise Deployments

Integrate ArgoCD with your organization's identity provider using OIDC or SAML. Configure the argocd-cm ConfigMap for OIDC integration with providers like Okta, Azure AD, or Google Workspace:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.example.com
  oidc.config: |
    name: Okta
    issuer: https://your-org.okta.com
    clientID: 0oa8abc123...
    clientSecret: $oidc.okta.clientSecret
    requestedScopes:
      - openid
      - profile
      - groups
    logoutURL: https://your-org.okta.com/login/signout

Combine SSO with fine-grained RBAC policies in the argocd-rbac-cm ConfigMap to map group memberships to ArgoCD roles.

Implement Progressive Delivery with Argo Rollouts

For advanced deployment strategies like blue-green and canary deployments, integrate ArgoCD with Argo Rollouts. Define a Rollout resource instead of a standard Deployment:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app-rollout
  namespace: production
spec:
  replicas: 5
  strategy:
    canary:
      steps:
        - setWeight: 20
        - pause: {duration: 10m}
        - setWeight: 40
        - pause: {duration: 10m}
        - setWeight: 100
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: my-app:2.0.0

ArgoCD syncs the Rollout resource, and Argo Rollouts handles the gradual traffic shifting and automated metric analysis.

Monitor Sync Status and Set Up Notifications

Configure ArgoCD notifications to alert your team about sync failures, degraded health, or successful deployments. Define notification triggers and templates in the argocd-notifications-cm ConfigMap. Here is a Slack notification configuration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.slack: |
    token: $slack-token
  triggers.trigger-on-sync-failed: |
    - when: app.status.operationState.phase == 'Error'
      send: [slack-channel]
  templates.template-slack: |
    message: |
      Application *{{.app.metadata.name}}* sync failed.
      Error: {{.app.status.operationState.message}}
    slack:
      channel: "#deployment-alerts"

Regularly Prune Stale Resources

Enable automated pruning in your sync policies to remove resources that exist in the cluster but are no longer defined in Git. This keeps your cluster clean and prevents resource sprawl. Always combine pruning with the PruneLast sync option to avoid service interruptions during configuration refactoring.

Version Your ArgoCD Configuration Itself

Treat your ArgoCD Application manifests, project definitions, and cluster configurations as code. Store them in a Git repository and apply them via a bootstrapping process. This ensures your entire continuous deployment pipeline is reproducible and recoverable.

Conclusion

ArgoCD transforms Kubernetes deployment from a manual, error-prone process into an automated, auditable, and reliable GitOps pipeline. By making Git the single source of truth for your cluster state, you gain continuous drift detection, automated synchronization, and a complete audit trail of every change. The setup process is straightforward: install ArgoCD on your cluster, connect your Git repositories, define your applications declaratively, and let the controller handle the rest. By following the best practices outlined here—separating config from code, securing secrets, using projects for isolation, enabling SSO, and implementing progressive delivery with Argo Rollouts—you will build a robust continuous deployment system that scales across teams and clusters. ArgoCD's active community, extensive documentation, and enterprise-grade features make it a cornerstone of modern Kubernetes delivery workflows.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles