From 7339ac7eecb713232a406f207df62543566db1aa Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sat, 3 Jan 2026 15:50:01 -0600 Subject: [PATCH] Add automatic database migrations on deployment - Create Kubernetes Job to run migrations before deployment - Update GitLab CI to execute migration job and wait for completion - Ensures migrations run once per deployment in clustered environment - Migration job uses PostgreSQL advisory locks to prevent race conditions --- .gitlab-ci.yml | 12 ++++++++++++ k8s/migrate-job.yaml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 k8s/migrate-job.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b4b26234..b2708a94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,6 +37,18 @@ deploy: script: - kubectl config get-contexts - kubectl config use-context graham/towerops:towerops + # Run database migrations before deploying new version + - | + # Create unique job name using commit SHA (truncated to fit k8s naming limits) + JOB_NAME="towerops-migrate-${CI_COMMIT_SHORT_SHA}" + # Generate job manifest with correct image tag and unique name + sed -e "s|IMAGE_TAG|${CI_COMMIT_SHA}|g" \ + -e "s|towerops-migrate-TIMESTAMP|${JOB_NAME}|g" \ + k8s/migrate-job.yaml | kubectl apply -f - + # Wait for migration to complete (max 5 minutes) + kubectl wait --for=condition=complete --timeout=5m job/${JOB_NAME} -n towerops + echo "Database migration completed successfully" + # Deploy new version - kubectl set image deployment/towerops towerops=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n towerops - kubectl rollout status deployment/towerops -n towerops --timeout=5m environment: diff --git a/k8s/migrate-job.yaml b/k8s/migrate-job.yaml new file mode 100644 index 00000000..f79da0b7 --- /dev/null +++ b/k8s/migrate-job.yaml @@ -0,0 +1,44 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: towerops-migrate-TIMESTAMP + namespace: towerops + labels: + app: towerops + component: migration +spec: + # Clean up completed jobs after 1 hour + ttlSecondsAfterFinished: 3600 + backoffLimit: 3 + template: + metadata: + labels: + app: towerops + component: migration + spec: + restartPolicy: Never + imagePullSecrets: + - name: gitlab-registry + containers: + - name: migrate + image: registry.gitlab.com/graham/towerops:IMAGE_TAG + command: ["/app/bin/towerops", "eval", "Towerops.Release.migrate()"] + env: + - name: MIX_ENV + value: "prod" + - name: RELEASE_COOKIE + valueFrom: + secretKeyRef: + name: towerops-secrets + key: RELEASE_COOKIE + envFrom: + - secretRef: + name: towerops-db + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "256Mi" + cpu: "500m"