Skip to content
Ravin Vasudev
Back to all articles

August 8, 2026 : 5 min read

How We Built a Production-Grade GitOps Pipeline with Argo CD and AWS EKS (A Practical Deep Dive)

A practical guide to building a production-grade GitOps pipeline using Argo CD and AWS EKS, with a focus on security, visibility, and multi-environment promotion workflows.

  • GitOps
  • ArgoCD
  • AWS
  • EKS
  • Kubernetes
  • DevOps
  • PlatformEngineering
  • ContinuousDelivery

When engineering teams first look into GitOps, the definition often sounds deceptively simple: "Use Git as your single source of truth for your infrastructure."

But how does that actually translate into production when you are managing real-world traffic, dealing with databases, and deploying across multiple environments?

Lately, our team built and refined a highly resilient, enterprise-grade GitOps architecture using AWS EKS, Argo CD, and Helm. It completely decoupled our application logic from our infrastructure configuration, simplified our secrets management, and automated our promotion gates from Development straight through to Production.

If you are trying to move away from legacy deployment models, here is the exact architectural blueprint, repository structure, and promotion workflow we used.


Paradigm Shift: Traditional CI/CD vs. Modern GitOps

To appreciate why this architecture works so well, it helps to contrast it against the traditional deployment methods many teams still struggle to maintain.

The Traditional Approach: The "Push" Model

In a traditional setup (using Jenkins, GitLab CI, or standard GitHub Actions), your CI runner acts as an all-powerful administrator.

  • How it works: The code builds, and the pipeline executes direct commands like kubectl apply -f manifests/ or helm upgrade --install.
  • The Security Flaw: Your CI pipeline runner must hold long-lived, high-privilege credentials (like AWS IAM keys or cluster kubeconfig files) to access your EKS cluster. If your CI system is compromised, your entire cloud infrastructure is exposed.
  • The Visibility Flaw: Your deployment is fire-and-forget. The pipeline pushes the files and terminates. If an engineer later logs into the AWS Console or uses CLI tools to manually modify a live service, the CI runner has no idea. This creates Configuration Drift.

The GitOps Approach: The "Pull" Model

We completely flipped this mechanism on its head. Instead of pushing code into AWS EKS from the outside, we pulled it from the inside.

  • How it works: Argo CD lives inside our EKS cluster. It is granted native, localized service permissions. It constantly watches our Git repository and pulls changes inward.
  • The Security Win: No external system holds cluster-admin credentials. GitHub doesn't know how to access our cluster; our cluster only knows how to read public/private Git repositories.
  • The Visibility Win: Argo CD continuously loops. If someone manually changes a configuration on the live EKS cluster, Argo CD instantly detects that the system state no longer matches Git, raises an alarm, and can automatically overwrite the manual change to heal the system.

The Core Architecture Blueprint

Here is what our continuous reconciliation loop looks like in action:

[ Developer Pushes Code ] ──> [ Application Repo ]
                                     │
                                     ▼ (CI Builds & Pushes)
                              [ AWS ECR Registry ]
                                     │
                                     ▼ (CI updates image tag)
                              [ Configuration Repo (Git) ]
                                     │
                                     ▼ (Continuous Pull & Sync)
                             [ Argo CD Controller ]
                                     │ (Inside EKS)
                                     ▼
                        [ AWS EKS Cluster (Live State) ]

1. The Repository Architecture

To achieve clean compliance and avoid accidental infrastructure disruptions, we decoupled our engineering into two distinct, independent repositories: the Application Repository and the Configuration Repository.

Repository 1: The Application Repo

Contains application logic (Node.js, Go, Python, etc.), Dockerfiles, and unit tests. Developers commit here dozens of times a day. It has zero knowledge of Kubernetes environments.

Repository 2: The Configuration Repo

This is the single source of truth for our infrastructure. It houses our Helm charts and environment configurations.

