aws-eks-gitops
Implementing GitOps with AWS EKS and ArgoCD for Production Systems
GitOps, when applied effectively, transforms Kubernetes cluster management into a declarative, auditable, and automated process. This guide details how to establish a robust GitOps workflow using Amazon Elastic Kubernetes Service (EKS) and ArgoCD, targeting experienced engineers who need to manage production environments.
TL;DR: This guide outlines the integration of ArgoCD with AWS EKS for a GitOps workflow. It covers EKS cluster setup, ArgoCD installation and access, manifest repository structure, ArgoCD application definition, and best practices for production environments.
Introduction to GitOps and its Benefits
GitOps is a paradigm for cloud-native application delivery and infrastructure management that leverages Git as the single source of truth. All desired cluster states and application configurations are version-controlled in Git. An automated agent, such as ArgoCD, continuously reconciles the cluster state with the Git repository.
Key benefits for production systems include:
- Auditable State: Every change is a Git commit, providing a complete audit trail of what changed, when, and by whom.
- Reproducibility: Entire environments can be recreated from Git, crucial for disaster recovery and testing.
- Reliability: Rollbacks are as simple as reverting a Git commit and letting GitOps reconcile.
- Developer Productivity: Developers manage infrastructure through familiar Git workflows.
- Enhanced Security: Reduced need for direct cluster access for deployments.
Prerequisites
Before proceeding, ensure you have:
- An AWS account with sufficient IAM permissions to create and manage EKS clusters, IAM roles, and networking resources.
- AWS CLI v2 installed and configured with credentials.
- installed and configured to interact with AWS EKS.
kubectl - installed for EKS cluster provisioning.
eksctl - A Git provider account (e.g., GitHub, GitLab, Bitbucket) and a dedicated Git repository for cluster configurations.
Step 1: Provisioning an Amazon EKS Cluster
Production-grade EKS clusters require careful configuration beyond basic defaults. We'll use
eksctl# Example: Provisioning a production-ready EKS cluster # Consider using a dedicated VPC, subnets, and security groups for isolation. # Adjust instance types, scaling, and Kubernetes versions based on workload requirements. eksctl create cluster \ --name my-prod-gitops-cluster \ --region us-west-2 \ --version 1.29 \ --nodegroup-name standard-workers \ --node-type t3.large \ --nodes 3 \ --nodes-min 2 \ --nodes-max 5 \ --managed \ --asg-access \ --external-dns-access \ --full-ecr-access \ --alb-ingress-access \ --ssh-access \ --with-oidc \ --scopes "eks:ClusterControlPlane:*" # Ensure necessary permissions for control plane
Note: For production, a dedicated VPC with appropriate subnet configurations (public/private) and NAT gateways is strongly recommended. IAM roles for service accounts (IRSA) are crucial for secure pod access to AWS services.
Step 2: Installing ArgoCD on EKS
ArgoCD will be the engine that synchronizes your Git repository with the EKS cluster.
# Create the ArgoCD namespace kubectl create namespace argocd # Apply the ArgoCD installation manifest kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml # Monitor ArgoCD components until they are running kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name=argocd-server -n argocd --timeout=300s kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name=argocd-application-controller -n argocd --timeout=300s
Step 3: Accessing the ArgoCD UI and CLI
ArgoCD provides a web UI and a CLI for interaction.
Accessing the ArgoCD UI
To access the UI securely, it's best practice to expose it via an Ingress controller or a LoadBalancer. For initial access or development, port-forwarding is convenient:
# Retrieve the initial admin password # Note: In production, it's highly recommended to reset this password immediately. initial_admin_secret=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d) echo "ArgoCD Initial Admin Password: $initial_admin_secret" # Port-forward the ArgoCD server (use a different local port if 8080 is in use) kubectl port-forward svc/argocd-server -n argocd 8080:443 # Access the UI at: https://localhost:8080 # Username: admin # Password: <The password obtained above>
Configuring the ArgoCD CLI
Install the ArgoCD CLI and configure it to connect to your cluster:
# Download and install ArgoCD CLI (example for Linux) curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 chmod +x argocd sudo mv argocd /usr/local/bin/ # Login to ArgoCD (if not using port-forwarding, adjust the --grpc-web flag and host) argocd login localhost:8080 --username admin --password "$initial_admin_secret" --insecure
Security Note: For production, consider configuring ArgoCD to use TLS termination via an Ingress controller and integrate with your identity provider (e.g., OIDC, SAML) for authentication instead of relying on the static initial password.
Step 4: Structuring Your Git Repository for Configurations
A well-organized Git repository is fundamental to GitOps. We recommend a structure that separates environments and leverages a configuration management tool like Kustomize or Helm.
Recommended Structure using Kustomize:
├── apps/ │ └── my-app/ │ ├── base/ │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── kustomization.yaml │ ├── overlays/ │ │ ├── dev/ │ │ │ ├── kustomization.yaml │ │ │ └── patch-replicas.yaml # Example patch │ │ └── prod/ │ │ ├── kustomization.yaml │ │ └── patch-resources.yaml # Example patch ├── clusters/ │ └── dev-cluster/ │ ├── argocd-apps/ │ │ ├── my-app.yaml │ │ └── another-app.yaml ├── infrastructure/ │ └── ... # E.g., CNI, Ingress controller manifests └── README.md
Example apps/my-app/base/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: app-container image: nginx:1.25-alpine # Use specific, immutable image tags ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "100m"
Example apps/my-app/base/service.yaml
apiVersion: v1 kind: Service metadata: name: my-app-svc spec: selector: app: my-app ports: - port: 80 targetPort: 80 type: ClusterIP # Use ClusterIP by default, expose via Ingress
Example apps/my-app/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml - service.yaml # Add common labels, annotations, or namespaces here if applicable to all environments commonLabels: app.kubernetes.io/managed-by: argocd
Example apps/my-app/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../base # Inherit base configurations # Environment-specific configurations for 'dev' namespace: dev patchesStrategicMerge: - patch-replicas.yaml - patch-image.yaml # Example to update image for a specific deployment images: - name: nginx newName: nginx newTag: 1.25-alpine # Ensure image tags are immutable and specific
Example apps/my-app/overlays/dev/patch-replicas.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 2 # Development environment may require fewer replicas
Example apps/my-app/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../base namespace: prod patchesStrategicMerge: - patch-replicas.yaml - patch-resources.yaml
Example apps/my-app/overlays/prod/patch-replicas.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 5 # Production environment requires higher replicas
Example apps/my-app/overlays/prod/patch-resources.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: template: spec: containers: - name: app-container resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"
Step 5: Defining ArgoCD Applications
An ArgoCD
ApplicationCreate a YAML file for your ArgoCD Application, for example,
clusters/dev-cluster/argocd-apps/my-app.yamlapiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: my-app-dev namespace: argocd # ArgoCD applications are managed in the argocd namespace spec: project: default # Use projects for RBAC and organization source: repoURL: https://github.com/your-username/your-gitops-repo.git # Your Git repository URL targetRevision: HEAD # Or a specific branch like 'main' or 'develop' path: apps/my-app/overlays/dev # Path to Kustomize overlays for the dev environment destination: server: https://kubernetes.default.svc # Target cluster (default is in-cluster) namespace: dev # Target namespace within the cluster syncPolicy: automated: prune: true # Automatically prune resources deleted from Git selfHeal: true # Automatically sync if the cluster state drifts from Git syncOptions: - CreateNamespace=true # Automatically create the target namespace if it doesn't exist
Apply this to your EKS cluster:
kubectl apply -f clusters/dev-cluster/argocd-apps/my-app.yaml
You can now see this application in the ArgoCD UI. Click "Sync" to apply the configurations, or let the automated sync (if enabled) handle it.
Multi-Cluster Strategy: For multi-cluster deployments, you'd create separate ArgoCD
Applicationhttps://<cluster-endpoint>Step 6: The GitOps Workflow in Action
- Developer Commits: A developer makes a code change and pushes it to the application's source code repository. Simultaneously, they update the Kubernetes manifests in the configuration Git repository (e.g., changing an image tag, resource limits).
- Git Push: The developer commits and pushes changes to the configuration Git repository.
- ArgoCD Detects Change: ArgoCD, configured to watch the specified and
repoURL, detects a new commit.path - ArgoCD Pulls: ArgoCD pulls the latest manifests from the Git repository.
- Reconciliation: ArgoCD compares the desired state (from Git) with the actual state of the EKS cluster.
- Apply Changes: ArgoCD applies the necessary Kubernetes API calls (e.g., ) to bring the cluster state in line with the Git repository.
kubectl apply - Reporting: ArgoCD reports the synchronization status (Synced, OutOfSync, Syncing, Error) in its UI and via its API.
Example Git Push for Update:
Let's say you want to update the
nginxdev-
Modify
(or update theapps/my-app/overlays/dev/patch-image.yamldirectly innewTagif not patching):kustomization.yaml# Example patch-image.yaml (if not updating kustomization.yaml directly) apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: template: spec: containers: - name: app-container image: nginx:1.26-alpine # Updated image tag -
Commit and push:
git add apps/my-app/overlays/dev/patch-image.yaml git commit -m "feat: Update nginx image to 1.26 for dev environment" git push origin main # Or your primary branch -
ArgoCD will detect this change, pull it, and update the
deployment in themy-app-devnamespace.dev
Best Practices for Production GitOps
- Repository Strategy:
- Monorepo vs. Polyrepo: For moderate complexity, a monorepo for configurations can be simpler. For large organizations, separate repos for applications and clusters (or environments) improve access control and modularity.
- Environment Separation: Clearly separate configurations for ,
dev,staging, etc., using overlays or separate directories.prod - Immutable Image Tags: Always use specific, immutable image tags (e.g., ) instead of
nginx:1.26.0-alpine. Image updates should be a Git commit.latest
- Security:
- Access Control: Implement strict RBAC within ArgoCD and on EKS. Grant only the necessary permissions.
argocd-application-controller - Credentials: Use SSH keys or tokens for Git repository access, stored securely as Kubernetes secrets. Regularly rotate these credentials.
- Network Policies: Restrict network access to ArgoCD components and your EKS cluster.
- Manifest Scanning: Integrate security scanning tools (e.g., OPA Gatekeeper, Trivy) into your GitOps pipeline or as pre-commit hooks.
- Access Control: Implement strict RBAC within ArgoCD and on EKS. Grant
- Operational Hygiene:
- Health Checks: Define robust Kubernetes liveness and readiness probes. ArgoCD's has a
Applicationsetting to monitor application health.healthPolicy - Resource Management: Set clear CPU and memory requests/limits for all application pods.
- Monitoring & Alerting: Monitor ArgoCD sync status, application health, and cluster resource utilization. Set up alerts for sync failures or application degradation.
- Rollbacks: Version-controlled manifests naturally support rollbacks. Revert a commit in Git and let ArgoCD reconcile.
- Progressive Delivery: Leverage Argo Rollouts or other tools for advanced deployment strategies like canary or blue/green deployments, managed through GitOps.
- Health Checks: Define robust Kubernetes liveness and readiness probes. ArgoCD's
Honest Trade-offs
- Learning Curve: While GitOps simplifies deployments, mastering ArgoCD, Kustomize/Helm, and Git strategies requires an initial investment in learning.
- Complexity of Setup: The initial setup of EKS, ArgoCD, and the Git repository structure can be intricate, especially for beginners.
- State Drift: While addresses it, frequent manual interventions outside of Git can lead to complex state drift scenarios that ArgoCD might struggle to reconcile automatically without careful debugging.
selfHeal - Large Monorepos: For extremely large numbers of applications and environments, managing a single monorepo can become unwieldy. This necessitates exploring multi-repo strategies.
- CI/CD Integration: GitOps is often complemented by CI pipelines that build container images and update manifest repositories. Integrating these requires careful design.
When Not to Use GitOps (or ArgoCD specifically)
- Ephemeral Environments/Testing: For temporary development environments or quick, unmanaged testing where a strict Git-based workflow is overhead.
- Highly Manual/Interactive Operations: Environments where direct, frequent, manual Kubernetes resource manipulation is a primary operational mode.
- Simple, Single-Pod Applications: For very small, non-critical applications where the complexity of ArgoCD and GitOps might outweigh the benefits.
- Lack of Git Expertise: If your team does not have a strong understanding or adoption of Git practices, implementing GitOps will face significant cultural and technical hurdles.
- Strictly Regulated Environments with Manual Approval Steps: While GitOps can facilitate manual approval (e.g., pull request reviews), environments requiring complex, multi-party manual sign-offs before any action can be taken might need custom tooling or a hybrid approach.
Decision Checklist
Before adopting GitOps with ArgoCD and EKS:
- [ ] Git Adoption: Is your team proficient and comfortable with Git workflows (commits, pull requests, branching)?
- [ ] Automation Goals: Do you aim to automate application deployments and infrastructure management?
- [ ] Auditability Requirements: Is an auditable history of all infrastructure and application changes critical?
- [ ] Reproducibility Needs: Do you need the ability to reliably recreate environments from scratch?
- [ ] Kubernetes Expertise: Does your team have a solid understanding of Kubernetes concepts (Deployments, Services, ConfigMaps, etc.)?
- [ ] Scalability: Do you anticipate managing a growing number of applications and environments?
- [ ] Security Posture: Can you integrate GitOps practices with your existing security policies (RBAC, secret management, network segmentation)?
- [ ] Tooling Investment: Are you prepared to invest time in setting up and maintaining ArgoCD, Git repositories, and potentially CI pipelines?
- [ ] Error Handling Strategy: Do you have a plan for how to handle sync failures and application misconfigurations within a GitOps framework?
Conclusion
Implementing GitOps with AWS EKS and ArgoCD provides a powerful, scalable, and auditable framework for managing Kubernetes environments. By adopting this approach, you enhance reliability, improve developer velocity, and establish a robust audit trail for all cluster and application state changes. Careful planning of your Git repository structure, security configurations, and operational practices will be key to a successful production deployment.
Additional Resources
- ArgoCD Documentation: https://argo-cd.readthedocs.io/
- AWS EKS Best Practices: https://aws.github.io/aws-eks-best-practices/
- Kubernetes Documentation: https://kubernetes.io/docs/
- Kustomize Documentation: https://kubectl.docs.kubernetes.io/references/kustomize/
- GitOps Principles: https://opengitops.dev/