利用阿里云来加速Kubeflow的安装

最近尝试了一下Kubeflow的安装,发现问题不少,因为里面用到的镜像大多是来自GCR.io,因为众所周知的原因,在国内是无法访问Google的镜像仓库的。搜了一下网上的教程,大多是把这些镜像同步到了其他的国内镜像源,但是好像很多都不能访问,或者版本不是最新的。因此我也做了一些研究,总结了一个方法可以自动化的把最新版本的镜像同步到国内的阿里云的镜像仓库。

获取Kubeflow Manifest用到的镜像

首先是下载Kubeflow的manifest,目前官网最新的版本是v1.2,在github上克隆项目,并切换到v1.2的版本

git clone https://github.com/kubeflow/manifests.git
git checkout v1.2-branch

遍历manifest里面的所有yaml文件,找出所有和gcr.io, quay.io, docker.io相关的镜像,以及其tag,代码如下:

import os
import json
import re

base_dir = 'manifests'
image_uri_re = re.compile(r"\.*((?:gcr|quay|docker)\.io/[^',\"\s\n\\]+)")
image_name_re = re.compile(r'^.*/([^@]*)')
tag_re = re.compile(r"\.*(?:tag|newTag): \'?([^\'\\]*)")
images_with_tag = set()
images_with_digest = set()

def checkfiles(path):
    files = os.listdir(path)
    subpath = []
    for item in files:
        newpath = path + "/" + item
        if os.path.isdir(newpath):
            subpath.append(newpath)
        else:
            if item.endswith('.yaml'):
                with open(newpath, 'r') as f:
                    lines = f.readlines()
                    for i in range(len(lines)):
                        if re.search(image_uri_re, lines[i]):
                            result = re.search(image_uri_re, lines[i]).group(1).strip()
                        else:
                            continue
                        
                        if ':' in result and '@' not in result:
                            images_with_tag.add(result)
                            continue
                        
                        if '@' in result:
                            images_with_digest.add(result)
                            continue
                        
                        tag = ''
                        if i<len(lines)-1:
                            if re.search(tag_re, lines[i+1]):
                                tag = re.search(tag_re, lines[i+1]).group(1)
                                i += 1
                            else:
                                if i<len(lines)-2:
                                    if re.search(tag_re, lines[i+2]):
                                        tag = re.search(tag_re, lines[i+2]).group(1)
                                        i += 2
                        
                        if tag!='':
                            images_with_tag.add(result+':'+tag.strip())
    if len(subpath)>0:
        for p in subpath:
            checkfiles(p)

checkfiles(base_dir)

代码运行后,会找到所有gcr.io, quay.io, docker.io的镜像。其中绝大部分镜像是带Tag的,另外有小部分的镜像是以digest的方式来获取。

自动同步镜像到国内的镜像服务器

获取了镜像的列表之后,我们就可以把这些镜像同步到国内的镜像服务器。这里我用的是阿里云的镜像仓库,选取仓库所在的区域,创建命名空间。例如我选择在广州创建镜像仓库,并建立一个叫做my_kubeflow的命名空间。

之后需要用到阿里的Image-syncer的软件来自动同步,具体用法可见https://github.com/AliyunContainerService/image-syncer

下载了Image-syncer的软件后,需要建立两个配置文件,一个是auth.yaml,在里面需要设置镜像仓库的用户名和密码。另一个是images.yaml,里面每一行是对应从源仓库Pull image,以及Push Image到目的地仓库,具体可以见Github上面的例子

这里有点麻烦的是,对于GCR的镜像,Google目前是没有提供用户名密码的方式来登录,需要参考https://cloud.google.com/container-registry/docs/advanced-authentication这个网页,里面提到了安装Google Cloud SDK,然后用Access Token的方式获取Token,这个可以作为密码来登录。这个方法有几个问题,一个是国内是无法访问Google的网站和下载Google Cloud SDK的,另一个是这个Token的有效期很短,只有1个小时。

为了解决无法安装Google Cloud SDK的问题,我们可以在阿里云上创建一台主机,主机位于美国区域,选择共享型的即可,我选择的是2CPU, 4G内存,40G数据盘,大概是0.6元/小时,不过其实选择1G内存应该也够了,费用还能更低一些。

在阿里云的主机上需要安装Google Cloud SDK后,可以通过以下命令来获取access token

~/software/google-cloud-sdk/bin/gcloud auth activate-service-account [email protected] --key-file=/root/projects/docker_sync/google_cloud.json

~/software/google-cloud-sdk/bin/gcloud auth print-access-token

