Deploy to GKE #296
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to GKE | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| environment: | |
| description: Environment to deploy to | |
| required: true | |
| default: development | |
| type: choice | |
| options: | |
| - development | |
| - production | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| environment: ${{ github.event.inputs.environment }} | |
| permissions: | |
| id-token: write | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Read version | |
| id: version | |
| run: | | |
| VERSION=$(tr -d '[:space:]' < .version) | |
| [ -n "$VERSION" ] || { echo "Missing .version"; exit 1; } | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| - uses: google-github-actions/auth@v3 | |
| with: | |
| workload_identity_provider: ${{ vars.WORKLOAD_ID_PROVIDER }} | |
| service_account: ${{ vars.SERVICE_ACCOUNT }} | |
| - uses: google-github-actions/get-gke-credentials@v2 | |
| with: | |
| cluster_name: ${{ vars.GKE_CLUSTER }} | |
| location: ${{ vars.GKE_LOCATION }} | |
| - name: Verify images exist | |
| run: | | |
| REGISTRY="${{ vars.REGISTRY }}/${{ vars.PROJECT_ID }}/${{ vars.REPOSITORY }}" | |
| VERSION="${{ steps.version.outputs.version }}" | |
| for IMAGE in whisp-app whisp-api whisp-db-migrate; do | |
| IMAGE_REF="${REGISTRY}/${IMAGE}:${VERSION}" | |
| echo "Checking ${IMAGE_REF}" | |
| gcloud artifacts docker images describe "${IMAGE_REF}" >/dev/null || { | |
| echo "Image not found: ${IMAGE_REF}" | |
| exit 1 | |
| } | |
| done | |
| - name: Deploy | |
| env: | |
| GKE_NAMESPACE: ${{ vars.GKE_NAMESPACE }} | |
| ENVIRONMENT: ${{ github.event.inputs.environment }} | |
| VERSION: ${{ steps.version.outputs.version }} | |
| IMAGE_REGISTRY: ${{ vars.REGISTRY }}/${{ vars.PROJECT_ID }}/${{ vars.REPOSITORY }} | |
| CLOUDSQL_INSTANCE: ${{ vars.CLOUDSQL_INSTANCE }} | |
| GCS_BUCKET: ${{ vars.GCS_BUCKET }} | |
| ENV_SECRET: ${{ vars.ENV_SECRET }} | |
| GEE_SECRET: ${{ vars.GEE_SECRET }} | |
| GCP_SERVICE_ACCOUNT: ${{ vars.GCP_SERVICE_ACCOUNT }} | |
| GKE_LB_STATIC_IP_NAME: ${{ vars.GKE_LB_STATIC_IP_NAME }} | |
| HOST_URL: ${{ vars.HOST_URL }} | |
| run: | | |
| set -euo pipefail | |
| VERSION_SLUG=$(echo "$VERSION" | tr '[:upper:]' '[:lower:]' | tr '.+' '-') | |
| export VERSION_SLUG | |
| INGRESS_HOST="${HOST_URL#https://}" | |
| INGRESS_HOST="${INGRESS_HOST#http://}" | |
| INGRESS_HOST="${INGRESS_HOST%%/*}" | |
| export INGRESS_HOST | |
| export DEPLOYED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ) | |
| VARS='$GKE_NAMESPACE $ENVIRONMENT $VERSION $VERSION_SLUG $IMAGE_REGISTRY $CLOUDSQL_INSTANCE $GCS_BUCKET $ENV_SECRET $GEE_SECRET $GCP_SERVICE_ACCOUNT $GKE_LB_STATIC_IP_NAME $HOST_URL $INGRESS_HOST $DEPLOYED_AT' | |
| OUT=/tmp/k8s | |
| mkdir -p "$OUT" | |
| for f in infra/k8s/[0-9]*.yaml; do | |
| envsubst "$VARS" < "$f" > "$OUT/$(basename "$f")" | |
| done | |
| shopt -s nullglob | |
| for tier in 00 01 02 03 04 05 06 07 08 09; do | |
| if [ "$tier" = "02" ]; then | |
| for f in "$OUT/${tier}."*.yaml; do | |
| grep -q '^apiVersion:' "$f" || continue | |
| kubectl delete -f "$f" --ignore-not-found | |
| done | |
| fi | |
| for f in "$OUT/${tier}."*.yaml; do | |
| grep -q '^apiVersion:' "$f" || continue | |
| kubectl apply -f "$f" | |
| done | |
| case $tier in | |
| 01|03) kubectl wait --for=condition=available deployment --all -n "$GKE_NAMESPACE" --timeout=300s ;; | |
| 02) | |
| kubectl wait --for=condition=complete job --all -n "$GKE_NAMESPACE" --timeout=300s & | |
| wp=$! | |
| while kill -0 $wp 2>/dev/null; do | |
| kubectl get job -n "$GKE_NAMESPACE" -o jsonpath='{range .items[*]}{.status.conditions[?(@.type=="Failed")].status}{"\n"}{end}' | grep -qx True && { | |
| kill $wp 2>/dev/null || true | |
| wait $wp 2>/dev/null || true | |
| kubectl get job -n "$GKE_NAMESPACE" | |
| exit 1 | |
| } | |
| sleep 2 | |
| done | |
| wait $wp | |
| ;; | |
| esac | |
| done |