You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Artifactory与ACR间Docker镜像自动同步?求GitLab CI脚本

实现Artifactory与ACR的Docker镜像自动同步(GitLab CI可用)

核心逻辑

  1. 定期查询Artifactory目标镜像的所有标签
  2. 对比上次同步记录,筛选出新增的image:tag
  3. 根据同步方向执行拉取/推送操作
  4. 更新同步记录,避免重复处理

Bash 脚本方案

#!/bin/bash
set -euo pipefail

# 配置参数(推荐在GitLab CI变量中定义)
ARTIFACTORY_REGISTRY="your-artifactory-registry-url"
ARTIFACTORY_REPO="your-docker-repo-name"
ARTIFACTORY_USER="$ARTIFACTORY_USER"
ARTIFACTORY_PASS="$ARTIFACTORY_PASS"
ACR_REGISTRY="your-acr-name.azurecr.io"
ACR_USER="$ACR_USER"
ACR_PASS="$ACR_PASS"
IMAGE_NAME="your-image-name"
# 同步方向:push_to_acr 或 pull_to_artifactory
SYNC_DIRECTION="push_to_acr"
# 存储上次同步标签的文件
LAST_SYNC_TAGS="./last_sync_tags.txt"

# 初始化同步记录文件
if [ ! -f "$LAST_SYNC_TAGS" ]; then
    touch "$LAST_SYNC_TAGS"
fi

# 获取Artifactory当前所有标签
get_artifactory_tags() {
    curl -s -u "$ARTIFACTORY_USER:$ARTIFACTORY_PASS" \
        "$ARTIFACTORY_REGISTRY/v2/$ARTIFACTORY_REPO/$IMAGE_NAME/tags/list" | \
        jq -r '.tags[]'
}

# 获取新增标签
current_tags=$(get_artifactory_tags)
new_tags=$(comm -13 <(sort "$LAST_SYNC_TAGS") <(echo "$current_tags" | sort))

if [ -z "$new_tags" ]; then
    echo "No new tags to sync, exiting."
    exit 0
fi

# 登录镜像仓库
docker login "$ARTIFACTORY_REGISTRY" -u "$ARTIFACTORY_USER" -p "$ARTIFACTORY_PASS"
docker login "$ACR_REGISTRY" -u "$ACR_USER" -p "$ACR_PASS"

# 执行同步
for tag in $new_tags; do
    echo "Syncing $IMAGE_NAME:$tag..."
    if [ "$SYNC_DIRECTION" = "push_to_acr" ]; then
        docker pull "$ARTIFACTORY_REGISTRY/$ARTIFACTORY_REPO/$IMAGE_NAME:$tag"
        docker tag "$ARTIFACTORY_REGISTRY/$ARTIFACTORY_REPO/$IMAGE_NAME:$tag" "$ACR_REGISTRY/$IMAGE_NAME:$tag"
        docker push "$ACR_REGISTRY/$IMAGE_NAME:$tag"
    elif [ "$SYNC_DIRECTION" = "pull_to_artifactory" ]; then
        docker pull "$ACR_REGISTRY/$IMAGE_NAME:$tag"
        docker tag "$ACR_REGISTRY/$IMAGE_NAME:$tag" "$ARTIFACTORY_REGISTRY/$ARTIFACTORY_REPO/$IMAGE_NAME:$tag"
        docker push "$ARTIFACTORY_REGISTRY/$ARTIFACTORY_REPO/$IMAGE_NAME:$tag"
    fi
    echo "Synced $IMAGE_NAME:$tag successfully."
done

# 更新同步记录
echo "$current_tags" > "$LAST_SYNC_TAGS"

# 登出(可选)
docker logout "$ARTIFACTORY_REGISTRY"
docker logout "$ACR_REGISTRY"

Python 脚本方案

import os
import subprocess
import requests
from typing import List

# 配置参数(从环境变量读取,适配GitLab CI)
ARTIFACTORY_REGISTRY = os.getenv("ARTIFACTORY_REGISTRY")
ARTIFACTORY_REPO = os.getenv("ARTIFACTORY_REPO")
ARTIFACTORY_USER = os.getenv("ARTIFACTORY_USER")
ARTIFACTORY_PASS = os.getenv("ARTIFACTORY_PASS")
ACR_REGISTRY = os.getenv("ACR_REGISTRY")
ACR_USER = os.getenv("ACR_USER")
ACR_PASS = os.getenv("ACR_PASS")
IMAGE_NAME = os.getenv("IMAGE_NAME")
SYNC_DIRECTION = os.getenv("SYNC_DIRECTION", "push_to_acr")
LAST_SYNC_TAGS_PATH = "./last_sync_tags.txt"


def get_artifactory_tags() -> List[str]:
    """获取Artifactory中目标镜像的所有标签"""
    url = f"{ARTIFACTORY_REGISTRY}/v2/{ARTIFACTORY_REPO}/{IMAGE_NAME}/tags/list"
    response = requests.get(url, auth=(ARTIFACTORY_USER, ARTIFACTORY_PASS))
    response.raise_for_status()
    return response.json().get("tags", [])


def get_new_tags(current_tags: List[str]) -> List[str]:
    """对比上次同步记录,返回新增标签"""
    if not os.path.exists(LAST_SYNC_TAGS_PATH):
        return current_tags
    
    with open(LAST_SYNC_TAGS_PATH, "r") as f:
        last_tags = [line.strip() for line in f if line.strip()]
    
    return list(set(current_tags) - set(last_tags))


def docker_login(registry: str, username: str, password: str):
    """登录Docker仓库"""
    subprocess.run(
        ["docker", "login", registry, "-u", username, "-p", password],
        check=True,
        capture_output=True
    )


def sync_image(tag: str):
    """同步单个镜像标签"""
    print(f"Syncing {IMAGE_NAME}:{tag}...")
    if SYNC_DIRECTION == "push_to_acr":
        source_img = f"{ARTIFACTORY_REGISTRY}/{ARTIFACTORY_REPO}/{IMAGE_NAME}:{tag}"
        target_img = f"{ACR_REGISTRY}/{IMAGE_NAME}:{tag}"
    elif SYNC_DIRECTION == "pull_to_artifactory":
        source_img = f"{ACR_REGISTRY}/{IMAGE_NAME}:{tag}"
        target_img = f"{ARTIFACTORY_REGISTRY}/{ARTIFACTORY_REPO}/{IMAGE_NAME}:{tag}"
    else:
        raise ValueError(f"Invalid sync direction: {SYNC_DIRECTION}")
    
    subprocess.run(["docker", "pull", source_img], check=True)
    subprocess.run(["docker", "tag", source_img, target_img], check=True)
    subprocess.run(["docker", "push", target_img], check=True)
    print(f"Synced {IMAGE_NAME}:{tag} successfully.")


def update_sync_record(tags: List[str]):
    """更新同步记录文件"""
    with open(LAST_SYNC_TAGS_PATH, "w") as f:
        f.write("\n".join(tags))


if __name__ == "__main__":
    current_tags = get_artifactory_tags()
    new_tags = get_new_tags(current_tags)
    
    if not new_tags:
        print("No new tags to sync, exiting.")
        exit(0)
    
    # 登录仓库
    docker_login(ARTIFACTORY_REGISTRY, ARTIFACTORY_USER, ARTIFACTORY_PASS)
    docker_login(ACR_REGISTRY, ACR_USER, ACR_PASS)
    
    # 同步所有新增标签
    for tag in new_tags:
        sync_image(tag)
    
    # 更新记录
    update_sync_record(current_tags)
    
    # 登出(可选)
    subprocess.run(["docker", "logout", ARTIFACTORY_REGISTRY])
    subprocess.run(["docker", "logout", ACR_REGISTRY])

GitLab CI 配置示例

stages:
  - sync

sync-images:
  stage: sync
  image: docker:latest
  services:
    - docker:dind
  variables:
    # 这些变量建议在GitLab项目CI/CD设置中配置为受保护变量
    ARTIFACTORY_REGISTRY: "your-artifactory-registry-url"
    ARTIFACTORY_REPO: "your-docker-repo-name"
    ACR_REGISTRY: "your-acr-name.azurecr.io"
    IMAGE_NAME: "your-image-name"
    SYNC_DIRECTION: "push_to_acr" # 或 pull_to_artifactory
  before_script:
    # 安装依赖(二选一)
    - apk add --no-cache jq curl # 针对Bash脚本
    # - apk add --no-cache python3 py3-pip && pip install requests # 针对Python脚本
  script:
    - chmod +x ./sync_script.sh && ./sync_script.sh # Bash脚本执行方式
    # - python ./sync_script.py # Python脚本执行方式
  # 定时触发:每小时执行一次
  schedule:
    - cron: "0 * * * *"
      timezone: Asia/Shanghai
  # 可选:配置Artifactory Webhook触发CI流水线(新镜像上传时实时触发)

注意事项

  1. 所有敏感凭证(用户名/密码)请在GitLab项目的CI/CD设置中配置为受保护变量,禁止明文写入代码
  2. 使用Docker-in-Docker模式时,需确保GitLab Runner配置了privileged: true权限
  3. 可根据业务需求调整定时任务频率,或配置Artifactory的Webhook实现实时同步

内容的提问来源于stack exchange,提问作者Sridattha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:33:20