然后把获取的Token作为密码写入到auth.yaml的gcr.io的认证信息中。

把之前获取的kubeflow manifests获取的镜像列表写入到images.yaml文件中,目的地仓库的地址填写阿里云创建的镜像命名空间,目录结构保持一致,例如以下的例子:

gcr.io/ml-pipeline/visualization-server:1.0.4: registry.us-west-1.aliyuncs.com/my_kubeflow/ml-pipeline/visualization-server:1.0.4

最后在云主机上运行image-syncer即可

nohup ./image-syncer --proc=6 --auth=./auth.yaml --images=./images.yaml 1>result.out 2>result.out &

运行结果会写入到result.out文件中,因为gcr.io的Token有效期只有1个小时,如果超出了就会无法拉取gcr的镜像,因此需要定期检查一下result.out的内容,如果出现token过期,需要重新获取token并更新auth.yaml

等同步运行完成后,即可愉快的用阿里云的镜像仓库地址替换掉manifest里面所有的gcr.io, docker.io, quay.io的镜像了。

手动构建镜像到国内镜像仓库(可选)

以上提到的自动同步镜像的方法虽然很方便,不过美中不足的是速度比较慢,大概要跑个2天才能全部同步完成。

这里有另外一种更快速的方法,就是在阿里云的镜像服务中设置用海外服务器来手工构建镜像,不过这种方法需要一个一个镜像在控制面版中添加仓库,比较繁琐。如果对于少量镜像需要同步的场景,可以用这种方式。如果太多镜像需要同步,还是建议用以上自动同步的方式来做。

以阿里云为例,在容器镜像服务的管理页面中,点击创建镜像仓库,填入仓库名称,点击下一步,在代码源里面选择Github里面存放Dockerfile的仓库。仓库创建完成后,在构建里面,开启海外机器构建的选项,然后添加规则,规则类型是Branch,填入Dockerfile目录和Tag,然后点击构建即可。

这里以构建gcr.io/ml-pipeline/visualization-server:1.0.4这个镜像为例,在自己的Github仓库中,建立一个ml-pipeline/visualization-server/1.0.4的目录,在这个目录下建立一个Dockerfile文件,内容如下:

From gcr.io/ml-pipeline/visualization-server:1.0.4
MAINTAINER gzroy <[email protected]>

建立私有镜像仓库(可选)

除了以上两种方式外,还有另外一个选择,也记录一下。

上面提到了可以创建一个阿里云的美国主机,来自动同步镜像,但是这种方式需要经常检查Google Token是否过期,过期后需要重新更新auth,以及重新运行image-syncer,其实也比较麻烦。

还有一种方式就是,在这个阿里云的美国主机上,直接运行docker pull的命令,把镜像列表的所有镜像拉取到本地,然后运行docker save把本地镜像打包。之后下载这个打包文件到本地,然后在本地建立一个私有的Dockers仓库,把这些镜像上传,之后就可用本地的仓库地址来替换manifests里面的镜像了。

私有Docker仓库的建立

docker pull registry

启动镜像

#创建数据存储的文件夹 ,将容器的/tem/registry目录映射到/docker/registry
mkdir /docker/registry

#启动容器,设定端口5000 ,然后映射文件夹,-v <宿主机目录>:<容器目录>
sudo docker run -d -p 5000:5000 --name myregistry --restart=always --privileged=true  -v /docker/registry:/var/lib/registry  registry

#--restart 标志会检查容器的退出代码,并据此来决定是否要重启容器,默认是不会重启。 
#--restart的参数说明 
#   always:无论容器的退出代码是什么,Docker都会自动重启该容器。 
#   on-failure:只有当容器的退出代码为非0值的时候才会自动重启。
#另外,该参数还接受一个可选的重启次数参数,`--restart=on-fialure:5`表示当容器退出代码为非0时,Docker#会尝试自动重启该容器,最多5次。

推送镜像到本地仓库

#必须要先将镜像的名称给变成  域名或ip/镜像名
docker tag kubia 192.168.1.6:5000/kubia

#推送到本地的仓库上
docker push 192.168.1.6:5000/kubia

用minikube来测试,如果之前minikube已经创建过,需要先执行minikube delete

minikube start --registry-mirror=https://registry.docker-cn.com --insecure-registry=192.168.1.6:5000

之后就可以在minikube来拉取镜像运行pod了

kubectl run kubia --image=192.168.1.6:5000/kubia --port=8080 --generator=run/v1

猜你喜欢

转载自blog.csdn.net/gzroy/article/details/113482322