Skip to content

GitOps Repository Structure

Overview

The cluster-gitops repository implements a production-ready GitOps workflow using ArgoCD ApplicationSets for automated application deployment across multiple environments.

Repository Structure

cluster-gitops/
├── applicationsets/              # ApplicationSet definitions
│   ├── syrf.yaml                # SyRF services (auto-generated Applications)
│   ├── infrastructure.yaml      # External infrastructure components
│   └── custom-charts.yaml       # Custom Helm charts from this repo
├── infrastructure/               # External infrastructure component configs
│   ├── cert-manager/
│   │   ├── config.yaml          # Points to external Helm chart
│   │   └── values.yaml          # Values for external chart
│   ├── ingress-nginx/
│   ├── rabbitmq/
│   └── external-secrets-operator/
├── charts/                       # Custom Helm charts (self-contained)
│   └── extra-secrets/
│       ├── Chart.yaml
│       ├── values.yaml          # Default values
│       ├── values-staging.yaml  # Environment overrides
│       ├── values-production.yaml
│       └── templates/
├── syrf/                         # SyRF application configuration
│   ├── global.values.yaml       # Values for ALL services in ALL environments
│   ├── services/                # Base service configurations
│   │   └── {service}/
│   │       ├── config.yaml      # Service metadata (chart path, repo)
│   │       └── values.yaml      # Base Helm values
│   └── environments/            # Per-environment configuration
│       ├── staging/
│       │   ├── namespace.yaml   # Environment metadata
│       │   ├── staging.values.yaml  # Environment-wide Helm values
│       │   └── {service}/       # Service configs (updated by CI/CD)
│       │       ├── config.yaml  # Service version (chartTag)
│       │       └── values.yaml  # Service-specific values
│       ├── production/
│       │   ├── production.values.yaml
│       │   └── ...
│       └── preview/
│           ├── preview.values.yaml
│           └── ...
├── argocd/
│   ├── projects/                # AppProject definitions (RBAC)
│   │   ├── syrf-staging.yaml
│   │   ├── syrf-production.yaml
│   │   ├── infrastructure.yaml
│   │   └── preview.yaml
│   ├── config/                  # ArgoCD configuration
│   ├── resources/               # ArgoCD's own resources
│   └── bootstrap/
├── scripts/
│   └── promote-to-production.sh
└── docs/
    ├── architecture/
    ├── decisions/
    └── how-to/

Design Principles

1. Separation of Concerns

Three ApplicationSets for Different Purposes:

  1. syrf.yaml - Application services from the syrf monorepo
  2. Auto-discovers services from syrf/*/config.yaml
  3. Creates Applications for each service × environment combination
  4. Single source of truth: environments/*/syrf.yaml for versions

  5. infrastructure.yaml - External infrastructure components

  6. Deploys charts from public Helm registries (Bitnami, Jetstack, etc.)
  7. Configuration in infrastructure/*/config.yaml
  8. Values in infrastructure/*/values.yaml

  9. custom-charts.yaml - Custom charts maintained in this repo

  10. Auto-discovers charts from charts/ directory
  11. Self-contained: chart + values together
  12. Use case: Migrated charts from Jenkins X, organization-specific wrappers

2. Value Hierarchy

Values merge in order (last wins):

1. Chart defaults (in monorepo chart)
2. syrf/global.values.yaml (ALL services, ALL environments)
3. syrf/services/{service}/values.yaml (THIS service base, ALL environments)
4. syrf/environments/{env}/{env}.values.yaml (ALL services in THIS environment)
5. syrf/environments/{env}/{service}/values.yaml (THIS service, THIS environment)

Example for API in Production:

  • Chart defaults (from monorepo)
    • syrf/global.values.yaml
    • syrf/services/api/values.yaml
    • syrf/environments/production/production.values.yaml
    • syrf/environments/production/api/values.yaml

Naming Convention:

  • global.values.yaml - Universal defaults
  • {env}.values.yaml - Environment-specific (staging.values.yaml, production.values.yaml)
  • values.yaml - Base service or service-specific values

3. Single Source of Truth for Versions

