本文介绍如何将默认实例中的镜像迁移至企业版实例。

迁移前准备

  1. 已拥有与默认实例同地域的ECS实例。具体操作,请参见实例计费
  2. 设置迁移任务的运行环境,推荐在VPC内网环境中运行迁移任务。
    • 如果在VPC内网环境中运行迁移任务,需要在企业版实例中绑定该ECS实例的VPC。具体操作,请参见配置专有网络的访问控制
    • 如果在公网环境中运行迁移任务,需要为企业版实例开启公网访问。具体操作,请参见配置公网的访问控制
  3. 验证ECS实例能否通过内⽹或公网环境访问默认实例和企业版实例。
    docker login <实例域名>

    预期输出:

    Login Succeeded

操作步骤

  1. 执行以下命令,下载阿里云CLI工具。更多信息,请参见CLI
    wget https://github.com/aliyun/aliyun-cli/releases/download/v3.0.60/aliyun-cli-linux-3.0.60-amd64.tgz
    tar -xzvf aliyun-cli-linux-3.0.60-amd64.tgz
    mv aliyun /usr/local/bin/
  2. 配置CLI访问容器镜像服务的AccessKey ID和AccessKey Secret。

    该配置用于在迁移过程中获取默认实例中的镜像仓库列表。

    aliyun configure --mode=AK
    Configuring profile 'default' in 'AK' authenticate mode...
    Access Key Id:<yourAccessKeyId>
    Access Key Secret:<yourAccessKeySecret>
    Default Region Id:<migrateRegionId>
    Default Output Format [json]: json (Only support json)
    Default Language [zh|en] en: zh
    Saving profile[default] ...Done.
    说明 以上配置中,Default Region Id需要和企业版实例的地域保持一致。
  3. 下载镜像同步工具image-syncer。
    wget https://node-local-dns.oss-cn-hangzhou.aliyuncs.com/image-syncer
    chmod +x image-syncer
  4. 在ECS实例上创建如下脚本migrate.sh
    #!/bin/bash
    
    usage()
    {
        echo "Usage: $0 [-v] [-a] [-i instanceId] [-r regionId]"
        echo "-v: pull and push via vpc network."
        echo "-a: auto create acr-ee namespace and set autoCreateRepo = true."
        echo "-i: acr-ee instance id."
        echo "-r: acr-ee instance region id."
        exit 2
    }
    
    set_variable()
    {
      local varname=$1
      shift
      if [ -z "${!varname}" ]; then
        eval "$varname=\"$@\""
      else
        echo "Error: $varname already set"
        usage
      fi
    }
    
    create_or_update_namespace()
    {
        local instanceId=$1
        local regionId=$2
        local namespaceName=$3
    
        local namespace=$(aliyun cr GetNamespace --region $regionId --version 2018-12-01 --InstanceId $instanceId --RegionId $regionId --NamespaceName $namespaceName --force)
        local Exists=$(echo $namespace | jq ".IsSuccess")
        local AutoCreateRepo=$(echo $namespace | jq ".AutoCreateRepo")
    
        if [ "$Exists" != "true" ]; then
            echo "create namespace: $namespaceName for acr-ee instance: $instanceId."
            local message=$(aliyun cr CreateNamespace --region $regionId --version 2018-12-01 --InstanceId $instanceId --RegionId $regionId --NamespaceName $namespaceName --AutoCreateRepo true --force)
        elif [ "$AutoCreateRepo" != "true" ]; then
            echo "set AutoCreateRepo = true for namespace: $namespaceName in instance: $instanceId."
            local message=$(aliyun cr UpdateNamespace --region $regionId --version 2018-12-01 --InstanceId $instanceId --RegionId $regionId --NamespaceName $namespaceName --AutoCreateRepo true --force)
        fi
    }
    
    ######### Pre ###########
    # jq
    if ! [ -x "$(command -v jq)" ]; then
        echo "install jq"
        wget https://node-local-dns.oss-cn-hangzhou.aliyuncs.com/jq
        chmod +x jq
        mv jq /usr/bin/jq
    fi
    
    ######### Main ###########
    unset instanceId regionId vpc autocreate images
    
    while getopts 'vai:r:?h' c
    do
        case $c in
            v) set_variable vpc "-vpc" ;;
            a) set_variable autocreate "true" ;;
            i) set_variable instanceId $OPTARG ;;
            r) set_variable regionId $OPTARG ;;
            h|?) usage ;; esac
    done
    
    [ -z "$instanceId" ] && usage
    [ -z "$regionId" ] && usage
    
    # check instance exists
    instanceName=$(aliyun cr GetInstance --version 2018-12-01 --InstanceId $instanceId  --RegionId $regionId --force | jq ".InstanceName")
    [ "$instanceName" = "null" ] && echo "acr-ee instance not exists." && exit 1
    instanceName=$(echo $instanceName | sed "s/\"//g")
    
    ## username、password
    read -p "Username for registry$vpc.$regionId.aliyuncs.com: " UsernameDefault
    read -p "Password for registry$vpc.$regionId.aliyuncs.com: " PasswordDefault
    
    read -p "Username for $instanceName-registry$vpc.$regionId.cr.aliyuncs.com: " Username
    read -p "Password for $instanceName-registry$vpc.$regionId.cr.aliyuncs.com: " Password
    
    ## generate config 
    PageSize=100
    
    namespaces=$(aliyun cr GET /namespace | jq ".data.namespaces[].namespace")
    IFS=' ' read -r -a aNamespace <<< $(echo $namespaces | sed "s/\"//g")
    for namespace in "${aNamespace[@]}"
    do
        PageNo=1
        total=$(aliyun cr --region $regionId GET /repos/$namespace --PageNo $PageNo --PageSize $PageSize | jq ".data.total")
        echo "namespace: $namespace has $total repositories."
    
        if [ "$autocreate" = "true" ]; then
            create_or_update_namespace $instanceId $regionId $namespace
        fi
    
        let total=total+PageSize
    
        while
            let current=PageNo*PageSize
            (( "$current" < "$total" ))
        do
            repos=$(aliyun cr GET /repos/$namespace --Page $PageNo --PageSize $PageSize | jq ".data.repos[].repoName")
            IFS=' ' read -r -a array <<< $(echo $repos | sed "s/\"//g")
            for repo in "${array[@]}"
            do
                image="\"registry$vpc.$regionId.aliyuncs.com/$namespace/$repo\":\"$instanceName-registry$vpc.$regionId.cr.aliyuncs.com/$namespace/$repo\""
                if [ "$images" = "" ]; then
                    images=$image
                else
                    images="$images,$image"
                fi
            done
            let PageNo=PageNo+1
        done
    done
    
    config='{ "auth": { "registry%s.%s.aliyuncs.com": { "username": "%s", "password": "%s" }, "%s-registry%s.%s.cr.aliyuncs.com": { "username": "%s", "password": "%s" } }, "images": {%s} }'
    echo $images
    echo $config
    
    printf "$config" "$vpc" "$regionId" "$UsernameDefault" "$PasswordDefault" "$instanceName" "$vpc" "$regionId" "$Username" "$Password" "$images" | jq | cat  > config.json
    
    ######## sync #########
    ./image-syncer --proc=4 --config=./config.json --retries=3
    参数 说明
    -v: pull and push via vpc network. 使用VPC内网环境执行镜像迁移,加快迁移任务速度。
    说明 如果您使用的是公网环境,则无需设置此参数。
    -a: auto create acr-ee namespace and set autoCreateRepo = true. 自动在企业版实例中创建和更新与默认实例版中对应的命名空间,并让该命名空间开启自动创建仓库功能。
    -i: acr-ee instance id. 指定企业版实例ID。
    -r: acr-ee instance region id. 指定地域ID。
  5. 运行脚本,执行迁移任务。
    ./migrate.sh -v -a -i <yourACREEInstanceId> -r <regionId>
    Username for registry-vpc.cn-shanghai.aliyuncs.com: <默认实例登录名>
    Password for registry-vpc.cn-shanghai.aliyuncs.com: <默认实例登录密码>
    Username for cn-shanghai-instance1-registry-vpc.cn-shanghai.cr.aliyuncs.com: <企业版实例登录名>
    Password for cn-shanghai-instance1-registry-vpc.cn-shanghai.cr.aliyuncs.com: <企业版实例登录密码>

结果验证

  • 任务执行完成后,可以在ECS实例上看到迁移镜像的记录。
    cat records

    预期输出:

    cn-shanghai-instance1-registry-vpc.cn-shanghai.cr.aliyuncs.com/<yourNamespace>/<yourRepo>,<blob>,<blobSize>
    ...
  • 在容器镜像服务控制台中对比默认实例和企业版实例,可以发现默认实例的所有命名空间、镜像仓库以及镜像Tag版本均已迁移到企业版实例。