Reference

ArgoCD Configuration

Complete technical reference for the ArgoCD Application manifest that deploys GitLab BDA.

ArgoCD Application Manifest

The ArgoCD Application CR (Custom Resource) that manages GitLab BDA deployment:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: gitlab-bda
  namespace: argocd
  labels:
    app.kubernetes.io/name: gitlab-bda
    app.kubernetes.io/part-of: gitlab-platform
  annotations:
    argocd.argoproj.io/sync-wave: "0"
spec:
  # Project: RBAC boundary for this application
  project: default

  # Source: Git repository containing manifests
  source:
    repoURL: https://git.bluedynamics.eu/kup6s/dp/dp-infra.git
    targetRevision: main
    path: gitlabbda/manifests

  # Destination: Where to deploy resources
  destination:
    server: https://kubernetes.default.svc
    namespace: gitlabbda

  # Sync Policy: Automation and behavior
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=true

  # Ignore differences in certain fields
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas  # Ignore HPA-managed replicas

  # Info: Additional metadata displayed in UI
  info:
    - name: Environment
      value: staging
    - name: Documentation
      value: https://git.bluedynamics.eu/kup6s/dp/dp-infra/-/tree/main/documentation

Field Reference

metadata

Field

Type

Required

Description

name

string

✅ Yes

Application name (shown in ArgoCD UI)

namespace

string

✅ Yes

Must be argocd (ArgoCD’s namespace)

labels

map

⚠️ Optional

Labels for grouping/filtering applications

annotations

map

⚠️ Optional

Annotations (rarely needed)

Example:

metadata:
  name: gitlab-bda
  namespace: argocd
  labels:
    environment: staging
    team: platform

spec.project

Field

Type

Required

Description

project

string

✅ Yes

AppProject name (RBAC boundary)

Values:

  • default - Default project (no restrictions)

  • Custom project name - Enforces allowed sources, destinations, resources

Example:

spec:
  project: default  # Most common

Custom project example:

# Create AppProject first
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: gitlab-platform
  namespace: argocd
spec:
  sourceRepos:
    - https://git.bluedynamics.eu/kup6s/dp/*
  destinations:
    - namespace: gitlabbda
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'

# Then reference in Application
spec:
  project: gitlab-platform

spec.source

Field

Type

Required

Description

repoURL

string

✅ Yes

Git repository URL

targetRevision

string

✅ Yes

Branch, tag, or commit SHA

path

string

✅ Yes

Path within repo to manifests

Example:

spec:
  source:
    repoURL: https://git.bluedynamics.eu/kup6s/dp/dp-infra.git
    targetRevision: main  # Or: v1.0.0, abc123
    path: gitlabbda/manifests       # Directory containing YAML files

Multiple sources (ArgoCD 2.6+):

spec:
  sources:
    - repoURL: https://git.bluedynamics.eu/kup6s/dp/dp-infra.git
      targetRevision: main
      path: gitlabbda/manifests
    - repoURL: https://helm-repo.example.com
      chart: gitlab
      targetRevision: 18.5.1

spec.destination

Field

Type

Required

Description

server

string

✅ Yes*

Kubernetes API server URL

name

string

✅ Yes*

Cluster name (alternative to server)

namespace

string

✅ Yes

Target namespace

*One of server or name required.

Example:

spec:
  destination:
    server: https://kubernetes.default.svc  # Deploy to same cluster as ArgoCD
    namespace: gitlabbda

Remote cluster example:

spec:
  destination:
    name: production-cluster  # Cluster registered in ArgoCD
    namespace: gitlabbda

spec.syncPolicy

Field

Type

Required

Description

automated

object

⚠️ Optional

Auto-sync configuration

syncOptions

list

⚠️ Optional

Sync behavior options

retry

object

⚠️ Optional

Retry failed syncs

automated

Field

Type

Default

Description

prune

bool

false

Delete resources removed from git

selfHeal

bool

false

Revert manual changes to cluster

allowEmpty

bool

false

Allow syncing to empty git directory

Example:

spec:
  syncPolicy:
    automated:
      prune: true       # Delete resources not in git
      selfHeal: true    # Revert kubectl edits
      allowEmpty: false # Prevent accidental deletion

Prune behavior:

# Scenario: Delete ConfigMap from git
git rm manifests/configmap.yaml
git commit -m "Remove unused ConfigMap"
git push

# With prune: true
# ArgoCD deletes ConfigMap from cluster

# With prune: false
# ConfigMap remains in cluster (drift)

SelfHeal behavior:

# Scenario: Manual kubectl edit
kubectl scale deployment/gitlab-webservice --replicas=5

# With selfHeal: true
# ArgoCD detects drift, scales back to git value (2)

# With selfHeal: false
# ArgoCD shows "OutOfSync" but doesn't fix

syncOptions

Option

Description

CreateNamespace=true

Create namespace if it doesn’t exist

