Skip to content

Commit 3a93e51

Browse files
committed
ci: mirror ubuntu:22.04 to ghcr
1 parent 00ded39 commit 3a93e51

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

.github/workflows/ghcr.yml

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Mirror DockerHub images used by the Rust project to ghcr.io.
2+
#
3+
# In some CI jobs, we pull images from ghcr.io instead of Docker Hub because
4+
# Docker Hub has a rate limit, while ghcr.io doesn't.
5+
# Those images are pushed to ghcr.io by this job.
6+
#
7+
# Note that authenticating to DockerHub or other registries isn't possible
8+
# for PR jobs, because forks can't access secrets.
9+
# That's why we use ghcr.io: it doesn't require authentication to pull images.
10+
11+
name: GHCR
12+
13+
on:
14+
schedule:
15+
# Run daily at midnight UTC
16+
- cron: '0 0 * * *'
17+
18+
jobs:
19+
mirror:
20+
name: DockerHub mirror
21+
runs-on: ubuntu-24.04
22+
permissions:
23+
# Needed to write to the ghcr.io registry
24+
packages: write
25+
steps:
26+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
27+
with:
28+
persist-credentials: false
29+
30+
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
31+
with:
32+
registry: ghcr.io
33+
username: ${{ github.repository_owner }}
34+
password: ${{ github.token }}
35+
36+
- name: Mirror DockerHub
37+
run: python3 src/ci/github-actions/ghcr.py
38+
shell: bash

src/ci/github-actions/ghcr.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import os
2+
import requests
3+
import tarfile
4+
import shutil
5+
import subprocess
6+
from io import BytesIO
7+
from tempfile import TemporaryDirectory
8+
9+
10+
def crane_gh_release_url() -> str:
11+
version = "v0.20.2"
12+
os_name = "Linux"
13+
arch = "x86_64"
14+
base_url = "https://github.com/google/go-containerregistry/releases/download"
15+
return f"{base_url}/{version}/go-containerregistry_{os_name}_{arch}.tar.gz"
16+
17+
18+
def download_crane():
19+
"""Download the crane executable from the GitHub releases in the current directory."""
20+
21+
try:
22+
# Download the GitHub release tar.gz file
23+
response = requests.get(crane_gh_release_url(), stream=True)
24+
response.raise_for_status()
25+
26+
with TemporaryDirectory() as tmp_dir:
27+
# Extract the tar.gz file to temp dir
28+
with tarfile.open(fileobj=BytesIO(response.content), mode="r:gz") as tar:
29+
tar.extractall(path=tmp_dir)
30+
31+
# The tar.gz file contains multiple files.
32+
# Copy crane executable to current directory.
33+
# We don't need the other files.
34+
crane_path = os.path.join(tmp_dir, "crane")
35+
shutil.copy2(crane_path, "./crane")
36+
37+
print("Successfully downloaded and extracted crane")
38+
39+
except requests.RequestException as e:
40+
raise RuntimeError(f"Failed to download crane: {e}") from e
41+
except (tarfile.TarError, OSError) as e:
42+
raise RuntimeError(f"Failed to extract crane: {e}") from e
43+
44+
45+
def mirror_dockerhub():
46+
# Images from DockerHub that we want to mirror
47+
images = ["ubuntu:22.04"]
48+
for img in images:
49+
repo_owner = "rust-lang"
50+
# Command to mirror images from DockerHub to GHCR
51+
command = ["./crane", "copy", f"docker.io/{img}", f"ghcr.io/{repo_owner}/{img}"]
52+
try:
53+
subprocess.run(
54+
command,
55+
# if the process exits with a non-zero exit code,
56+
# raise the CalledProcessError exception
57+
check=True,
58+
# open stdout and stderr in text mode
59+
text=True,
60+
)
61+
print(f"Successfully mirrored {img}")
62+
except subprocess.CalledProcessError as e:
63+
raise RuntimeError(f"Failed to mirror {img}: {e}") from e
64+
print("Successfully mirrored all images")
65+
66+
67+
if __name__ == "__main__":
68+
download_crane()
69+
mirror_dockerhub()

0 commit comments

Comments
 (0)