Skip to content

Commit 04295f6

Browse files
committed
ci: mirror ubuntu:22.04 to ghcr
1 parent 00ded39 commit 04295f6

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

.github/workflows/ghcr.yml

Lines changed: 38 additions & 0 deletions
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 has no rate limit and doesn't require authentication.
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@v4
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

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

0 commit comments

Comments
 (0)