github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/docs/design/build_zh.md (about) 1 # 集群镜像 build 2 3 ## Build 类型层 4 5 该模块主要通过对不同构建类型的区分,完成对集群镜像构建前期环境的准备,例如启动K8S 集群,启动sealer registry,以及拉取用于构建的镜像,从而分别实现Build接口,完成对集群镜像的构建。 6 7 ### 类型介绍 8 9 目前sealer 支持4种构建方式,用户可以通过命令行`-m` 参数指定,详细使用文档见[build 使用文档](../site/src/docs/getting-started/build-cloudimage.md) 。 10 11 #### lite build 12 13 该种构建模式,根据Kubefile的定义,实现不用拉起kubernetes集群的轻量化构建。用于已知镜像清单,或者没有特殊的资源需求的场景。 14 15 核心功能介绍 16 17 1. 基础集群镜像的拉取和挂载。 18 2. 本地缓存registry的启动和挂载。 19 3. 根据kubefile执行构建指令,收集相关产物。 20 4. 收集缓存的容器镜像。 21 5. 清理环境,本地缓存registry的回收。 22 23 ### 接口定义 24 25 `Build(name string, context string, kubefileName string) error` 26 27 参数解释 28 29 ```yaml 30 name: 新构建的集群镜像名字,不支持大写和特殊字符。 31 context: 用于构建集群镜像的上下文,默认为当前目录。 32 kubefilename: kubefile 用于描述集群镜像的构建过程,和Dockerfile类似。该参数为用户自定义的kubefile文件路径。 33 error: 当执行构建时候,如有发生错误,则会返回该错误。 34 ``` 35 36 ## Build 镜像层 37 38 集群构建流程的核心的实现,主要通过解析kubefile,初始化镜像模块接口,根据集群镜像的layer层定义,执行对应的指令内容和收集对应的产物,从而生成完整的集群镜像。 39 40 核心功能介绍 41 42 1. kubefile 文件的解析。 43 2. 镜像模块接口初始化,获取当前镜像的基础镜像信息和当前镜像层。 44 3. 根据文件目录生成新的镜像层 45 4. 构建指令的执行,以及对应的layer内容的预处理,对应的指令产物收集。 46 5. 新集群镜像的生成和提供对文件系统的存储功能。 47 48 ### 接口定义 49 50 ```shell 51 SaveBuildImage(name string) error 52 ExecBuild(ctx Context) error 53 Cleanup() error 54 ``` 55 56 参数解释 57 58 Context 结构体 59 60 ```yaml 61 BuildContext: 构建的上下文。 62 BuildType: 构建的类型。 63 UseCache: 标志位,用于检测是否使用缓存。 64 ``` 65 66 ### 构建流程介绍 67 68 Kubefile 举例如下: 69 70 ```shell 71 FROM registry.cn-qingdao.aliyuncs.com/sealer-io/kubernetes:v1.19.8 72 COPY recommended.yml manifests 73 COPY imageList manifests 74 COPY traefik ./charts 75 COPY bin/helm /bin 76 RUN helm --help 77 CMD kubectl apply -f manifests/recommended.yml 78 CMD helm install mytest charts/traefik 79 ``` 80 81 1. 根据Kubefile 初始化对应的BuildImage `NewBuildImage(kubefileName string)`,得到一个BuildImage结构体。 82 2. 根据Kubefile的内容,判断是否需要获取基础镜像,是否需要启动缓存registry,并且初始化镜像模块的接口。 83 3. 按照Kubefile对应的每一层内容,初始化不同的build指令,并且执行该指令,收集对应的产物。 84 4. 根据该层指令内容触发对应的layer 层的handler。例如 `COPY imageList manifests` 则会解析imageList中的镜像,并且缓存起来。 85 5. 待Kubefile对应的每一层内容执行完成后,根据是否启动缓存registry,判断是否需要收集对应的docker 镜像。 86 6. 待所有产物收集完毕,调用镜像模块接口将新构建的镜像保存到文件系统。 87 7. 环境清理,例如构建时候产生的临时文件,缓存registry的回收等。 88 89 ## Build 指令层 90 91 该模块主要完成对不同的构建指令的生成和执行,包括 `copy`,`cmd`,`run` 等具体指令的实现,以及集群镜像的层级挂载,集群镜像的缓存判断,指令层的对应layer id生成,对应layer层产物的存储等等。 92 93 ### 指令介绍 94 95 copy 指令 96 97 * 实现构建上下文的copy功能。 98 * 根据指令内容,实现对应的layer层功能。 99 * 根据指令产物,计算对应指令的layer id。 100 101 cmd 指令 102 103 * 挂载基础镜像和该指令之前所以指令层产物。 104 * 根据指令内容,实现对应的layer层功能。 105 * 根据挂载的指令层产物,实现对应的系统命令的调用。 106 * 一个kubefile,可以有多个cmd指令,但cmd指令没有产物,即不会计算对应的指令layer id。 107 108 run 指令 109 110 * 实现逻辑同cmd指令一致,但是会根据指令产物计算对应指令的layer id。 111 112 ### 指令缓存 113 114 #### 概念介绍 115 116 * layer id : 根据每一层指令运行的产物,根据时间,文件内容,文件权限等计算出该层指令独一无二的ID。 117 * cache id : 根据context 中文件的内容,时间权限等计算出该层指令独一无二的ID,如没有命中,则会在该指令层,生成对应的cacheID文件,内容为cache id。 118 * cache layer: 包括cache id和layer value,layer type的新结构体。 119 * parent id : 不包括当前层之前的所有指令的chain id计算结果。 120 * chain id : 根据parent id 和cache layer计算得出,用与匹配文件系统已经缓存的集群镜像。 121 122 #### 缓存计算方式 123 124 默认的parent id 起始值为"",系统会在初始化时候,按照以下生成逻辑,遍历当前文件系统存在的所有集群镜像。格式为map,key 是当前层的chain id,value为当前层对应的cache layer. 125 126 Copy指令 chain id 生成举例 127 128 ```yaml 129 chain id = ChainID("parent id"+"cache id"+"COPY:recommended.yaml manifests") 130 ``` 131 132 非Copy指令 chain id 生成举例 133 134 非Copy指令没有cache id,则计算时候为""。 135 136 ```yaml 137 chain id = ChainID("parent id" +""+"CMD:kubectl apply -f etc/tigera-operator.yaml") 138 ``` 139 140 #### 缓存命中逻辑 141 142 1. 根据cache 标志位判断是否需要进行缓存。若是则走以下流程,若否则走常规计算流程。 143 2. 计算context 中文件的对应的cache id,并且和当前对应的parent id进行计算,得到当前指令层的chain id。 144 3. 根据 chain id 和系统中存在的所有缓存map,进行比较。 145 4. 若命中,返回当前的layer id ,cache 标志设置为true,并将当前parent id替换为最新的chain id。 146 5. 若没有命中,返回当前的layer id ,cache 标志设置为false,当前parent id不发生变化,并将该层对应的cache id 写入文件系统,用于下次缓存计算使用。 147 148 ### 接口定义 149 150 ```shell 151 Exec(ctx ExecContext) (out Out, err error) 152 ``` 153 154 参数解释 155 156 ExecContext 结构体 157 158 ```yaml 159 BuildContext: 构建的上下文。 160 BuildType: 构建的类型。 161 ContinueCache: 标志位,用于检测是否继续使用缓存,会在每一层layer执行的时候修改。 162 ParentID cache.ChainID: 缓存chain id,起始值为 ""。会在每一层layer执行的时候修改为包括当前layer的chain id。 163 CacheSvc cache.Service: 缓存layer生成接口,根据当前layer和cache id,生成对应的缓存layer。用于和ParentID一起,生成当前的chain id。 164 Prober image.Prober: 缓存探测接口,用于判断对应的chain id 是否和系统中存在的缓存map命中。 165 LayerStore store.LayerStore: 构建产物存储接口,会根据当前指令执行的结果,计算对应的layerid,并将产物复制到对应的文件系统路径中。 166 ``` 167 168 Out 结构体 169 170 ```yaml 171 LayerID digest.Digest: 当前指令执行的产物hash,独一无二,将会用于当前layer的存储。 172 ParentID cache.ChainID: 缓存chain id,与ExecContext 中ParentID一致,用于下一层指令的缓存判断。 173 ContinueCache bool: 标志位,用于判断下一层指令是否继续使用缓存。 174 ``` 175 176 ## Build layer层 177 178 该模块主要完成对layer层内容的解析以及对应的处理函数的初始化。 179 180 ### 功能介绍 181 182 #### 解析 imageList 183 184 使用方式 185 186 如果对应的Kubefile中有以下字段,则会触发解析 imageList功能。其中COPY的 src 名字为`imageList`,dest 为`manifests`。 187 188 ```shell 189 COPY imageList manifests 190 ``` 191 192 功能介绍 193 194 1. imageList 解析,将对应`imageList`中的内容逐行获取。 195 2. 镜像拉取,将解析到的对应docker镜像,使用docker client拉取到本地。 196 197 #### 解析helm charts 198 199 使用方式 200 201 如果对应的Kubefile中有以下字段,则会触发解析helm charts功能。其中COPY的 src 名字为charts 包,dest 为`charts`。 202 203 ```shell 204 COPY traefik charts 205 ``` 206 207 功能介绍 208 209 1. charts包 解析,将对应 charts 包 中的内容使用helm引擎获取docker 镜像列表。 210 2. 镜像拉取,将解析到的对应docker镜像,使用docker client拉取到本地。 211 212 #### 解析yaml 文件 213 214 使用方式 215 216 如果对应的Kubefile中有以下字段,则会触发解析yaml 文件缓存镜像功能。其中COPY的 src 名字为 yaml文件格式为"yaml"或者"yml",dest 为`manifests`。 217 218 ```shell 219 COPY recommended.yml manifests 220 ``` 221 222 功能介绍 223 224 1. yaml文件解析,读取对应yaml文件中的内容,解析`image`字段获取docker镜像列表。 225 2. 镜像拉取,将解析到的对应docker镜像,使用docker client拉取到本地。 226 227 ### 接口定义 228 229 ```shell 230 LayerValueHandler(buildContext string, layer v1.Layer) error 231 ``` 232 233 参数解释 234 235 ```yaml 236 buildContext: 用于构建集群镜像的上下文,默认为当前目录。 237 layer: 构建阶段,对应的集群镜像层的内容,包括layer value,layer type。 238 error: 当执行构建时候,如有发生错误,则会返回该错误。 239 ``` 240 241 ### docker镜像缓存 242 如果使用的是sealer定制的docker,则docker镜像缓存到私有仓库只需要一步:从官方仓库pull镜像。因为sealer把私有仓库设置为代理,所有镜像都会先pull到私有仓库,然后才会再从私有仓库pull到本地。 243 244 如果使用的是原生的docker,则docker镜像缓存到私有仓库需要两步:首先,从官方仓库pull镜像。然后,将pull到本地的镜像再push到私有仓库中。 245 246 在每一个镜像的拉取操作之前加入一个判断docker引擎版本的步骤来进行区分。具体实现方式是:调用docker的sdk函数,得到docker引擎的版本信息,若docker引擎的版本中包含`sealer`字符串,则标示是sealer定制的docker,只进行pull操作。若docker引擎的版本中,不包含`sealer`字符串,则pull和push操作都会执行。