From d1e428c0385e4a02f0ca4ee2902a5b3d05779915 Mon Sep 17 00:00:00 2001 From: Andrew Park Date: Wed, 11 Nov 2026 19:59:49 +0000 Subject: [PATCH] ci: pull the base images from mirror.gcr.io at once --- .github/scripts/mirror_base_images.py | 7 ++++--- tst/unit/test_mirror_base_images_script.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/scripts/mirror_base_images.py b/.github/scripts/mirror_base_images.py index a2cac9a6e..849fb15d9 100644 --- a/.github/scripts/mirror_base_images.py +++ b/.github/scripts/mirror_base_images.py @@ -9,7 +9,7 @@ are also named in containerd, whose images Docker reads only on the containerd image store. Switching dockerd to it restarts dockerd, which stops the containers it runs, so this runs before any start. -``mirror_base_images.py PATH...`` does this for the Dockerfiles at or under each PATH. +``mirror_base_images.py PATH...`` does this for the Dockerfiles at or under each PATH, pulling their bases at once. """ from __future__ import annotations @@ -19,6 +19,7 @@ import subprocess import sys import time +from concurrent.futures import ThreadPoolExecutor from pathlib import Path ECR = "public.ecr.aws/docker/library/" @@ -33,8 +34,8 @@ def main(argv: list[str]) -> int: bases = _bases([Path(arg) for arg in argv]) if any("@" in base for base in bases): _use_containerd_store() - for base in bases: - _pull(base) + with ThreadPoolExecutor(max_workers=max(len(bases), 1)) as pool: + list(pool.map(_pull, bases)) return 0 diff --git a/tst/unit/test_mirror_base_images_script.py b/tst/unit/test_mirror_base_images_script.py index 3c12689c2..e3cd467d2 100644 --- a/tst/unit/test_mirror_base_images_script.py +++ b/tst/unit/test_mirror_base_images_script.py @@ -7,6 +7,7 @@ import json import subprocess import sys +import threading import pytest @@ -139,3 +140,22 @@ def test_a_pull_that_fails_once_is_tried_again(script, monkeypatch, tmp_path): assert ran[-1] == ["docker", "tag", "mirror.gcr.io/library/postgres:16-alpine", _TAGGED] assert ["sleep", 10] in ran and ["sleep", 20] not in ran + + +def test_the_bases_are_pulled_at_once(script, monkeypatch, tmp_path): + ran = _docker(monkeypatch, script) + fake = script.subprocess.run + both_pulling = threading.Barrier(2, timeout=10) + + def run(argv, **kwargs): + if argv[:2] == ["docker", "pull"]: + both_pulling.wait() + return fake(argv, **kwargs) + + monkeypatch.setattr(script.subprocess, "run", run) + dockerfile = tmp_path / "Dockerfile" + dockerfile.write_text(f"FROM {_TAGGED}\nFROM public.ecr.aws/docker/library/busybox:1.37\n") + + assert script.main([str(dockerfile)]) == 0 + + assert sorted(argv[1] for argv in ran) == ["pull", "pull", "tag", "tag"]