To prevent rewriting base templates for every single environment, we utilize a unified Helm chart paired with separate environment-specific values files. Here is what our directory layout looks like:

├── charts/
│   └── web-app/                  # Shared base Helm chart
│       ├── Chart.yaml
│       └── templates/            # Ingress, Deployment, Service definitions
├── environments/
│   ├── values-dev.yaml           # Low replica counts, dev DB endpoints
│   ├── values-qa.yaml            # QA-specific test configurations
│   ├── values-staging.yaml       # Mirrors production configurations
│   └── values-prod.yaml          # High availability configurations
└── secrets/
    ├── secret-dev.sealed.yaml    # Encrypted Bitnami Sealed Secrets
    └── secret-prod.sealed.yaml

2. Solving the Secrets Paradox

One of the biggest hurdles in GitOps is secret management. Since your Git repo is the source of truth, how do you handle sensitive database credentials without committing plaintext passwords?

We solved this by using a hybrid approach utilizing Bitnami Sealed Secrets and AWS Secrets Manager.

For core application secrets, we use Sealed Secrets. This allows us to encrypt sensitive strings locally using a public key. The resulting encrypted string (SealedSecret) is entirely safe to commit to Git. Once Argo CD pushes the manifest to EKS, an in-cluster Sealed Secrets controller decrypts it into a standard, native Kubernetes Secret.

# Example: secrets/secret-dev.sealed.yaml
apiVersion: ://bitnami.com
kind: SealedSecret
metadata:
  name: database-credentials
  namespace: development
spec:
  encryptedData:
    password: AgBybG9...[Only your EKS cluster can decrypt this]...f93ka

3. The Lifecycle: From Commit to Production

The magic of this architecture shines brightest during our multi-environment promotion cycle. We blended automated velocity in lower environments with human-governed Pull Requests (PRs) for production stability.

Phase 1: Automated Dev Deployments

  1. A developer merges a feature branch into the Application Repo.
  2. The CI pipeline builds the Docker image and pushes it to AWS ECR tagged with the commit SHA (e.g., web-app:v1.2.0-sha123).
  3. The pipeline immediately fires a script that modifies the image.tag inside environments/values-dev.yaml in the Config Repo.
  4. Argo CD detects the change, marks the cluster as OutOfSync, and immediately deploys the new image to the EKS Dev namespace.
# environments/values-dev.yaml
replicaCount: 2
image:
  repository: ://amazonaws.com
  tag: v1.2.0-sha123 # Automatically bumped by Dev CI

Phase 2: Controlled QA Promotion

Once the dev team confirms the build is healthy, it is time for QA testing.

To move the change forward, the QA team opens a Pull Request to merge the new image tag from values-dev.yaml into values-qa.yml.

Before the QA lead merges the PR, automated checks run in the pipeline (helm template and kube-linter) to ensure the YAML is valid and free of syntax errors. Once approved and merged, Argo CD deploys it to the QA namespace.

Phase 3: Staging and Production Gating

This exact Pull Request model repeats for Staging and Production environments. Moving software between environments becomes an issue of code promotion, documented transparently through Git commit logs and peer-reviewed PR approvals.


Why This Approach Changed Everything For Us

Implementing this structure yielded massive dividends for our operational maturity:

  1. Zero Configuration Drift: Manual cluster modifications are caught and overwritten by Argo CD automatically.
  2. Instant Disaster Recovery: Rebuilding a failed cluster is trivial. Spin up a fresh cluster, point Argo CD to our configuration repo, and the entire system heals itself back to its exact state in minutes.
  3. Flawless Auditing: If a bug crashes production at 2:00 AM, we no longer guess what changed. Our Git history tells the exact story: who approved the tag change, what environment values were modified, and precisely when it rolled out.

What does your deployment infrastructure look like? Are you leveraging a pull-based GitOps flow with Argo CD or Flux, or are you still relying on traditional push pipelines? Let’s discuss in the comments below!