Environment Promotion
Environment promotion is the process of moving applications through different environments (development → staging → production) in a controlled, automated manner. GitOps provides several patterns for implementing promotion workflows.
Promotion Concepts
Promotion ensures:
- Consistency - Same process for all environments
- Traceability - Complete audit trail
- Safety - Controlled, reviewed changes
- Automation - Reduce manual errors
Promotion Strategies
Strategy 1: Branch-Based Promotion
Each environment has its own Git branch.
Structure:
repo/
├── apps/
│ └── web-app/
│ ├── deployment.yaml
│ └── service.yaml
ArgoCD Applications:
# Dev Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-dev
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: dev
path: apps/web-app
---
# Staging Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-staging
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: staging
path: apps/web-app
---
# Production Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-prod
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: production
path: apps/web-app
Promotion Process:
# 1. Merge to dev
git checkout dev
git merge feature-branch
git push
# 2. Promote to staging
git checkout staging
git merge dev
git push
# 3. Promote to production
git checkout production
git merge staging
git push
Benefits:
- Clear environment separation
- Easy to see what’s in each environment
- Simple promotion (merge branches)
Limitations:
- Requires branch management
- Can have merge conflicts
- Multiple branches to maintain
Strategy 2: Directory-Based Promotion
Environments organized in directories, all in main branch.
Structure:
repo/
├── apps/
│ └── web-app/
│ ├── base/
│ └── overlays/
│ ├── dev/
│ ├── staging/
│ └── production/
Kustomize Overlays:
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
images:
- name: web-app
newTag: dev-latest
---
# overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
images:
- name: web-app
newTag: staging-v1.2.3
---
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
images:
- name: web-app
newTag: v1.2.3
ArgoCD Applications:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-dev
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: main
path: apps/web-app/overlays/dev
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-prod
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: main
path: apps/web-app/overlays/production
Promotion Process:
# Update image tag in production overlay
cd apps/web-app/overlays/production
# Edit kustomization.yaml to update image tag
git commit -m "Promote web-app v1.2.3 to production"
git push
Benefits:
- Single branch (main)
- Easy to compare environments
- All changes in one place
Limitations:
- Requires careful directory management
- Can accidentally promote wrong version
Strategy 3: Tag-Based Promotion
Use Git tags to mark versions for promotion.
ArgoCD Applications:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-dev
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: v1.2.3-dev
path: apps/web-app
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-prod
spec:
source:
repoURL: https://github.com/org/repo
targetRevision: v1.2.3-prod
path: apps/web-app
Promotion Process:
# Tag for dev
git tag v1.2.3-dev
git push --tags
# Tag same commit for staging
git tag v1.2.3-staging
git push --tags
# Tag for production
git tag v1.2.3-prod
git push --tags
Automated Promotion
Using ArgoCD ApplicationSets
Automate promotion with ApplicationSets:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: web-app
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
namespace: dev
imageTag: dev-latest
- env: staging
namespace: staging
imageTag: staging-v1.2.3
- env: production
namespace: production
imageTag: v1.2.3
template:
metadata:
name: 'web-app-{{env}}'
spec:
project: default
source:
repoURL: https://github.com/org/repo
targetRevision: main
path: apps/web-app/overlays/{{env}}
kustomize:
images:
- web-app:myregistry/web-app:{{imageTag}}
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Using Flux ImageUpdateAutomation
Automate image updates across environments:
# Dev ImageUpdateAutomation
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: web-app-dev
namespace: flux-system
spec:
interval: 5m0s
sourceRef:
kind: GitRepository
name: manifests
git:
checkout:
ref:
branch: main
commit:
author:
name: Flux
email: [email protected]
messageTemplate: 'Update dev image: {{range .Updated.Images}}{{println .}}{{end}}'
push:
branch: main
update:
path: ./apps/web-app/overlays/dev
strategy: Setters
---
# Production ImageUpdateAutomation (manual trigger)
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: web-app-prod
namespace: flux-system
spec:
interval: 24h0m0s # Less frequent
sourceRef:
kind: GitRepository
name: manifests
git:
checkout:
ref:
branch: main
commit:
author:
name: Flux
email: [email protected]
messageTemplate: 'Promote to prod: {{range .Updated.Images}}{{println .}}{{end}}'
push:
branch: main
update:
path: ./apps/web-app/overlays/production
strategy: Setters
Using CI/CD Integration
Promote via CI/CD pipelines:
# GitHub Actions example
name: Promote to Production
on:
workflow_dispatch:
inputs:
version:
description: 'Version to promote'
required: true
jobs:
promote:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Update production image
run: |
cd apps/web-app/overlays/production
sed -i "s/newTag: .*/newTag: ${{ github.event.inputs.version }}/" kustomization.yaml
- name: Create PR
uses: peter-evans/create-pull-request@v5
with:
title: "Promote web-app ${{ github.event.inputs.version }} to production"
branch: promote-prod
Promotion Gates and Approvals
Manual Approval Gates
Require approval before promotion:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-prod
namespace: argocd
spec:
syncPolicy:
syncWindows:
- kind: allow
schedule: '0 2 * * 1-5'
duration: 2h
manualSync: true
- kind: deny
schedule: '* * * * *'
manualSync: false
ArgoCD Sync Windows
Control when promotions can happen:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
syncWindows:
- kind: allow
schedule: '0 2 * * 1-5' # Weekdays 2 AM
duration: 2h
applications:
- 'production-*'
manualSync: true
- kind: deny
schedule: '* * * * *'
applications:
- 'production-*'
CI/CD Approval Gates
Use CI/CD for approval workflows:
# GitLab CI example
promote_to_prod:
stage: promote
only:
- main
when: manual # Requires manual trigger
script:
- ./scripts/promote-to-prod.sh
environment:
name: production
Rollback Strategies
Git Revert
Revert the promotion commit:
# Revert last promotion
git revert HEAD
git push
# GitOps controller automatically applies rollback
Tag Rollback
Point to previous tag:
# Update Application to previous tag
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app-prod
spec:
source:
targetRevision: v1.2.2 # Previous version
Kustomize Rollback
Revert image tag in overlay:
# Revert to previous image tag
cd apps/web-app/overlays/production
# Edit kustomization.yaml
git commit -m "Rollback to v1.2.2"
git push
Best Practices
1. Use Semantic Versioning
Tag versions consistently:
# Format: v<major>.<minor>.<patch>
git tag v1.2.3
git tag v1.2.3-dev
git tag v1.2.3-staging
git tag v1.2.3-prod
2. Automate Testing
Run tests before promotion:
# CI/CD pipeline
stages:
- test
- promote-dev
- test-staging
- promote-staging
- test-production
- promote-production
3. Require Approvals for Production
Always require manual approval for production:
spec:
syncPolicy:
# No automated sync for production
syncWindows:
- kind: allow
schedule: '0 2 * * 1-5'
manualSync: true
4. Document Promotion Process
Create runbooks:
# Promotion Process
1. Merge to dev branch
2. Verify in dev environment
3. Create PR to staging
4. Review and merge
5. Verify in staging
6. Create PR to production
7. Get approval
8. Merge to production
5. Monitor Promotions
Set up alerts for:
- Failed promotions
- Promotion approvals
- Rollbacks
Troubleshooting
Promotion Not Happening
# Check Application status
argocd app get web-app-prod
# Check sync status
argocd app sync web-app-prod
# Check sync windows
argocd app get web-app-prod --show-operation
Wrong Version Promoted
# Check current version
argocd app get web-app-prod
# Rollback
git revert <commit-hash>
git push
Summary
Environment promotion in GitOps:
- Branch-based - Separate branches per environment
- Directory-based - Overlays in same branch
- Tag-based - Git tags mark versions
- Automated - Use ApplicationSets or ImageUpdateAutomation
- Gated - Require approvals for production
- Traceable - All changes in Git
Choose a strategy based on your needs:
- Simple teams - Directory-based
- Complex workflows - Branch-based
- Version control - Tag-based
Always require approvals for production and maintain clear promotion processes.