ApplyOutOfSyncOnly=true

Only apply changed resources (faster)

PrunePropagationPolicy=foreground

Wait for dependents before deleting

PruneLast=true

Prune resources after new ones are healthy

Replace=true

Use kubectl replace instead of apply

ServerSideApply=true

Use server-side apply (K8S 1.22+)

Validate=false

Skip kubectl validation

RespectIgnoreDifferences=true

Honor ignoreDifferences during sync

Example:

spec:
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=true
      - PruneLast=true

Common combinations:

Standard deployment:

syncOptions:
  - CreateNamespace=true
  - ApplyOutOfSyncOnly=true

Database deployments (graceful shutdown):

syncOptions:
  - PrunePropagationPolicy=foreground
  - PruneLast=true

Large deployments (faster):

syncOptions:
  - ApplyOutOfSyncOnly=true
  - ServerSideApply=true

retry

Field

Type

Default

Description

limit

int

5

Maximum retry attempts

backoff.duration

string

5s

Initial backoff duration

backoff.factor

int

2

Backoff multiplier

backoff.maxDuration

string

3m

Maximum backoff duration

Example:

spec:
  syncPolicy:
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Retry schedule: 5s, 10s, 20s, 40s, 80s (capped at 3m)

spec.ignoreDifferences

Ignore specific fields when detecting drift.

Structure:

spec:
  ignoreDifferences:
    - group: <apiGroup>
      kind: <Kind>
      name: <resourceName>  # Optional: specific resource
      namespace: <namespace>  # Optional: specific namespace
      jsonPointers:
        - /path/to/field
      jqPathExpressions:
        - .path.to.field

Common use cases:

HPA-managed replicas:

ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
      - /spec/replicas  # HPA modifies this

Cluster-managed secrets:

ignoreDifferences:
  - group: ""
    kind: Secret
    name: gitlab-postgres-app  # CNPG-managed
    jsonPointers:
      - /data  # Don't track data changes

Status fields:

ignoreDifferences:
  - group: postgresql.cnpg.io
    kind: Cluster
    jsonPointers:
      - /status  # Status constantly changes

Annotations added by operators:

ignoreDifferences:
  - group: apps
    kind: Deployment
    jqPathExpressions:
      - .metadata.annotations."deployment.kubernetes.io/revision"

Sync Waves

Control resource creation order using annotations.

Annotation Syntax

metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "<number>"

Wave order: -5, -4, …, -1, 0 (default), 1, 2, 3, …

Rules:

  • Resources applied in ascending wave order

  • Resources in same wave applied in parallel

  • ArgoCD waits for wave N to be healthy before starting wave N+1

GitLab BDA Sync Waves

Wave 1: Infrastructure

# Namespace (must exist first)
apiVersion: v1
kind: Namespace
metadata:
  name: gitlabbda
  annotations:
    argocd.argoproj.io/sync-wave: "1"

# RBAC (needed for service accounts)
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab
  annotations:
    argocd.argoproj.io/sync-wave: "1"

# Crossplane ProviderConfig (needed for buckets)
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: hetzner-s3
  annotations:
    argocd.argoproj.io/sync-wave: "1"

# S3 Buckets (Crossplane resources)
apiVersion: s3.aws.upbound.io/v1beta2
kind: Bucket
metadata:
  name: artifacts-gitlabbda-kup6s
  annotations:
    argocd.argoproj.io/sync-wave: "1"

Wave 2: Secrets

# ClusterSecretStore (ESO needs this)
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: gitlabbda-app-secrets-store
  annotations:
    argocd.argoproj.io/sync-wave: "2"

# ExternalSecrets (wait for store)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: gitlab-secrets
  annotations:
    argocd.argoproj.io/sync-wave: "2"
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: gitlabbda-app-secrets-store
    kind: ClusterSecretStore
  target:
    name: gitlab-secrets

Wave 3: Applications

# PostgreSQL (needs secrets)
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: gitlab-postgres
  annotations:
    argocd.argoproj.io/sync-wave: "3"

# Redis (needs namespace)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  annotations:
    argocd.argoproj.io/sync-wave: "3"

# GitLab (needs database, Redis, secrets)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitlab-webservice
  annotations:
    argocd.argoproj.io/sync-wave: "3"

Adding Sync Waves in CDK8S

// charts/constructs/database.ts
export class DatabaseConstruct extends Construct {
  constructor(scope: Construct, id: string, config: AppConfig) {
    super(scope, id);

    const cluster = new cnpg.Cluster(this, 'postgres', {
      metadata: {
        namespace: config.namespace,
        annotations: {
          'argocd.argoproj.io/sync-wave': '3',  // After secrets (wave 2)
        },
      },
      // ... cluster config ...
    });
  }
}

ArgoCD-Specific Annotations

Sync Annotations

Annotation

Values

Description

argocd.argoproj.io/sync-wave

number

Sync order (see above)

