Skip to main content

Flux integration

info

This page covers the Flux config structure, dependency control to avoid race conditions, and deployment commands.

Meeting scheduling series

  1. Meeting scheduling
  2. Architecture
  3. Manifests
  4. Flux integration - You are here
  5. Operations

Two-repo GitOps pattern

The Cal.com stack follows a two-repo pattern where Flux config and app manifests are separated:

Flux config structure

The Flux configuration lives in your flux-config repo under clusters/my-cluster/calcom/.

clusters/my-cluster/calcom/
├── kustomization.yaml # Kustomize wrapper
├── source.yaml # GitRepository for app repo
├── 00-kustomization-ns.yaml # Flux Kustomization for namespace
├── 10-kustomization-app.yaml # Flux Kustomization for app
└── ns/
├── kustomization.yaml
└── namespace.yaml # calcom namespace

Dependency control

The deployment order is critical. Cal.com uses Cloudflare Origin CA certificates, which require the Origin CA Issuer controller to be running.

warning

Without proper dependencies, the Certificate resource will fail to issue because the OriginIssuer CRD and controller are not ready.

Namespace manifest

# clusters/my-cluster/calcom/ns/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: calcom
labels:
name: calcom

Namespace Flux Kustomization

This applies the namespace and waits for the Origin CA Issuer controller:

# clusters/my-cluster/calcom/00-kustomization-ns.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: calcom-ns
namespace: flux-system
spec:
dependsOn:
- name: origin-ca-issuer-controller
interval: 10m
prune: true
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
path: ./clusters/my-cluster/calcom/ns
timeout: 2m

Key points:

SettingValuePurpose
dependsOnorigin-ca-issuer-controllerEnsures CRD and controller exist
sourceRefflux-systemUses the flux-config repo itself
path./clusters/my-cluster/calcom/nsApplies namespace folder

GitRepository source

# clusters/my-cluster/calcom/source.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: calcom-app
namespace: flux-system
spec:
interval: 5m
timeout: 60s
url: ssh://git-ssh.example.local/your-org/calcom.git
ref:
branch: main
secretRef:
name: flux-ssh-auth
ignore: |
/*
!/k8s/

The ignore pattern tells Flux to only watch the k8s/ directory, reducing unnecessary reconciliations.

App Flux Kustomization

This applies the app repo manifests after the namespace is ready:

# clusters/my-cluster/calcom/10-kustomization-app.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: calcom-app
namespace: flux-system
spec:
dependsOn:
- name: calcom-ns
interval: 10m
timeout: 10m
prune: true
wait: true
sourceRef:
kind: GitRepository
name: calcom-app
namespace: flux-system
path: ./k8s/prod
targetNamespace: calcom
decryption:
provider: sops
secretRef:
name: sops-age

Key points:

SettingValuePurpose
dependsOncalcom-nsWait for namespace
sourceRefcalcom-appThe app repo GitRepository
path./k8s/prodApply manifests from this path
targetNamespacecalcomDeploy all resources to calcom namespace
decryption.providersopsDecrypt SOPS-encrypted secrets
timeout10mAllow time for init containers and migrations

Kustomize wrapper

The folder's kustomization.yaml ties everything together:

# clusters/my-cluster/calcom/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- source.yaml
- 00-kustomization-ns.yaml
- 10-kustomization-app.yaml

Root aggregator

Add the calcom folder to the root aggregator:

# clusters/my-cluster/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cert-manager.yaml
- ./flux-system
- ./apps
- ./origin-ca-issuer
- ./cloudflare
- ./monitoring
- ./calcom # Add this line

Deployment commands

After committing both repos:

# 1. Commit and push the app repo
cd /path/to/your-org/calcom
git add .
git commit -m "Add Cal.com manifests"
git push

# 2. Commit and push flux-config
cd /path/to/flux-config
git add clusters/my-cluster/{kustomization.yaml,calcom}
git commit -m "Add Cal.com via Flux"
git push

# 3. Reconcile Flux
flux reconcile source git flux-system -n flux-system
flux reconcile kustomization flux-system -n flux-system --with-source

# 4. Watch deployment progress
flux get kustomizations -n flux-system | grep calcom
kubectl get pods -n calcom -w

Verification

# Check Flux Kustomizations
flux get kustomizations -n flux-system | grep calcom
# Expected:
# calcom-ns main@sha1:... False True Applied revision: ...
# calcom-app main@sha1:... False True Applied revision: ...

# Check pods
kubectl get pods -n calcom
# Expected:
# calcom-db-0 1/1 Running
# calcom-xxxxx 1/1 Running

# Check certificate
kubectl get certificate -n calcom
# Expected:
# calcom-tls True calcom-tls ...

# Check ingress
kubectl get ingress -n calcom
# Expected:
# calcom cal.example.com ...

Troubleshooting

Certificate stuck on "Issuing"

The OriginIssuer controller may not be ready or the API token is invalid.

# Check if OriginIssuer is ready
kubectl get originissuer -n calcom

# Check certificate events
kubectl describe certificate calcom-tls -n calcom

# Check origin-ca-issuer logs
kubectl logs -n cert-manager -l app=origin-ca-issuer

Namespace does not exist error

The app Kustomization tried to deploy before the namespace was ready.

# Check dependency status
flux get kustomizations -n flux-system | grep calcom

# calcom-ns should be Ready before calcom-app starts

SOPS decryption failed

The sops-age secret is missing or does not contain the correct key.

# Check if the secret exists
kubectl get secret sops-age -n flux-system

# The secret should contain the age private key

Pod stuck in Init

The database may not be ready or migrations are failing.

# Check init container logs
kubectl logs -n calcom -l app=calcom -c wait-for-postgres
kubectl logs -n calcom -l app=calcom -c migrate

# Check database pod
kubectl get pods -n calcom -l app=calcom-db
kubectl logs -n calcom calcom-db-0

Force full reconciliation

# Reconcile the source
flux reconcile source git calcom-app -n flux-system

# Reconcile the app Kustomization
flux reconcile kustomization calcom-app -n flux-system --with-source