Add the Ansible README and expand prod bootstrap coverage for StorageBox keys, DB labels, DB stack configuration, and act runner setup. Update MongoDB configuration for replica set support and refresh prod roadmap/setup documentation for Swarm labels, StorageBox-backed cert paths, and recovery guidance.
9.6 KiB
08 — Deploy Pipeline Update (Prod)
Context
- File:
.gitea/workflows/deploy-prod.yml - Same changes as test pipeline (
test-env-setup/07-deploy-pipeline-update.md), adapted for prod paths and prod runner. - Prod-specific differences from test:
SPRING_PROFILES_ACTIVE=prod(nottest) in Run APISIX Init- DB hostnames use Swarm VIP prefixes:
iklimco_postgresql,iklimco_mongodb - Storagebox paths use
prod/instead oftest/
Step 1 — Remove manual cert scp lines from Initialize Servers
# DELETE from "Initialize Servers" step:
scp -P 23 ${{ vars.STORAGEBOX_USER }}@${{ vars.STORAGEBOX_USER }}.your-storagebox.de:prod/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:prod/app/iklim.co/ssl/STAR.iklim.co_key.txt ./STAR.iklim.co_key.txt
Also remove from Prepare Init Files:
# DELETE or make conditional:
sudo cp STAR.iklim.co.full.crt STAR.iklim.co_key.txt /opt/iklimco/ssl/
Step 2 — Add Prepare SWAG Directories step
Insert before Bootstrap Vault TLS Placeholder:
- 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/proxy-confs /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"
export RESTRICTED_IPS_BLOCK="$(echo "$RESTRICTED_IPS" | tr ',' '\n' | sed 's|.*| allow &;|')"
SWAG_VARS='${API_SUBDOMAIN}${APIGW_SUBDOMAIN}${GRAFANA_SUBDOMAIN}${RABBITMQ_SUBDOMAIN}${RESTRICTED_IPS_BLOCK}'
for tpl in swag/proxy-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
.envis sourced first soAPI_SUBDOMAIN=api.iklim.co(prod values) are used. Ensure these vars are inprod/secrets/iklim.co/.env.prodon storagebox.
Step 3 — Add Wait for etcd step
Insert after Deploy Swarm Stack and before Run APISIX Init.
APISIX reads its entire configuration from etcd; init script will fail silently if etcd is not ready.
- name: Wait for etcd
run: |
echo "⏳ Waiting for etcd..."
for i in $(seq 1 30); do
if docker run --rm --network iklimco-net alpine \
sh -c "wget -qO- http://etcd:2379/health 2>/dev/null | grep -q '\"health\":\"true\"'"; then
echo "✅ etcd ready"
break
fi
[ "$i" -eq 30 ] && echo "❌ etcd did not become ready in time" && exit 1
echo " attempt $i/30 — waiting 5s..."
sleep 5
done
Step 4 — Add Run APISIX Init step
Insert after Wait for etcd and before Bootstrap SWAG Certificate.
- name: Run APISIX Init
run: |
set -a; . ./.env; . ./.env.secrets.shared; set +a
echo "⏳ Waiting for Swarm APISIX..."
until curl -sf -o /dev/null \
-H "X-API-KEY: ${APISIX_ADMIN_KEY}" \
"http://apisix:9180/apisix/admin/upstreams" 2>/dev/null; do
sleep 5
done
export SPRING_PROFILES_ACTIVE=prod
/bin/bash init/apisix-core/init.sh
echo "✅ APISIX routes configured"
working-directory: /workspace/iklim.co
Prod-specific:
SPRING_PROFILES_ACTIVE=prod— test pipeline usestest.APISIX_ADMIN_KEYis sourced from.env.secrets.shared. The init script is idempotent (PUT semantics); safe to re-run on subsequent deploys. Withreplicas: 2in prod, both APISIX instances read the same etcd state — no per-replica init needed.
Step 5 — Add Bootstrap SWAG Certificate step
Insert after Run APISIX Init:
- 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"
exit 1
fi
CERT_PATH="/config/etc/letsencrypt/live/iklim.co/fullchain.pem"
echo "Waiting for 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"
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. Logs:"
docker service logs iklimco_swag --tail 50
exit 1
fi
docker exec "$SWAG_CTR" cat "$CERT_PATH" | \
docker run --rm -i -v /opt/iklimco/ssl:/output alpine \
sh -c "cat > /output/STAR.iklim.co.full.crt && chmod 644 /output/STAR.iklim.co.full.crt"
docker exec "$SWAG_CTR" cat "/config/etc/letsencrypt/live/iklim.co/privkey.pem" | \
docker run --rm -i -v /opt/iklimco/ssl:/output alpine \
sh -c "cat > /output/STAR.iklim.co_key.txt && chmod 644 /output/STAR.iklim.co_key.txt"
echo "✅ Cert bootstrapped to /opt/iklimco/ssl/"
working-directory: /workspace/iklim.co
Step 6 — Add Run Database Init Scripts step
Insert after Bootstrap SWAG Certificate and before Review Environment.
- name: Run Database Init Scripts
run: |
set -a; . ./.env; . ./.env.secrets.shared; set +a
echo "⏳ Waiting for PostgreSQL..."
until docker run --rm --network iklimco-net \
-e PGPASSWORD="${DATABASE_POSTGRES_ROOT_PASSWD}" \
postgis/postgis:17-3.5 \
pg_isready -h iklimco_postgresql -U "${DATABASE_POSTGRES_ROOT_USER}" -q 2>/dev/null; do
sleep 5
done
for sql_file in $(ls ./init/postgresql/*.sql 2>/dev/null | sort); do
echo "▶ $(basename "$sql_file")"
docker run --rm -i --network iklimco-net \
-e PGPASSWORD="${DATABASE_POSTGRES_ROOT_PASSWD}" \
postgis/postgis:17-3.5 \
psql -h iklimco_postgresql -U "${DATABASE_POSTGRES_ROOT_USER}" < "$sql_file"
done
echo "⏳ Waiting for MongoDB..."
until docker run --rm --network iklimco-net mongo:8 \
mongosh "mongodb://${DATABASE_MONGODB_ROOT_USER}:${DATABASE_MONGODB_ROOT_PASSWD}@iklimco_mongodb/admin" \
--eval "db.runCommand({ping:1})" --quiet 2>/dev/null; do
sleep 5
done
for js_file in $(ls ./init/mongodb/*.js 2>/dev/null | sort); do
echo "▶ $(basename "$js_file")"
docker run --rm -i --network iklimco-net mongo:8 \
mongosh "mongodb://${DATABASE_MONGODB_ROOT_USER}:${DATABASE_MONGODB_ROOT_PASSWD}@iklimco_mongodb/admin" \
--quiet < "$js_file"
done
echo "✅ Database init scripts completed"
working-directory: /workspace/iklim.co
Prod-specific: DB hostnames are
iklimco_postgresqlveiklimco_mongodb(Swarm VIP service names). Test pipeline usespostgresql/mongodb(unqualified aliases within the same stack). SQL and JS files are generated byPrepare Init Filesstep viainit_postgresql/init_mongodbfunctions incommon-functions.sh. Step is idempotent — scripts useCREATE IF NOT EXISTS/createCollectionsemantics.
Step 7 — Ensure subdomain env vars are in prod .env
Add to prod/secrets/iklim.co/.env.prod on storagebox:
API_SUBDOMAIN=api.iklim.co
APIGW_SUBDOMAIN=apigw.iklim.co
RABBITMQ_SUBDOMAIN=rabbitmq.iklim.co
GRAFANA_SUBDOMAIN=grafana.iklim.co
Step 8 — Final step order for prod pipeline
- Checkout Branch
- Prepare Folders
- Set up SSH Key and Add to known_hosts
- Update Apt Repository and Install Required Tools
- Fetch Service Secret Files
- Initialize Servers ← cert scp lines removed
- Upload Updated Secrets to Storagebox
- Provision Vault AppRole IDs and Docker Secrets
- Upload Updated Env to Storagebox
- Prepare Init Files ← cert copy lines removed
- Initialize Docker Swarm
- Stop Docker Compose Services
- Docker Login to Harbor
- Prepare SWAG Directories ← NEW
- Bootstrap Vault TLS Placeholder
- Deploy Swarm Stack
- Wait for etcd ← NEW
- Run APISIX Init ← NEW (
SPRING_PROFILES_ACTIVE=prod) - Bootstrap SWAG Certificate ← NEW
- Run Database Init Scripts ← NEW (
iklimco_postgresql,iklimco_mongodb) - Review Environment