Environment_Infrastructure/roadmap/test-env/07-deploy-pipeline-update.md
Murat ÖZDEMİR fd6a0b4f46 docs: fix roadmap inconsistencies between test-env and prod-env
Corrects six documentation files to match the actual deployed pipeline
behavior and align test/prod approaches where they share the same code.

prod-env/02-godaddy-credentials.md
- Step 1: correct secret file from .env.secrets.shared to .env.secrets.swag;
  add clarifying note that .env.secrets.shared holds AppRole/DB secrets
  and must not be used for GoDaddy credentials.
- Step 4: document that GoDaddy A records are now managed automatically
  by the pipeline's 'Update DNS Records' step via the GoDaddy API;
  reference the Gitea variable PROD_FLOATING_IP that must be set once.

prod-env/08-deploy-pipeline-update.md
- Add Step 2 documenting the new 'Update DNS Records' pipeline step
  (GoDaddy API, idempotent check-before-update, requires jq and
  vars.PROD_FLOATING_IP).
- Renumber subsequent steps 3-8 to accommodate the new step.
- Fix DB hostnames in Step 7 (Run Database Init Scripts) from
  iklimco_postgresql/iklimco_mongodb to postgresql/mongodb, matching
  how Swarm overlay DNS resolves service names inside iklimco-net.
- Update context block: correct DB hostname description, replace
  outdated storagebox path note with env-var approach, list new steps.
- Update final step order to 24 steps including the DNS step and
  Release Deploy Lock; mark Wait for etcd as NEW.

prod-env/09-verify.md
- Insert check #2 for the precipitation image directory
  (/mnt/storagebox/precipitation/images) and iklimco_image-data volume
  bind mount, mirroring the equivalent check in test-env/08-verify.md.
- Renumber all subsequent checks (3-12) to maintain sequential ordering.

test-env/03-infra-stack-changes.md
- Update SWAG service volume snippet: replace hardcoded paths
  (swag-vl:/config, /opt/iklimco/swag/dns-conf, /opt/iklimco/swag/site-confs)
  with env-var forms (${SWAG_CONFIG_DIR:-swag-vl}, ${SWAG_DNS_CONF_DIR:-...},
  ${SWAG_SITE_CONFS_DIR:-...}) to match docker-stack-infra.yml.
- Update cert-reloader volume snippet: replace swag-vl and /opt/iklimco/ssl
  with ${SWAG_CONFIG_DIR:-swag-vl} and ${SWAG_CERT_DIR:-/opt/iklimco/ssl},
  enabling StorageBox override in prod without changing the base file.

test-env/04-swag-nginx-configs.md
- Replace RESTRICTED_IP_1/RESTRICTED_IP_2 individual env vars with
  RESTRICTED_IPS (comma-separated CIDR list) in the required-vars section,
  matching env-test/.env and the actual pipeline.
- Update all three IP-restricted template examples (apigw, rabbitmq,
  grafana) from allow ${RESTRICTED_IP_1}; allow ${RESTRICTED_IP_2}; to
  ${RESTRICTED_IPS_BLOCK}, matching the actual .conf.tpl files in the repo.
- Rewrite the deploy step section to match the real pipeline: docker run
  alpine for file writing, RESTRICTED_IPS_BLOCK generation via sed, and
  envsubst with explicit SWAG_VARS filter to protect nginx $upstream_* vars.

test-env/07-deploy-pipeline-update.md
- Step 2 (Prepare SWAG Directories): replace sudo-tee approach with the
  actual docker-run-alpine method used in deploy-test.yml; add nginx
  reload block; update notes to reflect RESTRICTED_IPS_BLOCK generation.
- Step 4 (Re-order): correct step numbering to match actual pipeline
  (21 steps); mark 'Wait for etcd' as already present in pipeline rather
  than a new addition; add Bootstrap Vault TLS Placeholder which was
  missing from the documented order.
2026-05-16 16:52:48 +03:00

7.3 KiB
Raw Blame History

07 — Deploy Pipeline Update (Test)

