diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index a941d8c..1ceea64 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -230,60 +230,52 @@ jobs: PROD_BACKEND_HOST: ${{ secrets.PROD_BACKEND_HOST }} steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Login to container registry with PAT - run: | - echo "${{ secrets.REGISTRY_TOKEN }}" | podman --remote login \ - -u "${{ secrets.REGISTRY_USERNAME }}" \ - --password-stdin \ - "${{ secrets.REGISTRY_HOST }}" + - name: Login to container registry with PAT + run: | + echo "${{ secrets.REGISTRY_TOKEN }}" | podman --remote login \ + -u "${{ secrets.REGISTRY_USERNAME }}" \ + --password-stdin \ + "${{ secrets.REGISTRY_HOST }}" - - name: Pull production images (optional but faster on play) - run: | - podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-backend-api-postgres:$IMAGE_TAG" - podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-frontend:$IMAGE_TAG" + - name: (Optional) Pre-pull images to speed up play + run: | + podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-backend-api-postgres:$IMAGE_TAG" + podman --remote pull "$REGISTRY_HOST/$APP_NAME/sharenet-frontend:$IMAGE_TAG" - # RENDER nginx.conf FROM REPO AND COPY TO HOST (no unshare) - - name: Render nginx.conf and write to host - run: | - set -euo pipefail - apk add --no-cache gettext >/dev/null # provides envsubst - # Render with your CI env (PROD_* vars) - envsubst < nginx/nginx.conf > /tmp/nginx.conf + # 1) Render nginx.conf from repo and copy to host (no unshare) + - name: Render nginx.conf and write to host + run: | + set -euo pipefail + apk add --no-cache gettext >/dev/null + envsubst < nginx/nginx.conf > /tmp/nginx.conf + podman --remote run --rm -i \ + --userns=keep-id \ + -v /opt/sharenet/nginx:/host-nginx:rw \ + alpine:3.20 sh -c 'install -D -m 0644 /dev/stdin /host-nginx/nginx.conf' \ + < /tmp/nginx.conf - # Copy to host via remote Podman bind-mount; keep prod-service uid/gid - podman --remote run --rm -i \ - --userns=keep-id \ - -v /opt/sharenet/nginx:/host-nginx:rw \ - alpine:3.20 sh -c 'install -D -m 0644 /dev/stdin /host-nginx/nginx.conf' \ - < /tmp/nginx.conf + # 2) Lint nginx.conf BEFORE restarting the pod (avoids crash loops) + - name: Validate nginx.conf with throwaway container + run: | + set -euo pipefail + podman --remote run --rm \ + -v /opt/sharenet/nginx:/etc/nginx:ro \ + docker.io/nginx:alpine \ + sh -lc 'nginx -t -c /etc/nginx/nginx.conf' - # TRY ZERO-DOWNTIME RELOAD FIRST - - name: Reload in-pod Nginx (or restart on failure) - continue-on-error: true - run: | - set -euo pipefail - podman --remote exec sharenet-production-pod-nginx nginx -t - podman --remote exec sharenet-production-pod-nginx nginx -s reload + # 3) Recreate the pod (down → play). This ensures new images/ports/env + the validated conf. + - name: Recreate pod + run: | + set -euo pipefail + podman --remote kube down sharenet-production-pod || true + envsubst < deploy/prod-pod.yml | podman --remote kube play - - - name: Fallback restart Nginx container if reload failed - if: failure() - run: | - set -euo pipefail - podman --remote restart sharenet-production-pod-nginx + # 4) Verify health on the prod host + - name: Verify in-pod Nginx + run: | + set -euo pipefail + curl -sS -D- http://127.0.0.1:18080/healthz - # (Re)APPLY THE POD (ensures new images/config picked up) - - name: Recreate pod (down & play) - run: | - set -euo pipefail - podman --remote kube down sharenet-production-pod || true - # Render your pod manifest (uses same $ENV as before) - envsubst < deploy/prod-pod.yml | podman --remote kube play - - - # VERIFY - - name: Verify in-pod nginx is healthy - run: | - set -euo pipefail - curl -sS -D- http://127.0.0.1:18080/healthz