Amazon EKS — ArgoCD on EKS

2 minute read

ArgoCD is the most popular GitOps tool for Kubernetes. It watches a Git repository and continuously reconciles the desired state (manifests in Git) with the actual state (what’s running in the cluster).


Install ArgoCD

kubectl create namespace argocd

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

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

Get Initial Admin Password

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

Install ArgoCD CLI

brew install argocd

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

ALB Ingress for ArgoCD UI

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server
  namespace: argocd
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:123456789012:certificate/abc-123
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/backend-protocol: HTTPS
    alb.ingress.kubernetes.io/healthcheck-path: /healthz
spec:
  ingressClassName: alb
  rules:
    - host: argocd.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: argocd-server
                port:
                  number: 443

Application CRD

Define an ArgoCD Application to manage a workload:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/my-org/k8s-manifests.git
    targetRevision: main
    path: apps/my-app/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true         # Delete resources removed from Git
      selfHeal: true      # Revert manual changes in cluster
    syncOptions:
      - CreateNamespace=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        maxDuration: 3m0s
        factor: 2

Key sync options:

Option Description
automated.prune Delete resources not in Git
automated.selfHeal Override manual changes in cluster
CreateNamespace=true Create target namespace if missing
ServerSideApply=true Use server-side apply (avoids annotation limits)

ApplicationSet for Multi-Environment

Deploy the same app across multiple clusters or environments:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - cluster: staging
            url: https://staging-cluster-api.example.com
            namespace: staging
          - cluster: production
            url: https://prod-cluster-api.example.com
            namespace: production
  template:
    metadata:
      name: "my-app-"
    spec:
      project: default
      source:
        repoURL: https://github.com/my-org/k8s-manifests.git
        targetRevision: main
        path: "apps/my-app/overlays/"
      destination:
        server: ""
        namespace: ""
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

Multi-Cluster Management

Register external clusters:

# Add staging cluster
argocd cluster add staging-cluster-context --name staging

# Add production cluster
argocd cluster add production-cluster-context --name production

# List registered clusters
argocd cluster list

SSO with AWS Cognito

Configure ArgoCD to use Cognito for authentication:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.example.com
  oidc.config: |
    name: Cognito
    issuer: https://cognito-idp.us-east-1.amazonaws.com/<user-pool-id>
    clientID: <client-id>
    clientSecret: $oidc.cognito.clientSecret
    requestedScopes:
      - openid
      - profile
      - email

RBAC policy:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    g, platform-team, role:admin
    g, dev-team, role:readonly
  policy.default: role:readonly

ArgoCD Image Updater

Automatically update image tags in Git when new images are pushed to ECR:

kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml

Annotate your Application:

metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-list: my-app=123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app
    argocd-image-updater.argoproj.io/my-app.update-strategy: semver
    argocd-image-updater.argoproj.io/my-app.allow-tags: "regexp:^v[0-9]+\\.[0-9]+\\.[0-9]+$"
    argocd-image-updater.argoproj.io/write-back-method: git

Best Practices

  1. Enable auto-sync with prune and selfHeal — ensures Git is always the source of truth
  2. Use ApplicationSets for multi-env/multi-cluster — DRY configuration
  3. Store ArgoCD Applications in Git (app of apps pattern) — manage ArgoCD with ArgoCD
  4. Configure SSO — don’t use the admin password in production
  5. Use Image Updater — automate image tag updates without manual Git commits
  6. Separate infra and app repos — platform team manages infra, dev teams manage app manifests

Updated: