with one click
sync-image
// Use when syncing upstream database images into apecloud Docker Hub, auditing manifests, tags, architectures, and pullability before addon image use.
// Use when syncing upstream database images into apecloud Docker Hub, auditing manifests, tags, architectures, and pullability before addon image use.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | sync-image |
| description | Use when syncing upstream database images into apecloud Docker Hub, auditing manifests, tags, architectures, and pullability before addon image use. |
Reference resolution: when this source-derived skill mentions docs/..., resolve it from the shared support package beside the installed user skills: ~/.codex/skills/kubeblocks-addon-source-docs/docs/... for Codex or ~/.claude/skills/kubeblocks-addon-source-docs/docs/... for Claude Code. In the shared kubeblocks-addon-docs checkout, the same files live under skills/kubeblocks-addon-source-docs/docs/.... When it mentions scripts/..., resolve it from the same support package under scripts/.... If you are working inside a checkout of the original apecloud/kubeblocks-addon-skills, repo-relative paths are also valid.
Pull a Docker image from an upstream registry and push it to the apecloud Docker Hub organization.
Usage: /sync-image <source-image> [--arch amd64|arm64] [--os linux|windows]
Examples:
/sync-image docker.elastic.co/elasticsearch/elasticsearch:9.0.0/sync-image docker.elastic.co/elasticsearch/elasticsearch:9.0.0 --arch amd64/sync-image redis:7.2.1 --arch amd64 --os linuxArguments: $ARGUMENTS
# Source .env from repo root (silently skip if absent)
SCRIPT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
[ -f "$SCRIPT_DIR/.env" ] && source "$SCRIPT_DIR/.env"
# Validate required variables
: "${DOCKER_USERNAME:?'.env is missing DOCKER_USERNAME — copy .env.example to .env and fill it in'}"
: "${DOCKER_PASSWORD:?'.env is missing DOCKER_PASSWORD — copy .env.example to .env and fill it in'}"
echo "Docker credentials loaded for: $DOCKER_USERNAME"
Parse the source image and optional --arch / --os flags from arguments.
Defaults: --arch unset (pull native), --os linux.
Source image format: [registry/]repo/name:tag
docker.elastic.co/elasticsearch/elasticsearch:9.0.0 → registry=docker.elastic.co, name=elasticsearch, tag=9.0.0redis:7.2.1 → registry=docker.io (default), name=library/redis, tag=7.2.1bitnami/redis:7.2.1 → registry=docker.io, name=bitnami/redis, tag=7.2.1Target image will be: docker.io/apecloud/<name>:<tag>
(where <name> is just the image name without registry or organization prefix)
SOURCE=<source-image>
TARGET=docker.io/apecloud/<name>:<tag>
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:apecloud/<name>:pull" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"https://registry.hub.docker.com/v2/apecloud/<name>/manifests/<tag>")
if [ "$STATUS" == "200" ]; then
echo "Image $TARGET already exists in Docker Hub. Skipping sync."
exit 0
fi
echo "Target image not found (HTTP $STATUS). Proceeding with sync..."
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
If login fails, report the error and stop.
ARCH=<arch-or-empty> # from --arch flag, or empty
OS=<os-or-linux> # from --os flag, default "linux"
if [ -n "$ARCH" ]; then
docker pull --platform ${OS}/${ARCH} $SOURCE
else
docker pull $SOURCE
fi
This may take several minutes for large images. Report progress.
If pull fails, run the Docker Hub search fallback below before giving up.
Search Docker Hub for the image name and pick the best source:
IMAGE_NAME=<name> # just the name part, no tag
IMAGE_TAG=<tag>
# Search Docker Hub
curl -s "https://hub.docker.com/v2/search/repositories/?query=${IMAGE_NAME}&page_size=25" \
| python3 -c "
import sys, json
data = json.load(sys.stdin)
results = data.get('results', [])
for r in results:
print(r['is_official'], r['pull_count'], r['repo_name'], r.get('short_description',''))
"
Selection priority (highest to lowest):
is_official=True (shown as library/<name> on Docker Hub, pulled as <name>:<tag>). These are maintained by the Docker Official Images program.qdrant/qdrant, elastic/elasticsearch, redis/redis, mongo/mongodb-community-server). These are the upstream project's own published images.After identifying the best candidate, confirm the new source with the user before proceeding:
Found candidate: docker.io/<org>/<name>:<tag>
Proceed with this source? [y/N]
If confirmed, set SOURCE=docker.io/<org>/<name>:<tag> and retry the pull (Step 4).
docker tag $SOURCE docker.io/apecloud/<name>:<tag>
docker push docker.io/apecloud/<name>:<tag>
# Verify the push succeeded
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:apecloud/<name>:pull" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -I \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"https://registry.hub.docker.com/v2/apecloud/<name>/manifests/<tag>")
if [ "$STATUS" == "200" ]; then
echo "✓ Successfully synced:"
echo " Source: $SOURCE"
echo " Target: docker.io/apecloud/<name>:<tag>"
else
echo "✗ Verification failed (HTTP $STATUS). The push may have failed silently."
fi
Remove local copies to free disk space:
docker rmi $SOURCE docker.io/apecloud/<name>:<tag> 2>/dev/null || true
If ALIYUN_IMAGE_REGISTRY, ALIYUN_DOCKER_USERNAME, and ALIYUN_DOCKER_PASSWORD are all set
in .env, automatically mirror the image to the Aliyun registry as well.
if [ -n "$ALIYUN_IMAGE_REGISTRY" ] && [ -n "$ALIYUN_DOCKER_USERNAME" ] && [ -n "$ALIYUN_DOCKER_PASSWORD" ]; then
ALIYUN_TARGET="$ALIYUN_IMAGE_REGISTRY/apecloud/<name>:<tag>"
echo "ALIYUN_IMAGE_REGISTRY is configured — also syncing to $ALIYUN_TARGET ..."
if command -v skopeo &>/dev/null; then
skopeo copy \
--src-no-creds \
--dest-username "$ALIYUN_DOCKER_USERNAME" \
--dest-password "$ALIYUN_DOCKER_PASSWORD" \
"docker://docker.io/apecloud/<name>:<tag>" \
"docker://$ALIYUN_TARGET" \
&& echo "Aliyun sync OK: $ALIYUN_TARGET" \
|| echo "Warning: Aliyun sync failed. Docker Hub push was still successful."
else
echo "$ALIYUN_DOCKER_PASSWORD" | \
docker login "$ALIYUN_IMAGE_REGISTRY" \
-u "$ALIYUN_DOCKER_USERNAME" --password-stdin
docker tag "docker.io/apecloud/<name>:<tag>" "$ALIYUN_TARGET"
docker push "$ALIYUN_TARGET" \
&& echo "Aliyun sync OK: $ALIYUN_TARGET" \
|| echo "Warning: Aliyun sync failed. Docker Hub push was still successful."
docker rmi "$ALIYUN_TARGET" 2>/dev/null || true
fi
else
echo "ALIYUN_IMAGE_REGISTRY not set in .env — skipping Aliyun mirror."
fi