Docker镜像代理

管理数据中心的 k8s 集群,最麻烦的是网络环境的限制,内网、单出口等,集群镜像拉取上,目前采用了两个方案,达成节省带宽与突破访问限制的目的。

方案一:Harbor

Harbor 在我们集群中作为统一的镜像管理中心,同时也承担着镜像代理的职责。

1. 简单搭建

  • 官方 Release 中下载最新的离线包
  • tar -xvf 解压到本地
  • 修改 harbor.yml 中的 hostnameharbor_admin_password
  • 执行 ./install.sh (修改配置后,直接执行 ./prepare 即可)

重配置 harbor.yml
执行 ./prepare
重启容器
harbor 路径下执行 docker-compose down 停止所有容器

执行 docker-compose up -d 启动所有容器


2. 设置缓存仓库

进入 harbor 管理界面,Registries -> New Registry Endpoint 选择对应的 Provider

ZnOJF5oQ9AYiLW4

以代理 Docker Hub 为例 (Docker Hub更新使用条款后,对每日拉取镜像数量有限制):

  • Provider 中设置 Docker Hub
  • Endpoint URL 中设为 https://hub.docker.com
  • Access IDAccess Secret 分别填入 Docker Hub 账号密码。

3. 新建项目

使用上述镜像,还需要新建一个项目,项目是 harbor 中的一个管理单位。

Project 中点新建,如果是一个镜像缓存项目,需要开启 Proxy Cache

IzmSgsTDCZhKPNH

4. 作为镜像代理使用

在客户端服务器中配置 Docker ,以地址 10.1.0.46为例

  • 配置 /etc/docker/daemon.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    "insecure-registries": [
    "10.1.0.46"
    ],
    "log-opts": {
    "max-file": "5",
    "max-size": "50m"
    }
    }
  • 登陆 harbor :

    1
    $ docker login 10.1.0.46

    按分配的账号密码登录。

  • 拉取镜像:

    harbor 已配置好 Docker Hub 的 proxy cache ,需要拉取 Docker Hub 中的镜像,需要按照如下格式

    1
    $ docker pull 10.1.0.46/dockerhub/<IMAGE_NAME>:<VERSION>

    <> 中的内容请自行替换。

    注:某些使用场景可能需要在本地重新 docker tag 一下

  • 上传镜像:

    1
    2
    $ docker tag <IMAGE_NAME>:<VERSION> 10.1.0.46/<PROJECT_NAME>/<IMAGE_NAME>:<VERSION>
    $ docker push 10.1.0.46/<PROJECT_NAME>/<IMAGE_NAME>:<VERSION>

    由于 harbor 中是按照项目进行管理,所以镜像上传时一定要指定对应的项目名。

  • 访问 GCR:

    Harbor 的 proxy cache 目前只支持 Docker Hub 或其他 Harbor 仓库,因此想要使用 Harbor 拉取 gcr.io 中的镜像,需要使用 Docker Hub 中的 mirrorgcrio 仓库。

    1
    $ docker pull 10.1.0.46/dockerhub/mirrorgcrio/<IMAGE>

    以拉取 k8s 镜像为例,参见以下脚本实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #!/bin/bash
    # 获取要拉取的镜像信息,images.txt是临时文件
    kubeadm config images list > images.txt

    # 替换成mirrorgcrio的仓库,该仓库国内可用,和k8s.gcr.io的更新时间只差一两天
    sed -i 's@k8s.gcr.io@10.1.0.46/dockerhub/mirrorgcrio@g' images.txt

    # 拉取各镜像
    cat images.txt | while read line
    do
    docker pull $line
    done

    # 修改镜像tag为k8s.gcr.io仓库,并删除mirrorgcrio的tag
    sed -i 's@10.1.0.46/dockerhub/mirrorgcrio/@@g' images.txt
    cat images.txt | while read line
    do
    docker tag 10.1.0.46/dockerhub/mirrorgcrio/$line k8s.gcr.io/$line
    docker rmi -f 10.1.0.46/dockerhub/mirrorgcrio/$line
    done

    # 操作完后显示本地docker镜像
    docker images

    # 删除临时文件

    但其实可以发现,这种方式是比较麻烦的,需要频繁的 docker tag 改镜像名,另一种方式是直接在海外服务器上构建一个镜像代理。


方案二:docker-registry-proxy

来源于 https://github.com/rpardini/docker-registry-proxy ,该方案需要部署服务器具有gcr的访问能力,其他客户端机器通过该服务器实现镜像的转发。

gcr 认证

https://cloud.google.com/container-registry/docs/advanced-authentication#json_key_file

CWO5tsAJKE2m871

点击如图蓝色按钮进入 Service Account Key page

之后按照提示新建一个 JSON 格式的服务账号密钥,创建完成后从 Google Cloud Platform 提供的链接中下载密钥,下一步使用。


###配置 registry-proxy

运行:

1
2
3
4
5
6
7
8
9
docker run --rm --name docker_registry_proxy -it \
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
-v $(pwd)/docker_mirror_certs:/ca \
-e REGISTRIES="k8s.gcr.io gcr.io quay.io docker.io" \
-e AUTH_REGISTRIES_DELIMITER=";;;" \
-e AUTH_REGISTRY_DELIMITER=":::" \
-e AUTH_REGISTRIES="gcr.io:::_json_key:::$(cat <servicekey.json>);;;auth.docker.io:::<USERNAME>:::<PASSWORD>" \
rpardini/docker-registry-proxy:0.6.1

说明:

  • ;;; 为镜像中心分隔符,::: 为账号密码分隔符;

  • 可配置多个注册中心


客户端配置

可以直接运行命令,在 <SERVER_ADDR> 将服务器地址作为参数填入。

1
$ sh -C "$(wget -O- https://raw.githubusercontent.com/fusidic/Scripts/master/General/docker-proxy.sh)" <SERVER_ADDR>

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/bin/bash

RED='\033[0;31m'
NC='\033[0m' # No Color

a=`uname -a`
b="ubuntu"
c="/etc/centos-release"

if [ "$1" == "" ];then
echo -e " ${RED}[ERROR] Missing required parameters!${NC}\n"
echo -e " Usage:
./docker-proxy.sh [proxy_addr]
Params:
proxy_addr Your docker proxy server address
"
exit 1
fi

# Add environment vars pointing Docker to use the proxy
mkdir -p /etc/systemd/system/docker.service.d
cat << EOD > /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://${1}/"
Environment="HTTPS_PROXY=http://${1}/"
EOD

# Get the CA certificate from the proxy and make it a trusted root.
if [[ $a =~ $b ]];then
# Ubuntu
curl http://${1}/ca.crt > /usr/share/ca-certificates/docker_registry_proxy.crt
echo "docker_registry_proxy.crt" >> /etc/ca-certificates.conf
update-ca-certificates --fresh
elif [[ -f "$c" ]];then
# CentOS
curl http://${1}/ca.crt > /etc/pki/ca-trust/source/anchors/docker_registry_proxy.crt
echo "docker_registry_proxy.crt" >> /etc/ca-certificates.conf
update-ca-trust
else
echo "System version $a"
echo "No way"
fi

# Reload systemd
systemctl daemon-reload

# Restart dockerd
systemctl restart docker.service