背景介绍

使用 docker pull <spec> 命令的时候,实际上有以下几条规则

docker pull规则

原理

接受与docker pull相同的参数,转化为镜像位置下载,然后再通过docker tag命令将镜像改名为正确的名称

使用方法

将以下python脚本保存为 docker.py ,并运行 python docker.py pull <spec> 这个命令

#!/usr/bin/python
# coding=utf8

import os
import sys

DEFAULT_DOCKER_HUB_URL = "docker.io"
GCR_URL = "k8s.gcr.io"

mirror_map = {
    "default": "dockerhub.azk8s.cn/library",
    DEFAULT_DOCKER_HUB_URL: "dockerhub.azk8s.cn",
    "gcr.io": "gcr.azk8s.cn",
    GCR_URL: "gcr.azk8s.cn"
}

url_default_namespace_map = {
    DEFAULT_DOCKER_HUB_URL: "library",
    GCR_URL: "google_containers"
}

def execute_sys_cmd(cmd):
    result = os.system(cmd)
    if result != 0:
        print(cmd + " failed.")
        sys.exit(-1)

def usage():
    print("Usage: " + sys.argv[0] + " pull ${image}")
    print("Support the following image spec:")
    print("\\tdocker.py pull nginx:alpine")
    print("\\tdocker.py pull library/nginx:alpine")
    print("\\tdocker.py pull docker.io/nginx:alpine")
    print("\\tdocker.py pull docker.io/library/nginx:alpine")
    print("\\tdocker.py pull docker.io/istio/mixer")
    print("\\tdocker.py pull k8s.gcr.io/pause:latest")
    print("\\tdocker.py pull gcr.io/google_containers/pause:latest")

if __name__ == "__main__":
    if len(sys.argv) != 3 or sys.argv[1] != "pull":
        usage()
        sys.exit(-1)

    image = sys.argv[2]
    elements = image.split("/")

    URL = ""
    namespace = ""
    imageName = ""

    # nginx:alpine
    if len(elements) == 1:
        URL = DEFAULT_DOCKER_HUB_URL
        namespace = url_default_namespace_map[URL]
        imageName = elements[0]

    if len(elements) == 2:
        if "." in elements[0]:
            # docker.io/nginx:alpine
            # k8s.gcr.io/pause:latest
            URL = elements[0]
            if URL not in url_default_namespace_map:
                raise "Cannot find default namespace for " + image
            namespace = url_default_namespace_map[URL]
            imageName = elements[1]
        else:
            # library/nginx:alpine
            # istio/mixer
            URL = DEFAULT_DOCKER_HUB_URL
            namespace = elements[0]
            imageName = elements[1]
    
    if len(elements) == 3:
        URL = elements[0]
        namespace = elements[1]
        imageName = elements[2]

    if URL not in mirror_map:
        raise "Cannot find mirror for " + image

    newImage = mirror_map[URL] + "/" + namespace + "/" + imageName
    targetTagName = image
    if URL == DEFAULT_DOCKER_HUB_URL:
        if namespace == url_default_namespace_map[URL]:
            targetTagName = imageName
        else:
            targetTagName = namespace + "/" + imageName
    
    print("-- pulling image %s --" % image)

    cmd = "docker pull {image}".format(image=newImage)
    print("\\t" + cmd)
    execute_sys_cmd(cmd)

    cmd = "docker tag {newImage} {image}".format(newImage=newImage, image=targetTagName)
    print("\\t" + cmd)
    execute_sys_cmd(cmd)

    cmd = "docker rmi {newImage}".format(newImage=newImage)
    print("\\t" + cmd)
    execute_sys_cmd(cmd)

    print("-- {image} pulling done --".format(image=image))
    sys.exit(0)