argocd.argoproj.io/sync-options

string

Resource-level sync options

Example:

metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "2"
    argocd.argoproj.io/sync-options: "Prune=false"  # Don't prune this resource

Hook Annotations

Annotation

Values

Description

argocd.argoproj.io/hook

PreSync, Sync, PostSync, Skip, SyncFail

When to execute

argocd.argoproj.io/hook-delete-policy

HookSucceeded, HookFailed, BeforeHookCreation

When to delete hook resource

Example: Database migration job

apiVersion: batch/v1
kind: Job
metadata:
  name: gitlab-migrations
  annotations:
    argocd.argoproj.io/hook: PreSync  # Run before main sync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded  # Delete after success
    argocd.argoproj.io/sync-wave: "3"
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: gitlab/gitlab-ce:18.5.1
        command: ["/bin/sh", "-c", "gitlab-rake db:migrate"]

Note: GitLab BDA doesn’t currently use hooks (migrations handled by GitLab Helm chart).

Repository Credentials

For private repositories, configure credentials in ArgoCD.

GitLab Deploy Token

1. Create deploy token in GitLab:

  • Settings → Repository → Deploy Tokens

  • Scopes: read_repository

  • Save token (shown once!)

2. Create ArgoCD repository secret:

kubectl create secret generic gitlab-repo-creds \
  -n argocd \
  --from-literal=type=git \
  --from-literal=url=https://git.bluedynamics.eu/kup6s/dp/dp-infra.git \
  --from-literal=username=gitlab+deploy-token-123 \
  --from-literal=password=<deploy-token>

kubectl label secret gitlab-repo-creds \
  -n argocd \
  argocd.argoproj.io/secret-type=repository

3. Verify:

# Check repository is connected
argocd repo list

# Should show:
# URL: https://git.bluedynamics.eu/kup6s/dp/dp-infra.git
# STATUS: Successful

SSH Key (Alternative)

1. Generate SSH key:

ssh-keygen -t ed25519 -C "argocd-gitlab-bda" -f ~/.ssh/argocd-gitlab

2. Add public key to GitLab:

  • Settings → Repository → Deploy Keys

  • Paste public key (~/.ssh/argocd-gitlab.pub)

3. Create ArgoCD secret:

kubectl create secret generic gitlab-repo-ssh \
  -n argocd \
  --from-literal=type=git \
  --from-literal=url=git@git.bluedynamics.eu:kup6s/dp/gitlab.git \
  --from-file=sshPrivateKey=$HOME/.ssh/argocd-gitlab

kubectl label secret gitlab-repo-ssh \
  -n argocd \
  argocd.argoproj.io/secret-type=repository

Health Assessment

ArgoCD assesses resource health using built-in rules.

Standard Health Checks

Healthy resources:

  • Deployment: All replicas ready

  • StatefulSet: All replicas ready

  • DaemonSet: All pods ready

  • Service: Always healthy (unless type=LoadBalancer pending)

  • Job: Completed successfully

  • PVC: Bound

Progressing:

  • Deployment: Waiting for replicas

  • Job: Running

Degraded:

  • Deployment: CrashLoopBackOff, ImagePullBackOff

  • Job: Failed

Custom Health Checks

Define custom health for CRDs:

# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.health.postgresql.cnpg.io_Cluster: |
    hs = {}
    if obj.status ~= nil then
      if obj.status.phase == "Cluster in healthy state" then
        hs.status = "Healthy"
        hs.message = "PostgreSQL cluster is healthy"
      elseif obj.status.phase == "Applying configuration" then
        hs.status = "Progressing"
        hs.message = "Applying configuration changes"
      else
        hs.status = "Degraded"
        hs.message = obj.status.phase or "Unknown status"
      end
    else
      hs.status = "Progressing"
      hs.message = "Waiting for status"
    end
    return hs

Note: Most CRDs (CNPG, Crossplane, ESO) have built-in health checks.

CLI Commands

Get Application Status

# List all applications
argocd app list

# Get specific application
argocd app get gitlab-bda

# Show application tree (resources)
argocd app get gitlab-bda --show-operation

Manual Sync

# Sync application
argocd app sync gitlab-bda

# Sync specific resource
argocd app sync gitlab-bda --resource apps:Deployment:gitlab-webservice

# Dry-run sync
argocd app sync gitlab-bda --dry-run

Check Diff

# Compare git vs cluster
argocd app diff gitlab-bda

# Shows:
# - Resources in git but not cluster
# - Resources in cluster but not git
# - Field differences

History and Rollback

# Show sync history
argocd app history gitlab-bda

# Rollback to previous revision
argocd app rollback gitlab-bda <revision>

# Example:
argocd app rollback gitlab-bda 42

Force Refresh

# Force git repository refresh (don't wait 3 minutes)
argocd app get gitlab-bda --refresh

# Hard refresh (clear cache)
argocd app get gitlab-bda --hard-refresh