Skip to content

ci: pull the Temporal Conformance service images from mirror.gcr.io, off Docker Hub's anonymous pull quota - #22545

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-22541-ci-service-image-mirror
Oct 9, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-22541-ci-service-image-mirror

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #22541
Clause-②: no

What

The required Temporal Conformance (live PG + MySQL) job now pulls its two service images from mirror.gcr.io, Google's cache of Docker Hub, instead of from Docker Hub anonymously:

  • postgres:16 becomes mirror.gcr.io/library/postgres:16
  • mysql:8.0 becomes mirror.gcr.io/library/mysql:8.0

The diff is two image: values plus a six-line comment, all in .github/workflows/ci.yml. The job name, env, ports and both health checks (pg_isready -U postgres, mysqladmin ping -h 127.0.0.1) are unchanged. scripts/check-required-contexts.mjs pins the job name, and that name is untouched.

Why

Since 20:53Z on 2026-10-09, every run of this job failed at Initialize containers (three Docker pull failed with exit code 1, then failure), before checkout or any test body ran. Docker Hub answered toomanyrequests for the anonymous per-IP quota. The job is a required context, so the merge queue ejected every entry. The newest failures, read through the jobs API at 21:31Z, are the same: jobs 114034494503 (21:30:40Z), 114033905117, 114031741661, 114030793729, 114029405989 and 114028399482. Each has Initialize containers as its only failing step.

A Docker Hub login is not the fix. It needs a maintainer-held secret, and secrets never reach fork pull requests, so those runs would stay on the anonymous quota.

Measured: same image, same tag, same digest

Anonymous registry probe from this session at 2026-10-09T21:32:53Z, HEAD /v2/REPO/manifests/TAG with each registry's anonymous token flow, accepting the OCI index and Docker manifest-list types:

image Docker Hub mirror.gcr.io ECR Public (public.ecr.aws/docker/library)
postgres:16 sha256:ca0bd484cb98bf4b24eb1010e73fb3fcbd6714d240fbc1a10eea5b7dbecb641d 200, same digest 200, same digest
mysql:8.0 sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b 200, same digest 200, same digest
  • The registry probe to Docker Hub itself answered 429 for both repositories, even for HEAD, with ratelimit-limit: 100;w=3600, ratelimit-remaining: 0;w=3600 and a docker-ratelimit-source naming the egress IP. That is the anonymous per-IP quota this PR moves off. So the Docker Hub column was read from the Hub tag API (hub.docker.com/v2/repositories/library/IMAGE/tags/TAG, HTTP 200). It gives postgres:16 last pushed 2026-10-07T19:07:56Z and mysql:8.0 last pushed 2026-05-05T02:02:21Z.
  • Both mirrors returned an OCI image index (application/vnd.oci.image.index.v1+json), and neither response carried a rate-limit header.
  • Why mirror.gcr.io and not ECR Public: both serve both tags anonymously with identical digests. mirror.gcr.io is a cache of Docker Hub itself, so the bytes are Docker Hub's. ECR Public stays the measured fallback: if this mirror ever misbehaves, the swap is the same two lines to public.ecr.aws/docker/library/....

Proof

There is no Docker daemon in the authoring container, so this PR's own CI run is the measurement. The Temporal Conformance (live PG + MySQL) job on this PR must pass Initialize containers with the mirror named in its pull lines, then run its suites. The job id and conclusion go in the dispatch report on #22541.

Acceptance notes

  • Scaffold E2E (.github/workflows/scaffold-e2e.yml, on pull_request) builds docker/Dockerfile, which is FROM node:22-slim, and so also pulls from Docker Hub anonymously. It is not one of the seven required contexts, so it does not block the queue, and this PR does not change it. No other required job pulls a container image.
  • No changeset: a CI-only path publishes nothing.

Generated by Claude Code

The required `Temporal Conformance (live PG + MySQL)` job started its
postgres:16 and mysql:8.0 service containers from Docker Hub with no
credentials. Docker Hub's anonymous per-IP pull quota is exhausted on
shared runner IPs, so `Initialize containers` failed before any step ran
and the merge queue ejected every entry.

Both images now come from mirror.gcr.io (Google's cache of Docker Hub):
the same official image and tag, with the index digest measured equal on
Docker Hub, mirror.gcr.io and ECR Public for both tags. Job name, env,
ports and health checks are unchanged.

Claude-Session: https://claude.ai/code/session_01VZqqwTj2wsihZEbfT6yyYN
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 9, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 9, 2026 22:04
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 9, 2026 22:04
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit ce78ff7 Oct 9, 2026
39 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22541-ci-service-image-mirror branch October 9, 2026 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants