# GitOps for Application Environments

> **CNPA Domain:** Continuous Delivery & Platform Engineering (16%) **Topic:** GitOps for Application Environments

## Overview

Applying GitOps to manage **multiple application environments** — dev, staging, production, preview — is one of the highest-value use cases for platform engineering. When every environment is a Git-declared state, promotion between environments is a controlled, auditable process rather than a risky manual procedure.

***

## Environment Promotion with GitOps

The central challenge of multi-environment delivery is **promotion**: moving a verified artifact from one environment to the next with confidence.

```
CI Pipeline produces image:
  registry.example.com/payment-service:abc1234

GitOps Promotion Flow:
  [staging manifests] ──PR merge──▶ [staging cluster reconciles]
          ↓ (tests pass + approval)
  [production manifests] ──PR merge──▶ [production cluster reconciles]
```

All promotions are Git pull requests — reviewable, reversible, traceable.

***

## Repository Structure for Multi-Environment GitOps

### Environment Directory Pattern

```
platform-gitops/
├── apps/
│   └── payment-service/
│       ├── base/               # Shared Kustomize base
│       │   ├── kustomization.yaml
│       │   └── deployment.yaml
│       ├── staging/            # Staging overlay
│       │   ├── kustomization.yaml
│       │   └── image-patch.yaml
│       └── production/         # Production overlay
│           ├── kustomization.yaml
│           └── image-patch.yaml
├── clusters/
│   ├── staging-cluster/        # Flux/ArgoCD config per cluster
│   └── production-cluster/
└── infrastructure/
    ├── monitoring/
    └── networking/
```

### Image Update per Environment

```yaml
# apps/payment-service/staging/image-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
spec:
  template:
    spec:
      containers:
        - name: payment-service
          image: registry.example.com/payment-service:abc1234  # ← CI updates this
```

***

## Automated Image Promotion

### Flux Image Automation

Flux can automatically update image tags in Git when a new image is pushed to the registry:

```yaml
# Image policy: track semver tags
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: payment-service
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: payment-service
  policy:
    semver:
      range: ">=2.0.0 <3.0.0"
```

```yaml
# Image automation: commit new tags to Git
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: flux-image-update
  namespace: flux-system
spec:
  interval: 5m
  sourceRef:
    kind: GitRepository
    name: platform-gitops
  git:
    checkout:
      ref:
        branch: main
    commit:
      author:
        name: Flux Bot
        email: flux@example.com
      messageTemplate: |
        chore: update {{range .Updated.Images}}{{println .}}{{end}}
    push:
      branch: main
  update:
    strategy: Setters
```

This commits updated image tags back to Git automatically — keeping the repo as the true source of deployment history.

***

## Progressive Delivery

GitOps integrates naturally with **progressive delivery** strategies that reduce deployment risk.

### Deployment Strategies

| Strategy           | How                               | Risk     | Rollback               |
| ------------------ | --------------------------------- | -------- | ---------------------- |
| **Recreate**       | Stop old, start new               | Downtime | New deploy             |
| **Rolling Update** | Replace pods gradually            | Low      | `kubectl rollout undo` |
| **Blue/Green**     | Run both versions, switch traffic | Low      | Switch back instantly  |
| **Canary**         | Route % of traffic to new version | Very Low | Reduce canary to 0%    |

### Argo Rollouts (Canary via GitOps)

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: payment-service
spec:
  replicas: 5
  strategy:
    canary:
      steps:
        - setWeight: 10       # 10% canary traffic
        - pause: {duration: 5m}
        - analysis:           # Automated analysis
            templates:
              - templateName: success-rate
        - setWeight: 50       # 50% canary traffic
        - pause: {duration: 10m}
        - setWeight: 100      # Full promotion
```

If the analysis step fails (e.g., error rate > threshold), the rollout automatically aborts and rolls back.

***

## Preview Environments via GitOps

Preview environments are ephemeral environments created for each pull request.

### PR Preview Workflow

```
PR opened on application repo
    ↓
CI builds image: registry.example.com/payment-service:pr-42-ab1cd
    ↓
CI commits to platform-gitops:
  apps/payment-service/preview/pr-42/kustomization.yaml
    ↓
ArgoCD/Flux detects new path
    ↓
Creates namespace: preview-pr-42
Deploys application with PR image
    ↓
CI posts URL to PR comment:
  https://pr-42.payment-service.preview.example.com
    ↓
PR merged / closed → CI deletes preview directory from GitOps repo
Namespace and resources automatically garbage-collected
```

```yaml
# apps/payment-service/preview/pr-42/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: preview-pr-42
images:
  - name: payment-service
    newTag: pr-42-ab1cd
```

***

## Multi-Cluster GitOps

Platform teams often manage GitOps across **multiple clusters** (per environment, per region, per tenant).

### Fleet Management with ArgoCD ApplicationSets

```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: payment-service-all-envs
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - env: staging
            cluster: https://staging.k8s.example.com
            namespace: payments-staging
          - env: production
            cluster: https://prod.k8s.example.com
            namespace: payments-production
  template:
    metadata:
      name: "payment-service-{{env}}"
    spec:
      project: payments
      source:
        repoURL: https://github.com/example/platform-gitops
        targetRevision: HEAD
        path: apps/payment-service/{{env}}
      destination:
        server: "{{cluster}}"
        namespace: "{{namespace}}"
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
```

A single `ApplicationSet` manages all environments — add a new cluster by adding one list entry.

***

## GitOps Promotion Policies

Mature platform engineering teams define **promotion policies** enforced through Git branch protection and CI checks:

| Policy                                           | Enforcement                             |
| ------------------------------------------------ | --------------------------------------- |
| All staging tests must pass before production PR | CI status check required on GitOps repo |
| Production changes require 2 approvals           | Branch protection rule                  |
| No direct commits to production directory        | CODEOWNERS file                         |
| Image tags must be immutable SHA-based           | Policy check in CI                      |

***

## Key Takeaways

* GitOps turns environment promotion into an auditable Git workflow: **PR → review → merge → reconcile**
* Use a **centralized GitOps repo** with per-environment directories managed by the platform team
* **Flux image automation** can auto-commit new image tags to keep Git in sync with the registry
* **Progressive delivery** (canary, blue/green) with Argo Rollouts integrates naturally with GitOps for safer deployments
* **Preview environments** are ephemeral namespaces created and destroyed via GitOps per pull request
* **ApplicationSets** in ArgoCD enable fleet-wide multi-cluster GitOps with minimal configuration

***

## Further Reading

* [Argo Rollouts Documentation](https://argo-rollouts.readthedocs.io/)
* [Flux Image Automation](https://fluxcd.io/docs/components/image/)
* [ArgoCD ApplicationSets](https://argo-cd.readthedocs.io/en/stable/user-guide/applicationset/)
* → Next: [Platform Capabilities Model](https://blog.htunnthuthu.com/getting-started/fundamentals/platform-engineering-101/platform-engineering-101-capabilities-model)
