Flux integration
This page covers the Flux config structure, dependency control to avoid race conditions, and deployment commands.
Meeting scheduling series
- Meeting scheduling
- Architecture
- Manifests
- Flux integration - You are here
- 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.
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:
| Setting | Value | Purpose |
|---|---|---|
dependsOn | origin-ca-issuer-controller | Ensures CRD and controller exist |
sourceRef | flux-system | Uses the flux-config repo itself |
path | ./clusters/my-cluster/calcom/ns | Applies 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:
| Setting | Value | Purpose |
|---|---|---|
dependsOn | calcom-ns | Wait for namespace |
sourceRef | calcom-app | The app repo GitRepository |
path | ./k8s/prod | Apply manifests from this path |
targetNamespace | calcom | Deploy all resources to calcom namespace |
decryption.provider | sops | Decrypt SOPS-encrypted secrets |
timeout | 10m | Allow 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