Context

  • File: .gitea/workflows/deploy-test.yml
  • Changes:
    1. Remove manual scp STAR.iklim.co.full.crt steps (SWAG now owns cert lifecycle).
    2. Add SWAG host directories preparation (dns-conf, nginx site-confs).
    3. Add cert bootstrap step: on first deploy, wait for SWAG to obtain cert, then copy to /opt/iklimco/ssl/ so Vault can start.
    4. Ensure GODADDY_KEY and GODADDY_SECRET are available from .env.secrets.swag.

Step 1 — Update Initialize Servers step

Remove the two scp lines that copy the TLS cert files:

# DELETE these two lines from the "Initialize Servers" step:
          scp -P 23 ${{ vars.STORAGEBOX_USER }}@${{ vars.STORAGEBOX_USER }}.your-storagebox.de:test/app/iklim.co/ssl/STAR.iklim.co.full.crt ./STAR.iklim.co.full.crt
          scp -P 23 ${{ vars.STORAGEBOX_USER }}@${{ vars.STORAGEBOX_USER }}.your-storagebox.de:test/app/iklim.co/ssl/STAR.iklim.co_key.pem ./STAR.iklim.co_key.pem

Also remove any references to STAR.iklim.co.full.crt and STAR.iklim.co_key.pem in the Prepare Init Files step's sudo cp commands:

# DELETE or make conditional:
          sudo cp STAR.iklim.co.full.crt STAR.iklim.co_key.pem /opt/iklimco/ssl/ 2>/dev/null || true

Step 2 — Add Prepare SWAG Directories step

