github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/docs/design/image-save_zh.md (about) 1 # docker镜像及helm chart包保存 2 3 save模块的位置在image/save目录下,其作用是拉取其他仓库中的docker镜像或者helm chart包,并保存到本地的文件系统中。 4 5 ## 使用示例 6 7 ### Helm chart包 8 9 > workflow: 用helm push 推送chart包到registry中->使用sealer build将chart包存储到集群镜像中->用build后的集群镜像建立集群,使用helm pull拉取仓库中的chart包 10 11 #### Step1: helm push 推送chart包到registry中 12 13 例如,本地存在两个已经构建好的chart包:mysql-8.8.19-tgz和rabbitmq-8.24.13.tgz。首先用registry:2.7.1镜像启动docker容器监听5000端口,然后设置环境变量`HELM_EXPERIMENTAL_OCI=1`,接着执行`helm push mysql-8.8.19-tgz oci://localhost:5000/helm-charts`,`helm push rabbitmq-8.24.13.tgz oci://localhost:5000/helm-charts`。 14 15 #### Step2: 使用sealer build将chart包存储到集群镜像中 16 17 在一个空目录下创建两个文件,一个是`Kubefile`文件,一个是`imageList`文件。`Kubefile`文件内容如下: 18 19 ``` 20 FROM kubernetes-clusterv2:v1.19.8 21 COPY imageList manifests 22 ``` 23 24 `imageList`文件内容如下: 25 26 ``` 27 localhost:5000/helm-charts/mysql:8.8.19 28 localhost:5000/helm-charts/rabbitmq:8.24.13 29 ``` 30 31 在该目录下执行`sealer build -t test:1 .` 32 33 #### Step3: 建立集群并用helm pull拉取仓库中的chart包 34 35 需要一台额外的机器来创建k8s集群,其ip地址用`x.x.x.x`表示。执行`sealer run test:1 -m x.x.x.x -p x`创建集群。集群创建成功后,进入ip地址为`x.x.x.x`的机器,安装helm,设置环境变量`HELM_EXPERIMENTAL_OCI=1`。然后可以通过执行`helm pull oci://sea.hub:5000/helm-charts/mysql --version 8.8.19`和`helm pull oci://sea.hub:5000/helm-charts/rabbitmq --version 8.24.13`来拉取相应的chart包。 36 37 ### Docker 镜像 38 39 > workflow: 使用sealer build将docker镜像存储到集群镜像中->用build后的集群镜像建立集群,使用docker pull拉取仓库中的docker镜像 40 41 #### Step1: 使用sealer build将docker镜像存储到集群镜像中 42 43 在一个空目录下创建两个文件,一个是`Kubefile`文件,一个是`imageList`文件。`Kubefile`文件内容如下: 44 45 ``` 46 FROM kubernetes-clusterv2:v1.19.8 47 COPY imageList manifests 48 ``` 49 50 `imageList`文件内容如下: 51 52 ``` 53 mysql:latest 54 ubuntu:18.04 55 ``` 56 57 如果要拉取私有仓库的镜像,请先执行`docker login` 登录。在该目录下执行`sealer build -t test:1 .` 58 59 #### Step2: 建立集群并用docker pull拉取仓库中的docker镜像 60 61 需要一台额外的机器来创建k8s集群,其ip地址用`x.x.x.x`表示。执行`sealer run test:1 -m x.x.x.x -p x`创建集群。集群创建成功后,进入ip地址为`x.x.x.x`的机器,执行`docker pull sea.hub:5000/mysql:latest`和`docker pull sea.hub:5000/ubuntu:18.04`来拉取相应的docker镜像。 62 63 ## 模块工作流程 64 65 1. 解析镜像名称,获得三个重要信息:域名(registry),仓库名(repository),镜像名(image),把相同域名的镜像放在一个切片中,以便后续一起处理。 66 2. 根据域名建立与相应的registry的连接。然后就能获取到repository service, manifest service, tag service, blob service. 通过这些service来拉取和保存镜像数据。 67 3. 获取manifest列表,该列表包含所有架构的镜像。每一个镜像都有一个唯一的digest字段。通过digest字段可以获取到该镜像的manifest数据。 68 4. 获取blob数据。每一个镜像都包含多个blob,每一个blob也有一个唯一的digest字段。通过步骤3中的manifest可以获取到所有的blob的digest字段,然后再通过blob的digest字段能够获取到所有的blob的数据。 69 5. 把一个镜像的manifest和blob都拉取下来之后,保存到本地的文件系统下。这样,启动一个私有registry时,只需要挂载相应的目录,私有registry中就包含了目录下的所有镜像。 70 71 ## 对外暴露接口 72 73 save模块对外只暴露一个接口,如下: 74 75 ``` 76 type ImageSave interface { 77 SaveImages(images []string, dir, arch string) error 78 } 79 ``` 80 81 `SaveImages`函数接收三个参数,返回一个error信息。三个参数分别代表着: 82 83 1. images:要保存的所有的镜像名称,类型是一个字符串slice 84 2. dir:保存镜像的目的路径,类型是string 85 3. arch:要保存的镜像是基于什么处理器架构的,类型是string 86 87 save模块定义了一个DefaultImageSaver对象,该对象实现了ImageSave接口,同时还提供了该对象的New函数。 88 89 ``` 90 type DefaultImageSaver struct { 91 ctx context.Context 92 domainToImages map[string][]Named 93 } 94 95 func NewImageSaver(ctx context.Context) ImageSave { 96 if ctx == nil { 97 ctx = context.Background() 98 } 99 return &DefaultImageSaver{ 100 ctx: ctx, 101 domainToImages: make(map[string][]Named), 102 } 103 } 104 ``` 105 106 `DefaultImageSaver`对象有两个字段,一个是`context.Context`类型,表示代码执行的上下文环境。另一个是从`string`到`[]Named`的映射,`string`表示域名,`[]Named`是镜像名称的切片,该映射其实是从域名到该域名下的所有镜像名称的映射。 107 108 `NewImageSaver`函数接收一个`context.Context`类型的参数,若该参数为空,则调用`context.Background()`创建一个`context.Context`类型的对象用来对`DefaultImageSaver`进行初始化。 109 110 `ImageSave`接口的使用示例如下: 111 112 ``` 113 images := []string{"ubuntu", "ubuntu:18.04", "registry.aliyuncs.com/google_containers/coredns:1.6.5", "fanux/lvscare"} 114 is := NewImageSaver(context.Background()) 115 err := is.SaveImages(images, "/var/lib/registry", "amd64") 116 if err != nil { 117 panic(err) 118 } 119 ```