ci(docker-deploy): pin APP_IP via docker inspect, not shared DNS
CI / Architecture Guardrails (push) Successful in 4m15s
CI / Assistant Split Regression (push) Successful in 6m29s
CI / Typecheck (push) Successful in 7m50s
CI / Lint (push) Successful in 7m46s
CI / Unit Tests (push) Failing after 10m56s
CI / E2E Tests (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / Release Images (push) Has been cancelled
CI / Build (push) Has been cancelled

The 'app' hostname on gitea_gitea collides with foreign containers from
other stacks that also answer /api/health. Previous logic picked the first
IP whose health check returned 200 — sometimes a neighbor whose process
died mid-test, producing ERR_CONNECTION_REFUSED on smoke test #2.

Use 'docker compose ps -q app' + docker inspect to read our own
container's gitea_gitea IP. Zero DNS ambiguity.
This commit is contained in:
2026-04-13 05:07:09 +02:00
parent a984635ef3
commit d90a86c7d7
+24 -17
View File
@@ -485,32 +485,39 @@ jobs:
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml --profile full up -d --build app
- name: Resolve and pin app IP
# 'app' hostname collides on shared gitea_gitea network — same split
# -brain as e2epg. Smoke test #2 hit ERR_CONNECTION_REFUSED even
# after both warm-ups returned the expected codes, because curl and
# Playwright-launched Chromium picked different IPs from the DNS set.
# Probe each resolved IP for /api/health and pin the winner as
# APP_BASE_URL so every subsequent step (wait, warm-up, smoke run)
# hits the same container.
# 'app' hostname collides on shared gitea_gitea network: many unrelated
# containers (from other stacks or concurrent jobs) also answer to
# "app" and to /api/health. Previously we probed every IP that
# `getent hosts app` returned and pinned the first 200 responder —
# which could easily be a foreign container whose process then died
# mid-test, producing ERR_CONNECTION_REFUSED.
#
# Use docker compose ps to uniquely identify OUR app container, then
# docker inspect to read its IP on the gitea_gitea network (the one
# the act_runner job can reach). No DNS, no guessing.
run: |
set -e
for i in $(seq 1 36); do
IPS=$(getent hosts app | awk '{print $1}')
if [ -n "$IPS" ]; then
for ip in $IPS; do
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "http://$ip:3100/api/health" || echo "000")
echo "Attempt $i: $ip -> HTTP $CODE"
CID=$(docker compose -f docker-compose.yml -f docker-compose.ci.yml ps -q app || true)
if [ -n "$CID" ]; then
APP_IP=$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{if eq $k "gitea_gitea"}}{{$v.IPAddress}}{{end}}{{end}}' "$CID")
if [ -n "$APP_IP" ]; then
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "http://$APP_IP:3100/api/health" || echo "000")
echo "Attempt $i: container $CID on $APP_IP -> HTTP $CODE"
if [ "$CODE" = "200" ]; then
echo "APP_IP=$ip" >> "$GITHUB_ENV"
echo "APP_BASE_URL=http://$ip:3100" >> "$GITHUB_ENV"
echo "APP_IP=$APP_IP" >> "$GITHUB_ENV"
echo "APP_BASE_URL=http://$APP_IP:3100" >> "$GITHUB_ENV"
exit 0
fi
done
else
echo "Attempt $i: container $CID has no gitea_gitea IP yet"
fi
else
echo "Attempt $i: 'app' not yet in DNS"
echo "Attempt $i: compose has no 'app' container yet"
fi
sleep 5
done
echo "No reachable app:3100 found"
echo "Our stack's app container never reported healthy on gitea_gitea"
docker compose -f docker-compose.yml -f docker-compose.ci.yml logs app --tail=50
exit 1