Insert this step before Deploy Swarm Stack:

      - name: Prepare SWAG Directories
        run: |
          set -a; . ./.env; . ./.env.secrets.swag; set +a

          docker run --rm -v /opt/iklimco/swag:/output alpine \
            mkdir -p /output/dns-conf /output/site-confs

          envsubst < swag/dns-conf/godaddy.ini.tpl | docker run --rm -i \
            -v /opt/iklimco/swag/dns-conf:/output \
            alpine sh -c "cat > /output/godaddy.ini && chmod 600 /output/godaddy.ini"
          echo "✅ godaddy.ini written"

          # RESTRICTED_IPS → multi-line allow block (indented 8 spaces per nginx style)
          export RESTRICTED_IPS_BLOCK="$(echo "$RESTRICTED_IPS" | tr ',' '\n' | sed 's|.*|        allow &;|')"

          # Explicit var list prevents nginx $upstream_* from being substituted by envsubst
          SWAG_VARS='${API_SUBDOMAIN}${APIGW_SUBDOMAIN}${GRAFANA_SUBDOMAIN}${RABBITMQ_SUBDOMAIN}${RESTRICTED_IPS_BLOCK}'
          for tpl in swag/site-confs/*.conf.tpl; do
            fname=$(basename "${tpl%.tpl}")
            envsubst "$SWAG_VARS" < "$tpl" | docker run --rm -i \
              -v /opt/iklimco/swag/site-confs:/output \
              alpine sh -c "cat > /output/${fname}"
            echo "✅ ${fname}"
          done

          cat swag/site-confs/default.conf | docker run --rm -i \
            -v /opt/iklimco/swag/site-confs:/output \
            alpine sh -c "cat > /output/default.conf"

          echo "✅ SWAG directories ready"

          SWAG_CTR=$(docker ps -q -f name=iklimco_swag 2>/dev/null | head -1)
          if [ -n "$SWAG_CTR" ]; then
            docker exec "$SWAG_CTR" nginx -t && docker exec "$SWAG_CTR" nginx -s reload
            echo "✅ SWAG nginx reloaded"
          fi
        working-directory: /workspace/iklim.co

GODADDY_KEY ve GODADDY_SECRET .env.secrets.swag içinde olmalı (bkz. step 02). API_SUBDOMAIN, APIGW_SUBDOMAIN vb. .env içinde olmalı (bkz. step 04). Dosyalar docker run alpine ile yazılır — host'a sudo erişimi gerekmez. RESTRICTED_IPS comma-separated CIDR listesinden (env-test/.env) her satıra allow direktifi üretilir.

Step 3 — Add Bootstrap SWAG Certificate step

Insert this step after Deploy Swarm Stack and before any step that depends on Vault being accessible (e.g., Provision Vault AppRole IDs):

      - name: Bootstrap SWAG Certificate
        run: |
          echo "Waiting for SWAG container to start..."
          SWAG_CTR=""
          for i in $(seq 1 24); do
            SWAG_CTR=$(docker ps -q -f name=iklimco_swag 2>/dev/null | head -1)
            [ -n "$SWAG_CTR" ] && break
            sleep 10
          done

          if [ -z "$SWAG_CTR" ]; then
            echo "❌ SWAG container did not start in time"
            exit 1
          fi

          CERT_PATH="/config/etc/letsencrypt/live/iklim.co/fullchain.pem"
          echo "Waiting for SWAG to obtain Let's Encrypt cert (up to 10 min)..."
          for i in $(seq 1 20); do
            if docker exec "$SWAG_CTR" test -f "$CERT_PATH" 2>/dev/null; then
              echo "✅ Cert obtained by SWAG"
              break
            fi
            echo "  attempt $i/20 — waiting 30s..."
            sleep 30
          done

          if ! docker exec "$SWAG_CTR" test -f "$CERT_PATH" 2>/dev/null; then
            echo "❌ SWAG did not obtain cert in time. Check logs:"
            docker service logs iklimco_swag --tail 50
            exit 1
          fi

          # Copy cert to host for Vault bootstrap
          sudo mkdir -p /opt/iklimco/ssl
          docker exec "$SWAG_CTR" cat "$CERT_PATH" | \
            sudo tee /opt/iklimco/ssl/STAR.iklim.co.full.crt > /dev/null
          docker exec "$SWAG_CTR" cat "/config/etc/letsencrypt/live/iklim.co/privkey.pem" | \
            sudo tee /opt/iklimco/ssl/STAR.iklim.co_key.pem > /dev/null
          echo "✅ Cert bootstrapped to /opt/iklimco/ssl/"
        working-directory: /workspace/iklim.co

First deploy only: SWAG contacts Let's Encrypt via GoDaddy DNS challenge. This step waits up to 10 minutes. On subsequent deploys the cert is already in swag-vl (persisted volume) and SWAG starts immediately — wait loop exits fast.

Step 4 — Re-order steps

Final step order in the pipeline:

  1. Checkout Branch
  2. Prepare Folders
  3. Set up SSH Key
  4. Update Apt / Install Tools
  5. Fetch Service Secret Files
  6. Initialize Docker Swarm
  7. Initialize Servers
  8. Upload Updated Secrets to Storagebox
  9. Provision Vault AppRole IDs and Docker Secrets
  10. Upload Updated Env to Storagebox
  11. Prepare Init Files ← sudo cp STAR.iklim.co.*.crt lines removed
  12. Stop Docker Compose Services
  13. Docker Login to Harbor
  14. Prepare SWAG Directories ← NEW
  15. Bootstrap Vault TLS Placeholder
  16. Deploy Swarm Stack
  17. Wait for etcd ← zaten pipeline'da mevcut; etcd health endpoint'i kontrol eder
  18. Run APISIX Init ← NEW (SPRING_PROFILES_ACTIVE=test)
  19. Bootstrap SWAG Certificate ← NEW
  20. Run Database Init Scripts ← NEW
  21. Review Environment

Steps 8 (Provision Vault) runs before SWAG because it creates Docker secrets and AppRole IDs — Vault must be reachable for this. On re-deploys, Vault is already running with the previous cert. On first deploy, step 16 handles the cert wait before any further Vault interaction is needed post-deploy.

If Vault provisioning (step 8) fails on first deploy because Vault has no cert yet, move step 16 before step 8. Adjust based on observed behavior.

Notes

  • .env must contain the subdomain env vars added in step 04. Add them to storagebox test/secrets/iklim.co/.env before the first deploy.
  • RESTRICTED_IP_1 and RESTRICTED_IP_2 are hardcoded in the pipeline step above. Move to .env if they change often.
  • Precipitation service expects its image-data bind mount at /mnt/storagebox/precipitation/images. This directory is provisioned by the test Ansible bootstrap through storagebox_managed_directories; do not rely on the deploy pipeline to create it.