RSS

How to Deploy ArgoCD with Terraform on Kubernetes

Terraform Kubernetes GitOps CI/CD

What you’ll learn: This guide walks you through the deployment of Argo CD to Kubernetes using Terraform's Kubernetes and Helm providers, covering Argo CD installation, application repository configuration, RBAC setup for multi-tenancy, and GitOps workflow integration that automatically deploys applications from Git commits without manual kubectl commands.

kubectl apply works until it doesn't. You start with a few deployments, manage them by hand, and everything feels manageable. Then your team grows, environments multiply, and suddenly you're tracking which version of what application runs where through Slack messages.

GitOps makes Git the single source of truth for cluster state, and Argo CD implements this by automatically syncing your cluster with repository contents. However, manually installing Argo CD with kubectl or bash scripts means every environment needs identical manual steps, and configuration drift creeps in between clusters.

Terraform treats Argo CD installation as infrastructure code. The same configuration that provisions your Kubernetes cluster deploys Argo CD, configures repositories, and sets up application definitions. You get reproducible installations, proper state management, and integration between infrastructure provisioning and continuous delivery. This guide explores the setup, from deploying Argo CD components to configuring your first GitOps applications.

What is Argo CD in Kubernetes?

What is Argo CD

Argo CD is a declarative GitOps continuous delivery tool built specifically for Kubernetes.

It monitors Git repositories containing Kubernetes manifests and automatically makes sure that your cluster state matches what's defined in those repositories. Unlike traditional CI/CD tools that push changes through external orchestration, Argo CD runs inside Kubernetes and uses native Kubernetes APIs to manage resources.

When you commit a change to Git, Argo CD detects the difference between your desired state and the live cluster, then applies the necessary changes to reconcile them without plugins or translation layers.

Argo CD in Kubernetes

Argo CD itself is just another Kubernetes application. It runs as a collection of deployments, services, and config maps inside your cluster, typically in a dedicated namespace.

The architecture comprises an API server that handles requests and the web UI, a repository server that clones and caches Git repositories, and an application controller that continuously monitors applications and compares their live state with the desired state. Additional components handle Redis caching and notifications.

Argo CD architectural overview showing the API server, repository server, and application controller inside the cluster, with Git repositories and the Kubernetes API as external interfaces.
Argo CD architectural overview (source)

Because Argo CD lives inside the cluster it manages, it uses Kubernetes service accounts and RBAC for authentication.

The application controller watches for changes in both Git repositories and cluster state through standard Kubernetes mechanisms, which makes it efficient and reduces external dependencies.

This in-cluster architecture means Argo CD can manage the cluster it runs in, though it can also reach out to manage external clusters when configured with appropriate credentials.

Argo CD and GitOps

GitOps relies on three core principles:

  1. Infrastructure and applications are defined declaratively
  2. Git serves as the single source of truth
  3. Changes are automatically applied when the desired state diverges from the actual state.

Argo CD implements all three by treating Git repositories as the authoritative definition of what should run in your cluster, then continuously reconciling any differences it finds.

The pull model distinguishes Argo CD from push-based deployment tools. Instead of your CI pipeline having credentials to push changes into production clusters, Argo CD pulls changes from Git repositories on its own schedule. Your CI pipeline's job ends at updating a Git repository, and Argo CD handles the deployment.

This separation reduces the attack surface because compromising your CI system doesn't give an attacker direct cluster access. It also provides automatic drift detection, as Argo CD constantly compares the cluster state with the Git state, regardless of how the changes occurred.

How to use Argo CD

Argo CD automates application deployment to Kubernetes clusters by monitoring Git repositories and automatically syncing changes. Teams use it to eliminate manual kubectl commands, enforce consistency across environments, and maintain deployment history through Git commits. The deployment patterns vary based on organizational needs, for example:

To integrate with existing tools, you need to follow a clear division of responsibilities. Your CI pipeline handles building, testing, and pushing container images, then updates Kubernetes manifests in Git with new image tags or configuration changes. Argo CD watches those manifest repositories and deploys changes based on sync policies you define, while monitoring tools like Prometheus and Grafana observe the deployed applications. The benefits and trade-offs of this approach become clear once you understand how Argo CD fits into your workflow:

