Skip to content

GitOps Workflow

What is GitOps?

GitOps is a deployment methodology where: - Git is the single source of truth - Changes are made via Git commits - Deployments happen automatically - No manual kubectl commands needed

DineTogether GitOps Flow with FluxCD

graph TB
    A[Developer] -->|1. Push Code| B[App Repository]
    B -->|2. Trigger CI| C[GitHub Actions]
    C -->|3. Build & Push| D[GHCR Registry]
    D -->|4. New Image| E[Flux Image Automation]
    E -->|5. Update Tag| F[Infrastructure Repo]
    F -->|6. Git Commit| G[HelmRelease/Kustomization]
    G -->|7. Flux Reconcile| H[K3s Cluster]
    H -->|8. Pull Image| D
    H -->|9. Deploy| I[Running Application]

Key Principles

1. Declarative Configuration

Everything is declared in Git: - Application deployment in HelmRelease manifests - Configuration in values.yaml files - Infrastructure as code via Kustomize/Helm

2. Version Control

All changes are: - Tracked in Git history - Reviewable via Pull Requests - Revertible if needed - Auditable for compliance

3. Automated Reconciliation

FluxCD ensures: - Continuous reconciliation of desired state - Automatic rollback on failures - Self-healing infrastructure - No configuration drift

Workflow Steps Explained

Step 1: Developer Pushes Code

git add .
git commit -m "feat: add new feature"
git push origin main

Step 2: CI/CD Builds Image

GitHub Actions in app repository:

- name: Build and push Docker image
  uses: docker/build-push-action@v5
  with:
    push: true
    tags: |
      ghcr.io/dine-together/app:latest
      ghcr.io/dine-together/app:sha-${{ github.sha }}

Step 3: Flux Detects New Image

FluxCD components watch for new images:

# ImageRepository - Scans GHCR
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: app
  namespace: flux-system
spec:
  image: ghcr.io/dine-together/app
  interval: 1m
# ImagePolicy - Selects latest tag
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: app
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: app
  policy:
    alphabetical:
      order: asc
  filterTags:
    pattern: '^sha-[a-f0-9]+'

Step 4: Automatic Tag Update

ImageUpdateAutomation commits new tag to Git:

apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
  name: infra-updater
  namespace: flux-system
spec:
  interval: 1m
  sourceRef:
    kind: GitRepository
    name: infra
  git:
    commit:
      author:
        name: Flux
        email: flux@dinetogether.co.uk
      messageTemplate: "chore: update images"
    push:
      branch: main
  update:
    strategy: Setters

Step 5: HelmRelease Deployment

Flux applies the updated HelmRelease:

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: app
  namespace: staging
spec:
  interval: 5m
  chart:
    spec:
      chart: nextjs-app
      sourceRef:
        kind: GitRepository
        name: app-charts
  values:
    image:
      repository: ghcr.io/dine-together/app
      tag: sha-abc123  # {"$imagepolicy": "flux-system:app:tag"}

Step 6: K3s Deployment

Kubernetes performs rolling update: - Creates new pods with new image - Waits for health checks to pass - Terminates old pods - Zero downtime achieved

Manual GitOps Operations

Deploy New Application

  1. Create HelmRelease:

    cat > clusters/staging/apps/my-app/helmrelease.yaml <<EOF
    apiVersion: helm.toolkit.fluxcd.io/v2
    kind: HelmRelease
    metadata:
      name: my-app
      namespace: staging
    spec:
      # ... configuration
    EOF
    

  2. Commit and push:

    git add clusters/staging/apps/my-app/
    git commit -m "feat: deploy my-app to staging"
    git push
    

  3. Flux automatically deploys

Update Configuration

  1. Edit HelmRelease values:

    vi clusters/staging/apps/my-app/helmrelease.yaml
    

  2. Commit changes:

    git commit -am "chore: increase replicas for my-app"
    git push
    

  3. Flux applies changes

Rollback Deployment

Option 1 - Git revert:

git revert HEAD
git push

Option 2 - Flux suspend and resume:

flux suspend helmrelease my-app -n staging
# Fix issues
flux resume helmrelease my-app -n staging

Monitoring GitOps

Check Flux Status

# Overall status
flux get all

# Specific app
flux get helmrelease my-app -n staging

# Watch reconciliation
flux logs --follow

Check Git Sync

# Source status
flux get sources git

# Last sync
flux get kustomization cluster-staging

Debug Issues

# Events
flux events

# Detailed errors
flux get helmrelease my-app -n staging -o yaml

GitOps Best Practices

1. Repository Structure

k8s-infrastructure/
├── clusters/
│   ├── staging/
│   │   └── apps/          # Staging apps
│   └── production/
│       └── apps/          # Production apps
└── apps/
    └── base/              # Shared configurations

2. Environment Promotion

  • Develop in staging branch
  • Test thoroughly
  • Promote via PR to production
  • Use different value files per environment

3. Secret Management

Never commit secrets to Git: - Use Sealed Secrets - Use External Secrets Operator - Use SOPS with Flux - Reference existing K8s secrets

4. Change Management

  • All changes via Pull Request
  • Require reviews for production
  • Use semantic commit messages
  • Tag releases appropriately

Advantages of GitOps

Developer Experience

  • Familiar Git workflows
  • No kubectl access needed
  • Self-service deployments
  • Clear deployment history

Operations

  • Consistent deployments
  • Automatic rollbacks
  • Disaster recovery via Git
  • Complete audit trail

Security

  • No cluster credentials in CI/CD
  • All changes reviewed
  • Principle of least privilege
  • Immutable infrastructure

Troubleshooting

Image Not Updating

Check image automation:

flux get images all -A
flux get imageupdateautomation -A

Deployment Stuck

Check HelmRelease:

kubectl describe helmrelease my-app -n staging
kubectl get events -n staging

Sync Issues

Force reconciliation:

flux reconcile source git infra
flux reconcile kustomization cluster-staging

Next Steps