From 687e4d9f2d5816b3262d0ec0a2ed5638a591074d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Arag=C3=B3n?= Date: Fri, 10 Jul 2026 12:17:40 +0000 Subject: [PATCH] fix(ci): use container name 'portainer' instead of IP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All services (Gitea, the 3 runners and Portainer itself) are in the same Docker network 'portainer_default', so the service name 'portainer' resolves directly from inside any container in that network. The previous auto-discovery dance with IPs and routes is no longer needed. - Set the PORTAINER_URL secret to 'http://portainer:9000'. - Replace the entire 'Step 0' auto-discovery with a simple check that the configured URL is reachable. - Drop the debug Step 0a that was added during troubleshooting. The runner's job container can now reach Portainer the same way the runner itself does — by name. --- .gitea/workflows/ci-cd.yaml | 62 +++++-------------------------------- 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/.gitea/workflows/ci-cd.yaml b/.gitea/workflows/ci-cd.yaml index 649a7ec..a8c830a 100644 --- a/.gitea/workflows/ci-cd.yaml +++ b/.gitea/workflows/ci-cd.yaml @@ -65,64 +65,18 @@ jobs: - name: Redeploy stack on Portainer if: github.event_name == 'workflow_dispatch' && inputs.deploy == true env: + PORTAINER_URL: ${{ secrets.PORTAINER_URL }} PORTAINER_TOKEN: ${{ secrets.PORTAINER_TOKEN }} PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }} PORTAINER_STACK_ID: ${{ secrets.PORTAINER_STACK_ID }} run: | - # NOTE: no `set -e` here on purpose — the auto-discovery loop below - # needs to try every candidate even if some probes fail, and some - # diagnostic commands (ip route, hostname -I) might return empty - # in unusual container network setups without aborting the job. - echo "hostname: $(hostname)" - echo "hostname -I:" - hostname -I 2>/dev/null || echo "(none)" - echo "ip -4 addr show (eth* only):" - ip -4 addr show 2>/dev/null | grep -E "^[0-9]+:|inet " | head -20 - echo "ip route:" - ip route 2>/dev/null - echo "ip route show default:" - ip -4 route show default 2>/dev/null - echo "curl to 192.168.1.30:9000 (5s timeout):" - curl -sS -o /dev/null -w ' HTTP=%{http_code} time=%{time_total}s\n' --max-time 5 "http://192.168.1.30:9000/api/status" 2>&1 || echo " (curl failed)" - echo "---" - - echo "--- Step 0: auto-discover a reachable Portainer URL ---" - # The runner creates an ephemeral docker network per job, so the - # canonical PORTAINER_URL (e.g. http://192.168.1.30:9000) often isn't - # reachable from inside the job container. Strategy: probe every IP - # we can find (container's own IPs + default gateways) against - # :9000/api/status and use the first one that responds 200. - PORTAINER_URL="" - CANDIDATES=() - - # 1) Container's own IPv4 addresses - for ip in $(hostname -I 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+\.'); do - CANDIDATES+=("http://${ip}:9000") - done - - # 2) Default gateways of every default route - while IFS= read -r gw; do - [ -n "$gw" ] && CANDIDATES+=("http://${gw}:9000") - done < <(ip -4 route show default 2>/dev/null | awk '{print $3}' | sort -u) - - # 3) Fallback: secret value (in case everything else fails) - CANDIDATES+=("${{ secrets.PORTAINER_URL }}") - - echo "Candidates: ${CANDIDATES[@]}" - for url in "${CANDIDATES[@]}"; do - code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 "${url}/api/status" 2>/dev/null || echo "000") - echo " probe ${url}/api/status -> ${code}" - if [ "$code" = "200" ]; then - PORTAINER_URL="$url" - echo " -> using ${PORTAINER_URL}" - break - fi - done - - if [ -z "$PORTAINER_URL" ]; then - echo "ERROR: no candidate URL reached Portainer. Tried: ${CANDIDATES[@]}" >&2 - echo "ERROR: container hostname=$(hostname) IP=$(hostname -I)" >&2 - echo "ERROR: ip route=$(ip route 2>&1 | tr '\n' ';')" >&2 + # Portainer, Gitea and the runners all share the `portainer_default` + # Docker network on the NAS, so the service name "portainer" resolves + # directly from the job container. No need for IP auto-discovery. + echo "Using PORTAINER_URL=$PORTAINER_URL" + if ! curl -sS -o /dev/null -w '%{http_code}' --max-time 5 \ + "${PORTAINER_URL}/api/status" | grep -q '^200$'; then + echo "ERROR: Portainer not reachable at $PORTAINER_URL" >&2 exit 1 fi