GitHub Actions Fails Quickly with Connection Reset: The Cross-Border Pitfall When Overseas Runners Pull Alibaba Cloud ACR
1. Problem Description
A routine push triggered a Docker image build, and GitHub Actions failed directly about 2 seconds after starting:
ERROR: failed to authorize: failed to fetch oauth token:
Post "https://dockerauth.cn-hangzhou.aliyuncs.com/auth": read: connection reset by peer
The log error points to this line in the Dockerfile:
FROM registry.cn-hangzhou.aliyuncs.com/<namespace>/node:22-pm2
The first instinct might go astray: is the base image tag wrong? Has the ACR password expired? Is there a problem with the recently changed Dockerfile?
None of these. The only criterion: with the same Dockerfile and credentials, a previous build succeeded, then one failed, with no related changes in between. The code hasn't changed but the result has, so the problem isn't in the code.
2. Environment
| Item | Details |
|---|---|
| CI | GitHub Actions, GitHub-hosted runner (overseas data center) |
| Build | docker/build-push-action, multi-platform (amd64 + arm64) |
| Image Repository | Alibaba Cloud ACR (Hangzhou region) |
| Base Image | Custom node:22-pm2, also stored in the same ACR |
3. Root Cause
Breaking down the link:
- GitHub-hosted runner is overseas.
FROMa private ACR image, buildx needs to fetch an OAuth token fromdockerauth.cn-hangzhou.aliyuncs.comduring the "load metadata" phase.- This overseas → Alibaba Cloud Hangzhou cross-border TCP link has unstable quality, occasionally being directly RST by intermediate devices—manifesting as
connection reset by peer.
So this is an intermittent network-layer failure, not an authentication configuration issue (authentication errors return 401/403 HTTP responses, not TCP connection resets), and certainly not a Dockerfile issue (the error points to the FROM line only because the failure occurs during the metadata parsing stage of that line).
A Diagnostic Mantra Worth Remembering
First, check at which second the failure occurs. Second-level failure = network / authentication link; minute-level failure might be compilation / dependency issue.
Failing in 2 seconds, dependencies haven't even started installing; spending time checking npm packages or code is counterproductive.
4. Fix: Add Automatic Retry in Workflow
The intermittent RST of cross-border links cannot be eliminated from our side, but its characteristic is that retries are likely to succeed. Modify the build step:
- name: Build and push
id: build
continue-on-error: true # 第一次失败不终止 job
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.IMAGE_TAGS }}
- name: Wait before retry
if: steps.build.outcome == 'failure'
run: sleep 30 # 给链路一点恢复时间
- name: Build and push (retry)
if: steps.build.outcome == 'failure'
uses: docker/build-push-action@v6
with: # ⚠️ 参数必须与上面逐字一致
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.IMAGE_TAGS }}
Two practical notes:
-
GitHub Actions YAML does not support anchors (
&anchor/*ref), so thewithblocks of the two steps cannot be reused; they must be manually kept in verbatim sync—when changing parameters later, both places need to be changed, and it's best to leave comments in the file as reminders. -
continue-on-error: truewill make the step status show a green checkmark when the first step fails (the outer job does not fail), so rely onsteps.build.outcometo determine the actual result; don't be fooled by the interface color.
After deploying this retry mechanism, similar intermittent resets are caught by the second build, and there have been no more occurrences of the entire pipeline turning red.
5. Structural Solution (Optional)
Retry is just a stopgap. To make the cross-border dependency of "overseas runners pulling domestic images" disappear entirely, the idea is to mirror the base image to an overseas registry that is stably accessible:
- Sync and push a copy of the custom base image to GHCR (
ghcr.io) - Change the
FROMin Dockerfile to GHCR—pulling side no longer crosses borders - Build artifacts are pushed to ACR as before (push-side cross-border writes are tested to be more stable than authentication pulls, and failures are caught by the retries above)
The cost is maintaining an extra image sync. If the intermittent frequency is not high, the retry solution is sufficient; implement this when the failure frequency affects the release rhythm.
6. Troubleshooting Checklist (Go Through in Order for Similar Errors)
- At which second does the failure occur? Second-level → network/authentication direction; minute-level → compilation/dependency direction
- Is the error at the TCP layer (connection reset / timeout) or HTTP layer (401/403/404)? The former checks the link, the latter checks credentials
- Has the same configuration succeeded before? If it succeeded before and there are no related changes → intermittent environmental issue, retry first
- The code line pointed to by the error (e.g., FROM) is just the position being processed at the time of failure, not necessarily an issue with that line