基于 GitHub Actions + Issue 的容器镜像自动同步工具。通过提交 Issue 指定要同步的镜像,Action 自动将镜像的所有架构同步到已配置的目标仓库,并在 Issue 中反馈同步结果。
- 📝 Issue 驱动 — 提交 Issue 即可触发同步,操作简单直观
- 🏗️ 多架构同步 — 自动同步镜像支持的所有架构(amd64、arm64、arm 等),使用
skopeo copy --all - 🔒 安全认证 — 用户名/密码通过 GitHub Secrets 存储,日志自动屏蔽为
*** - 📊 自动反馈 — 同步完成后在 Issue 中评论结果,包含源镜像、目标镜像和已同步架构
- 🌐 多云支持 — 支持 Docker Hub、GHCR、Quay、腾讯云、华为云、阿里云及私有仓库
- ⚡ 失败检测 — 未配置仓库、登录失败、源镜像不存在时均自动反馈具体原因
- 🎯 配置简单 — 只需配置仓库地址、命名空间和登录密码,无需选择仓库类型
统一使用扁平命名空间,只取镜像名的最后一段:
{仓库地址}/{命名空间}/{镜像名最后一段}:{Tag}
| 原始镜像 | 同步后镜像 |
|---|---|
docker.io/apache/seatunnel:2.3.13 |
ccr.ccs.tencentyun.com/ruichuangdev/seatunnel:2.3.13 |
docker.io/library/mysql:8.4.10 |
ccr.ccs.tencentyun.com/ruichuangdev/mysql:8.4.10 |
docker.io/nginxinc/nginx:latest |
ccr.ccs.tencentyun.com/ruichuangdev/nginx:latest |
quay.io/prometheus/node-exporter:v1.8.0 |
ccr.ccs.tencentyun.com/ruichuangdev/node-exporter:v1.8.0 |
所有目标仓库均使用扁平命名空间(只取镜像名最后一段),无论 Docker Hub、腾讯云、华为云还是阿里云。
理论上支持所有标准容器镜像仓库,以下平台已实际验证可用:
| 平台 | REGISTRY_URL | 特点 |
|---|---|---|
| Docker Hub | docker.io |
上传速度快;下载需配置加速 |
| Quay | quay.io |
上传速度快;中国地区可直接访问 |
| 腾讯云 TCR | 随区域变化(见下方) | 非中国地区上传快;可公开下载 |
| 华为云 SWR | 随区域变化(见下方) | 中国地区速度优于腾讯云海外;个人版无法公开拉取 |
| 阿里云 ACR | 随区域变化(见下方) | 上传速度较慢;可公开下载 |
| 私有仓库 | 自定义 | 需自行确保网络可达 |
⚠️ 腾讯云、华为云、阿里云的镜像仓库地址随所选区域变化,没有统一的标准地址。 下文各平台章节中给出的地址仅为示例,并非真实可用地址。请登录各云平台控制台,从实际的访问凭证或登录指令中获取你所在区域的真实仓库地址。
首次使用需要完成以下 5 步配置,请按顺序执行:
将此仓库 Fork 到你的 GitHub 账户下,或作为模板创建新仓库。
⚠️ 这一步不能跳过! 如果没有预先创建标签,Issue 模板无法自动添加标签,Action 不会被触发。
方法一:通过 Labels 页面创建
- 进入你的仓库,点击 Issues 标签页
- 点击右侧 Labels → New label
- 填写:
- 名称:
image-sync - 颜色:建议
#0075ca(蓝色)
- 名称:
- 点击 Create label
方法二:直接访问 URL
访问 https://github.com/<你的用户名>/<仓库名>/labels,点击 New label,填写名称 image-sync,保存。
根据你要使用的目标仓库,从对应云平台控制台获取以下 4 项信息:
| 配置项 | 说明 | 获取方式 |
|---|---|---|
| REGISTRY_URL | docker login 时使用的仓库地址 |
云平台控制台的访问凭证 / 登录指令 |
| REGISTRY_NAMESPACE | 命名空间或组织名 | 云平台控制台创建 |
| REGISTRY_USERNAME | 登录用户名 | 云平台控制台的访问凭证 |
| REGISTRY_PASSWORD | 登录密码或 Token | 云平台控制台生成 |
⚠️ 密码 ≠ AK/SK:各云平台的REGISTRY_PASSWORD是docker login密码,不是 API 的 Access Key / Secret Key。AK/SK 无法用于 docker login。
- 浏览器访问 hub.docker.com,登录账号
- 点击右上角头像 → Account settings → Personal access tokens → Generate new token
- 权限选择:Read & Write
- 有效期:建议选择永不过期
- 生成后复制 Token,此即为
REGISTRY_PASSWORD
- 访问 hub.docker.com/repositories,确认你的用户名(即为
REGISTRY_NAMESPACE) - 访问 hub.docker.com/repository-settings,设置默认隐私为 Public(否则同步后的镜像无法公开拉取)
| 配置项 | 值 |
|---|---|
| REGISTRY_URL | docker.io |
| REGISTRY_NAMESPACE | 你的 Docker Hub 用户名 |
| REGISTRY_USERNAME | 你的 Docker Hub 用户名 |
| REGISTRY_PASSWORD | Personal Access Token |
- 浏览器访问 quay.io,登录账号
- 选择旧版 UI,点击右上角头像 → Account Settings → CLI Password
- 生成密码后复制,此即为
REGISTRY_PASSWORD
| 配置项 | 值 |
|---|---|
| REGISTRY_URL | quay.io |
| REGISTRY_NAMESPACE | 你的 Quay 用户名 |
| REGISTRY_USERNAME | 你的 Quay 用户名 |
| REGISTRY_PASSWORD | CLI Password |
⚠️ 镜像上传后默认为私有,需在镜像仓库的 Settings 中将 Repository Visibility 设为 Public 才可公开拉取。
- 浏览器访问 腾讯云 TCR 控制台
- 选择区域,创建实例和命名空间
- 进入 实例管理 → 访问凭证,获取:
- 镜像仓库地址(
REGISTRY_URL,随区域变化,下方仅为示例) - 登录用户名(
REGISTRY_USERNAME) - 设置固定密码(
REGISTRY_PASSWORD,⚠️ 不是临时登录密码,不是 API SecretKey)
- 镜像仓库地址(
| 配置项 | 值 |
|---|---|
| REGISTRY_URL | 从控制台获取(示例:ccr.ccs.tencentyun.com) |
| REGISTRY_NAMESPACE | 你创建的命名空间 |
| REGISTRY_USERNAME | 从控制台获取 |
| REGISTRY_PASSWORD | 固定密码( |
⚠️ 仓库地址随区域变化,上方示例地址并非真实可用,请从控制台获取你所在区域的实际地址。⚠️ 镜像上传后默认为私有,需在仓库信息中设置为公开才可公开拉取。 💡 建议选择非中国地区实例(如香港、新加坡),上传速度更快。
- 浏览器访问 华为云 SWR 控制台
- 创建组织(即为
REGISTRY_NAMESPACE) - 进入 总览 → 登录指令,获取:
- 镜像仓库地址(
REGISTRY_URL,随区域变化,下方仅为示例) - 登录用户名(
REGISTRY_USERNAME) - 长期登录密码(
REGISTRY_PASSWORD,⚠️ 不是 AK/SK)
- 镜像仓库地址(
| 配置项 | 值 |
|---|---|
| REGISTRY_URL | 从登录指令获取(示例:swr.cn-north-4.myhuaweicloud.com) |
| REGISTRY_NAMESPACE | 你创建的组织名 |
| REGISTRY_USERNAME | 从登录指令获取 |
| REGISTRY_PASSWORD | 长期登录密码( |
⚠️ 仓库地址随区域变化,上方示例地址并非真实可用,请从登录指令获取你所在区域的实际地址。⚠️ 个人版 SWR 无法配置镜像公开拉取,只能登录华为云账户拉取,或共享给指定华为账户。
- 浏览器访问 阿里云 ACR 控制台
- 创建个人版实例(无论选哪个区域,默认全球可用)
- 创建命名空间(即为
REGISTRY_NAMESPACE),配置默认类型为公开 - 进入 访问凭证,设置固定密码(即为
REGISTRY_PASSWORD) - 获取镜像仓库地址(
REGISTRY_URL,随区域变化,下方仅为示例)
| 配置项 | 值 |
|---|---|
| REGISTRY_URL | 从控制台获取(示例:registry.cn-hangzhou.aliyuncs.com) |
| REGISTRY_NAMESPACE | 你创建的命名空间 |
| REGISTRY_USERNAME | 从访问凭证获取 |
| REGISTRY_PASSWORD | 固定密码( |
⚠️ 仓库地址随区域变化,上方示例地址并非真实可用,请从访问凭证获取你所在区域的实际地址。 💡 个人版 ACR 上传速度较慢,企业版自带加速功能无需使用本工具。
| 配置项 | 值 |
|---|---|
| REGISTRY_URL | 你的私有仓库地址(如 registry.company.com) |
| REGISTRY_NAMESPACE | 项目名 |
| REGISTRY_USERNAME | 仓库用户名 |
| REGISTRY_PASSWORD | 仓库密码 |
请确保私有仓库的网络可达性,GitHub Actions Runner 需能访问该仓库地址。
进入你 Fork 的仓库 → Settings → Secrets and variables → Actions,配置以下 4 项:
| 变量名 | 说明 | 示例 |
|---|---|---|
REGISTRY_URL |
目标仓库地址(docker login 时使用的地址) |
ccr.ccs.tencentyun.com |
REGISTRY_NAMESPACE |
目标命名空间 | ruichuangdev |
| Secret 名 | 说明 | 示例 |
|---|---|---|
REGISTRY_USERNAME |
目标仓库用户名 | your-username |
REGISTRY_PASSWORD |
目标仓库密码或 Token | your-token |
⚠️ REGISTRY_USERNAME和REGISTRY_PASSWORD必须配置为 Secret,切勿配置为 Variable,否则密码会在日志中暴露。
建议先用一个小镜像测试配置是否正确:
-
本地验证登录(可选但推荐):
docker login <你的REGISTRY_URL> -u <用户名> # 输入密码后应显示 "Login Succeeded"
-
提交测试 Issue:
- 在仓库中点击 New Issue
- 选择 🔄 容器镜像同步请求 模板
- 填写小镜像地址:
docker.io/library/alpine:latest - 提交 Issue
-
检查结果:
- 进入 Actions 标签页,确认工作流已触发
- 等待运行完成后,回到 Issue 查看自动评论
- ✅ 显示同步成功 → 配置完成
- ❌ 显示失败 → 参考下方 常见问题排查
配置完成后,随时通过提交 Issue 同步镜像:
- 在仓库中点击 New Issue
- 选择 🔄 容器镜像同步请求 模板
- 填写完整的镜像地址(必须包含仓库地址)
- 提交 Issue,Action 自动运行
docker.io/apache/seatunnel:2.3.13
docker.io/library/mysql:8.4.10
docker.io/nginxinc/nginx:latest
quay.io/prometheus/node-exporter:v1.8.0
ghcr.io/owner/repo:tag
⚠️ 必须填写完整的镜像地址(包含仓库地址),不能只写apache/seatunnel:2.3.13。
Action 运行完成后会自动在 Issue 中评论结果:
成功示例:
项目 值 原始镜像 docker.io/apache/seatunnel:2.3.13同步后镜像 ccr.ccs.tencentyun.com/ruichuangdev/seatunnel:2.3.13✅ amd64 (x86_64) ✅ arm64 (aarch64)
用户提交 Issue(完整镜像地址 + image-sync 标签)
│
▼
GitHub Actions 触发(labeled 事件)
┌─ Issue 模板自动附加标签 → 触发
└─ 手动添加 image-sync 标签 → 触发
│
▼
解析 Issue 内容 → 提取仓库地址、镜像名、Tag
│
▼
检查仓库配置 ──── 未配置 ──→ 评论反馈 + 关闭 Issue
│
▼ 已配置
安装 skopeo 工具
│
▼
登录目标仓库 ──── 失败 ──→ 评论反馈登录错误详情
│
▼ 成功
检查源镜像 ──── 不存在 ──→ 评论反馈源镜像错误详情
│
▼ 存在
同步所有架构(skopeo copy --all)
│
▼
验证同步结果
│
▼
评论反馈结果 + 关闭 Issue
触发机制:Action 仅监听
labeled事件,不监听opened。Issue 模板自动附加image-sync标签时会触发labeled事件;手动添加该标签也会触发。这样避免了opened+labeled同时触发导致重复运行。
最常见原因:image-sync 标签未预先创建
Issue 模板要求标签必须在仓库中已经存在才能自动添加。如果标签不存在,模板创建的 Issue 没有标签,Action 不会触发。
解决方法:
- 进入仓库 Issues → Labels 页面
- 确认
image-sync标签存在(不存在则手动创建) - 回到之前的 Issue,手动添加
image-sync标签触发同步
其他可能原因:
- Secrets 或 Variables 未配置 → Action 的
if条件不满足 - Workflow 文件语法错误 → 进入 Actions 页面查看错误提示
| 错误信息 | 原因 | 解决方法 |
|---|---|---|
unauthorized: authentication required |
密码错误或类型不对 | 确认密码是 docker login 密码,不是 AK/SK |
| 腾讯云登录失败 | 使用了临时密码 | TCR 控制台 → 访问凭证 → 设置固定密码 |
| 华为云登录失败 | 使用了 AK/SK | SWR 控制台 → 获取长期登录指令,提取密码 |
| 阿里云登录失败 | 使用了主账号 AK/SK | ACR 控制台 → 访问凭证 → 设置固定密码 |
| Docker Hub 登录失败 | 使用了账号密码 | Account Settings → Security → New Access Token |
验证方法: 在本地终端执行:
docker login <你的REGISTRY_URL> -u <用户名>确认能成功登录后再配置到 GitHub Secrets。
Issue 评论显示 ❌ 源镜像不存在或无法访问:
- 确认镜像名称和 Tag 拼写正确
- 确认镜像地址格式完整(必须包含仓库地址)
- 在本地验证:
docker pull <完整镜像地址> - 如果源镜像为私有镜像,当前不支持同步
大镜像跨国同步可能超过 30 分钟:
- 这是正常现象,不是卡死
- 在 Actions 日志中可以看到实时进度输出
- 如果频繁超时,考虑同步更小的镜像或使用更近的源仓库
这是正常现象,不是同步失败。
现代镜像(使用 Docker Buildx 构建的)会在 manifest list 中附带 attestation manifests(构建证明书),其 platform 被标记为 unknown/unknown。脚本会自动过滤这些元数据,只在日志和 Issue 评论中显示真实架构。
无需处理,多架构同步是完整的。
不会。GitHub Actions 会自动将所有与已注册 Secrets 完全匹配的字符串在日志中替换为 ***。脚本从不主动打印密码值。
image-sync/
├── .github/
│ ├── workflows/
│ │ └── sync-image.yml # 主工作流(仅 labeled 事件触发)
│ ├── ISSUE_TEMPLATE/
│ │ └── sync-image.yml # Issue 提交模板
│ └── registry-config-example # 仓库配置参考
├── scripts/
│ └── sync-image.sh # 镜像同步脚本
└── README.md # 说明文档
- 标签必须预创建 — 首次使用前必须在仓库中创建
image-sync标签,否则 Issue 模板无法自动添加标签,Action 不触发 - 密码必须用 Secret —
REGISTRY_USERNAME和REGISTRY_PASSWORD必须配置为 Secret,切勿配置为 Variable - 仓库地址随区域变化 — 腾讯云、华为云、阿里云的仓库地址随所选区域变化,请从各自云平台控制台获取实际地址,文档中的地址仅为示例
- 密码 ≠ AK/SK — 各云平台的
REGISTRY_PASSWORD是docker login密码,不是 API 的 Access Key / Secret Key - 镜像地址必须完整 — Issue 中必须填写包含仓库地址的完整镜像地址,不能只写镜像路径
- 私有源镜像不支持 — 当前仅支持同步公有源镜像,私有源镜像需要额外配置源仓库认证
- 架构自动同步 —
skopeo copy --all会同步源镜像支持的所有架构,不限于 amd64 和 arm64 unknown/unknown已过滤 — 日志中不再出现 Docker Buildx attestation manifests 的unknown/unknown架构
本项目使用 WorkBuddy 搭配 GLM-5.1 和 Kimi-K2.7 模型,全流程 AI 开发完成——从项目架构设计、代码编写、问题调试到文档撰写,均由 AI 主导执行。
MIT License