Only environments/*/syrf.yaml changes on deployment:

# environments/staging/syrf.yaml
services:
  - name: api
    enabled: true
    chartTag: api-v8.21.1  # ← CI/CD updates this line

Image tags are automatically derived from chartTags: - api-v8.21.1 → image tag 8.21.1 - No duplication across multiple files - Chart version and image version always match

4. RBAC with AppProjects

AppProject Purpose Who Can Deploy Sync Policy
syrf-staging Staging applications Developers + CI/CD Auto-sync, 24/7
syrf-production Production applications Platform team only Manual approval, sync windows
infrastructure Platform components Platform team only Manual sync only
preview PR preview environments Developers + CI/CD Auto-sync, ephemeral

Sync Windows: - Production: Blocked during business hours (9am-5pm Mon-Fri UTC) - Staging: Always allowed - Infrastructure: Always manual

Key Features

Auto-Discovery with ApplicationSets

Matrix Generator Pattern:

Environments × Services = Applications

(staging, production) × (api, web, pm, quartz, docs, user-guide)
= api-staging, api-production, web-staging, web-production, ...

Selective Deployment

Services can be selectively deployed per environment:

# environments/staging/syrf.yaml
services:
  - name: api
    enabled: true
    chartTag: api-v8.21.1

  - name: quartz
    enabled: false  # Not deployed to staging

ApplicationSet filters ensure only enabled services are deployed.

Optional Value Files

Uses Helm's ignoreMissingValueFiles: true feature: - Service-specific values files are optional - If syrf/api/values-staging.yaml doesn't exist, it's skipped - Allows flexibility in value overrides

Deployment Workflows

Staging (Automatic)

1. Developer pushes to main branch
2. CI/CD builds image and creates git tag
3. CI/CD updates environments/staging/syrf.yaml with new chartTag
4. GitHub webhook triggers ArgoCD
5. ApplicationSet regenerates Application with new version
6. ArgoCD syncs to cluster

Time: ~1-2 minutes

Production (Manual)

1. Run promotion script or manually edit environments/production/syrf.yaml
2. Create PR for review
3. Team reviews and approves
4. Merge PR
5. ArgoCD syncs (respects sync windows)

Time: Manual approval + sync window

Migration from Old Structure

Before

apps/
  api-staging.yaml          # Manual Application manifest
  api-production.yaml       # Manual Application manifest
  web-staging.yaml
  web-production.yaml
  ... (12+ files)

environments/
  staging/
    api.values.yaml         # Version defined here
  production/
    api.values.yaml         # Version defined here (drift risk)

Problems: - 12+ manually maintained Application manifests - Version duplication (chartTag in apps/, image tag in values/) - Add new service = create 2+ new files - Change common config = update 12+ files

After

applicationsets/
  syrf.yaml                 # ONE ApplicationSet generates all

syrf/
  api/
    config.yaml             # Static metadata
    values.yaml             # Static defaults

environments/
  staging/
    syrf.yaml               # ALL service versions (single source of truth)
  production/
    syrf.yaml

Benefits: - 3 ApplicationSets instead of 12+ Application manifests - Single source of truth for versions - Add new service = create 1 config directory - Change common config = update 1 template - Auto-discovery from directory structure

Common Operations

Deploy New Service Version to Staging

Automatic via CI/CD:

# CI/CD does this automatically
yq eval -i '(.services[] | select(.name == "api") | .chartTag) = "api-v8.21.1"' \
  environments/staging/syrf.yaml

git add environments/staging/syrf.yaml
git commit -m "chore(api): deploy v8.21.1 to staging"
git push

Promote to Production

Manual via script:

./scripts/promote-to-production.sh api api-v8.21.1
# Creates PR for review

Add New Service

  1. Create service config:

    mkdir -p syrf/new-service
    cat > syrf/new-service/config.yaml <<EOF
    service:
      name: new-service
      chartPath: src/services/new-service/charts/new-service
      chartRepo: https://github.com/camaradesuk/syrf.git
    EOF
    

  2. Add to environment lists:

    yq eval -i '.services += [{"name": "new-service", "enabled": true, "chartTag": "new-service-v0.1.0"}]' \
      environments/staging/syrf.yaml
    

  3. Push to git → ApplicationSet creates Applications automatically

Add Custom Chart

  1. Create chart structure:

    mkdir -p charts/my-chart/templates
    # Add Chart.yaml, values.yaml, values-staging.yaml, values-production.yaml
    

  2. Push to git → ApplicationSet discovers and deploys automatically

References