Benefits Challenges
Eliminates kubectl sprawl across team members Initial setup requires understanding GitOps patterns
Provides a complete deployment audit trail through Git history Learning curve for teams new to declarative configuration
Enables true rollback through Git revert operations Managing secrets outside Git requires additional tooling
Reduces deployment complexity with automated synchronization Requires a solid Git workflow foundation and discipline
Automatic drift detection catches manual cluster changes Debugging sync failures needs familiarity with Argo CD logs
Self-healing capabilities fix configuration drift automatically Multi-cluster setups add authentication complexity

These benefits come from specific features that distinguish Argo CD from other deployment tools:

How to deploy Argo CD on Kubernetes

Before deploying Argo CD, you need a running Kubernetes cluster (if you're using AWS, see our guide on deploying an AWS EKS cluster with Terraform), Terraform installed and configured, kubectl access to your target cluster, and a Git repository ready for your Argo CD configuration. The cluster should already exist and be accessible, since Terraform will use your current kubectl context or explicit credentials to deploy resources.

Using Terraform to deploy Argo CD

Terraform's Helm provider offers the cleanest path to deploying Argo CD because it handles the complexity of multiple Kubernetes resources while giving you reproducible installations. Configure the provider to authenticate with your cluster, then deploy the official Argo CD Helm chart:

provider "helm" {
  kubernetes {
    config_path = "~/.kube/config"
  }
}

resource "helm_release" "argocd" {
  name             = "argocd"
  repository       = "https://argoproj.github.io/argo-helm"
  chart            = "argo-cd"
  namespace        = "argocd"
  create_namespace = true
  version          = "5.51.6"

  values = [
    file("${path.module}/argocd-values.yaml")
  ]
}

This approach beats kubectl apply or bash scripts because Terraform tracks the installation in state (for more on state management, see managing Terraform state on AWS), which makes it easy to update Argo CD versions or modify configuration later. The chart version pins to a specific release, preventing unexpected changes during terraform apply.

Configuration and access

Argo CD needs external access for both the API server and web UI. You have two options:

  1. Expose it through a LoadBalancer service
  2. Configure an Ingress with TLS

LoadBalancer works for quick setups but costs more in cloud environments, while Ingress integrates with existing ingress controllers and certificate managers:

resource "kubernetes_ingress_v1" "argocd" {
  metadata {
    name      = "argocd-server"
    namespace = helm_release.argocd.namespace
    annotations = {
      "cert-manager.io/cluster-issuer" = "letsencrypt-prod"
    }
  }

  spec {
    ingress_class_name = "nginx"
    tls {
      hosts       = ["argocd.example.com"]
      secret_name = "argocd-tls"
    }
    rule {
      host = "argocd.example.com"
      http {
        path {
          path      = "/"
          path_type = "Prefix"
          backend {
            service {
              name = "argocd-server"
              port { number = 80 }
            }
          }
        }
      }
    }
  }
}

The initial admin password gets generated automatically and stored in a Kubernetes secret. Retrieve it through kubectl or, better yet, output it from Terraform so your team can access the UI immediately after deployment. Remember that secrets must ideally be stored in a secrets manager like Vault.

Connecting repositories and creating applications

Argo CD applications define what to deploy and where it should be deployed. Create them through Terraform using the Kubernetes provider to declare custom resources. Here is an example:

resource "kubernetes_manifest" "example_app" {
  manifest = {
    apiVersion = "argoproj.io/v1alpha1"
    kind       = "Application"
    metadata = {
      name      = "example-app"
      namespace = "argocd"
    }
    spec = {
      project = "default"
      source = {
        repoURL        = "https://github.com/your-org/manifests"
        targetRevision = "main"
        path           = "apps/example"
      }
      destination = {
        server    = "https://kubernetes.default.svc"
        namespace = "production"
      }
      syncPolicy = {
        automated = {
          prune    = true
          selfHeal = true
        }
      }
    }
  }
}

This application watches the manifests repository, automatically syncs changes when they appear in the main branch, and enables self-healing so Argo CD reverts manual changes back to the Git-defined state. The prune setting removes resources that have been deleted from Git, completing the GitOps loop. The key to a successful setup is understanding which components belong in Terraform and which belong in your GitOps workflow:

Infrastructure component Managed by Reason
Kubernetes cluster Terraform Foundation infrastructure
Argo CD installation Terraform One-time setup that’s versioned
Application definitions Terraform Infrastructure-adjacent config
Application manifests Git + Argo CD Frequent updates, team workflow

This separation keeps infrastructure provisioning and application deployment in their appropriate layers. Terraform creates the cluster and installs Argo CD, then Argo CD handles ongoing application deployments without requiring terraform apply for every app update. For a complete view of how Terraform and Argo CD work together across the entire stack, see our guide on end-to-end GitOps with Terraform and ArgoCD.

Best practices for Argo CD

Getting Argo CD deployed is one thing, but running it effectively in production requires following patterns that prevent common pitfalls. These are some key practices that should be considered at scale:

Repository structure

Separate application manifests from Argo CD configuration to keep concerns isolated. One repository holds your Argo CD application definitions and projects, while separate repositories contain the actual Kubernetes manifests for each application. Monorepos work well for smaller teams deploying related services together, while multi-repos give larger organizations independence between teams. To learn about how to structure your Terraform code, see our guide on Terraform code organization.

Secret management

Never commit secrets to Git. Use Sealed Secrets to encrypt secrets with asymmetric cryptography, so only your cluster can decrypt them, or use External Secrets Operator to pull secrets from AWS Secrets Manager, HashiCorp Vault, or other secret stores at runtime.

Sync strategies

Automatic sync works well for non-production environments where speed matters more than control. Production deployments often need manual sync approval to give teams a chance to verify changes during business hours or coordinate with database migrations. Configure retry logic for transient failures, but set reasonable limits to avoid endlessly retrying broken configurations.

Custom health checks

Custom resource definitions need explicit health checks since Argo CD doesn't know how to assess their readiness by default. Define these in Argo CD's configuration map, and specify which fields indicate health for your CRDs.

Monitoring integration

Argo CD exports Prometheus metrics covering sync status, application health, and API performance. Set up alerts for repeated sync failures, applications stuck in progressing state, or sudden increases in out-of-sync resources. For integrating these metrics into your broader infrastructure monitoring, our Grafana deployment guide provides a comprehensive setup guide.

Backup and versioning

Export Argo CD application definitions regularly through kubectl or the CLI, storing them outside your cluster, which protects against accidental deletion and provides disaster recovery. Version pinning in your Terraform configuration prevents unexpected Argo CD updates during routine infrastructure changes.

Alternative deployment options and tools

While this guide focuses on Argo CD deployed to Kubernetes clusters, your infrastructure choices and tooling preferences might differ based on team experience and existing investment:

Option Use case Key consideration
Google Kubernetes Engine (GKE) Managed Kubernetes on Google Cloud Integrated monitoring with Cloud Operations, Workload Identity for authentication
Azure Kubernetes Service (AKS) Managed Kubernetes on Azure Azure AD integration, tight coupling with Azure services
Self-hosted Kubernetes Complete infrastructure control More operational overhead, flexibility for hybrid deployments
FluxCD Alternative GitOps operator Operator-based architecture, Kubernetes-native patterns
Jenkins X Traditional CI/CD extended for Kubernetes Better fit for teams already invested in Jenkins ecosystem

FluxCD offers a compelling alternative to Argo CD with its operator-based architecture and GitOps Toolkit components, which some teams find more aligned with Kubernetes philosophy.

Jenkins X makes sense if your organization already runs Jenkins and wants to extend existing pipelines rather than adopting new tooling. The key decision factors are team size, existing infrastructure, multi-cloud requirements, and GitOps maturity.

Conclusion

Terraform and Argo CD together create a complete GitOps workflow where infrastructure provisioning and application deployment work as integrated layers. Terraform handles cluster creation and Argo CD installation, while Argo CD manages ongoing application deployments through Git without manual kubectl commands.

Start with a single cluster and basic setup to prove the workflow, then expand to multi-cluster management as your team's GitOps maturity increases. Stategraph Orchestration enhances this by adding Terraform automation, policy enforcement, and drift detection without requiring separate CI/CD configuration.