How to Deploy ArgoCD with Terraform on Kubernetes
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.
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:
- Infrastructure and applications are defined declaratively
- Git serves as the single source of truth
- 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:
- Single cluster management works for smaller teams where Argo CD runs in the same cluster it manages
- Multi-cluster orchestration is necessary for managing staging and production from a central control plane
- Environment promotion workflows let you test changes in development before pushing to production through Git branches or tags.
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:
- Application definitions: Declare what to deploy and where using Kubernetes custom resources
- Sync policies: Control whether changes apply automatically or require manual approval, including sync windows and self-healing options
- Health assessment: Built-in monitoring for standard Kubernetes resources to determine deployment success
- Sync strategies: Support hooks for pre-sync and post-sync operations like database migrations, with sync waves for ordered deployments
- Multi-tenancy: Projects isolate different teams or applications with separate RBAC policies
- UI and CLI: Web interface for visual management alongside CLI for automation and scripting
- SSO integration: Support for OIDC, SAML, and other authentication providers
- Notifications: Integration with Slack, webhooks, and monitoring systems for deployment alerts
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:
- Expose it through a LoadBalancer service
- 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.