GitOps with Argo CD: Simplifying Kubernetes Deployments Across Multiple Environments
What is GitOps and Why Should You Care?
GitOps is an operational framework that takes DevOps best practices used for application development such as version control, collaboration, compliance, and CI/CD, and applies them to infrastructure automation.
In simpler terms, GitOps makes Git your single source of truth for infrastructure. Changes to your infrastructure happen through Git operations (commits, pull requests, merges), and automated tools ensure your actual infrastructure matches what’s defined in your Git repository.
For Kubernetes environments, GitOps has emerged as the gold standard for deployment strategies. Why? Because it provides:
- Version control for your infrastructure: Track changes, roll back easily when needed
 - Audit trail: Who changed what and when is automatically documented
 - Consistency across environments: Define once, deploy everywhere with environment-specific tweaks
 - Self-documenting systems: Your Git repository becomes living documentation
 - Automation: Reduce manual operations and human error
 
The Challenge: Managing Multiple Environments
Many organizations struggle when implementing GitOps across multiple environments (dev, test, staging, production). A common approach is to use a branch strategy—maintaining a separate Git branch for each environment. This might seem intuitive initially, but it’s actually considered an anti-pattern for several reasons:
- Config drift: Changes made in development might not make it to production
 - Merge conflicts: Conflicts become increasingly difficult to resolve
 - Automation complexity: CI/CD pipelines become more complicated
 - Visibility issues: It’s harder to see the differences between environments
 
The Solution: Directories + Kustomize + Argo CD
Instead of using branches, a better approach leverages the power of directories combined with tools like Kustomize or Helm. This structure provides a clean, manageable way to handle multiple environments while maintaining a single source of truth.
Directory Structure That Works
Here’s an example structure using Kustomize:
apps/
    example-app/
        base/
            kustomization.yaml
            deployment.yaml
            service.yaml
            configmap.yaml
        overlays/
            dev/
                kustomization.yaml
                configmap.patch.yaml
            test/
                kustomization.yaml
                deployment.patch.yaml
            qa/
                kustomization.yaml
                deployment.patch.yaml
            prod/
                kustomization.yaml
                deployment.patch.yaml
                hpa.yaml
    example-app-2/
        ...
    application-set.yaml
In this structure:
base/contains the common configuration shared across all environmentsoverlays/contains environment-specific patches that modify the base configuration- Each environment’s 
kustomization.yamlreferences the base and applies its specific patches 
Kustomize: The Secret Sauce
Kustomize makes environment-specific configuration simple:
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: example-dev
patchesStrategicMerge:
  - configmap.patch.yaml
images:
  - name: example-app
    newTag: dev-latest
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
  - hpa.yaml
namespace: example-prod
patchesStrategicMerge:
  - deployment.patch.yaml
images:
  - name: example-app
    newTag: v1.2.3
With this approach, you can:
- Override namespaces per environment
 - Add environment-specific resources (like an HPA in production)
 - Modify resource limits or replica counts
 - Update image tags
 - Change config values
 
All while maintaining a clean separation and clear visibility of what’s different between environments.
Application Sets: Automating the Automation
Argo CD ApplicationSets supercharge your GitOps workflow by eliminating manual application creation. They’re like templates that automatically generate Argo CD Applications based on patterns.
Here’s an example ApplicationSet that would create applications for all environments of all apps:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: all-apps
spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: https://github.com/your-org/gitops-repo.git
              revision: HEAD
              directories:
                - path: apps/*/
          - list:
              elements:
                - env: dev
                  cluster: https://kubernetes.default.svc
                - env: test
                  cluster: https://kubernetes.default.svc
                - env: qa
                  cluster: https://kubernetes.default.svc
                - env: prod
                  cluster: https://kubernetes.default.svc
  template:
    metadata:
      name: "{{path.basename}}-{{env}}"
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/gitops-repo.git
        targetRevision: HEAD
        path: "{{path}}/overlays/{{env}}"
      destination:
        server: "{{cluster}}"
        namespace: "{{path.basename}}-{{env}}"
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
This single resource would create applications like:
- example-app-dev
 - example-app-test
 - example-app-qa
 - example-app-prod
 - example-app-2-dev
 - …and so on
 
No more manual application creation in the Argo CD UI!
The Full Picture: From Code to Cluster
Let’s tie it all together with a CI/CD workflow that makes deployments smooth:
- Developer pushes code to application repository
 - CI pipeline runs:
- Builds and tests the application
 - Creates a container image
 - Pushes the image to a registry
 - Updates the image tag in the GitOps repo (using tools like 
kustomize edit set image) 
 - Argo CD detects the change in the GitOps repo
 - Argo CD synchronizes the application configuration with the cluster
 - New version is deployed to the environment
 
With this workflow, you get:
- Fast, automated deployments
 - Full visibility and traceability
 - Easy rollbacks with 
git revert - Consistent practices across environments
 - Reduced manual operations
 
Summary
- GitOps provides significant benefits for Kubernetes deployments
 - Avoid using branches for environment separation; use directories instead
 - Kustomize makes environment-specific configuration clean and manageable
 - ApplicationSets eliminate manual application creation in Argo CD
 - A proper CI pipeline completes the automation picture
 
By implementing these patterns, you’ll create a smoother development experience, reduce operational overhead, and build a more reliable deployment process for your Kubernetes applications.
Happy GitOps-ing!