原创 关于在容器中构建镜像

发布时间:2021-08-02 22:13:50 浏览 97 来源:猿笔记 作者:seymour

    工作中遇到了构建镜像相关的内容,他的原理是通过一系列的声明式指令集来生成文件系统和镜像的元数据,通过*dockerbuild*命令来构建镜像需要docker引擎的api,在我们的业务场景中需要在*kubernetes*环境中制作镜像,如果业务中只是需要构建镜像,就必须要求构建镜像的宿主机具有*dockerdaemon*。而且在我们的业务中也遇到了需要在流程中构建镜像。我们不得不将*dockerdaemon*的socket安装到业务流程的构建容器中,因为这实际上赋予构建容器访问*Kubernetes*节点的root权限。


    theme:fancy

    highlight:github.css

    在工作中,我遇到了镜像构建的相关内容,整理了其中涉及的知识点。

    # #构建容器图像

    众所周知,容器图像可以通过dockerfile快速构建。他的原理是通过一系列声明性指令集生成文件系统和映像的元数据。*dockerbuild*命令需要docker引擎的api,其底层由* dockerdaemon *支持。在我们的业务场景中,我们需要在*kubernetes*环境中制作图像,因此它不同于通常在主机上构建图像时遇到的问题。这里我们稍后将讨论如何在*kubernetes*环境中制作图像。

    *dockerbuild*只是dockerdaemon提供的众多功能之一,使用这个功能需要主机的root权限,这就涉及到安全风险和权限问题。如果业务中只需要构建镜像,那么必须要求镜像的主机必须有* dockerdaemon *,构建的触发器也必须有主机的根权限,这是多余的,也不优雅,在优秀的*CI/CD*流程中也不是必须的。我们只需要* dockerdaemon *的一个小特性,仅此而已。

    此外,在我们的业务中,我们还会遇到在流程中构建图像的需求。为了让*Dockerbuild*在Kubernetes节点中运行,我们必须把* dockerdaemon *的socket安装到业务流程的building容器中,这样就可以用于building了。

    `dockerrun-it-v/var/run/docker.sock:/var/run/docker.sock-v/tmp/kaniko:/tmp/kanikodocker`

    从安全性的角度来看,这是不合适的,因为它实际上给了构建容器对*Kubernetes*节点的根访问权。另一个解决方案是避免在节点上运行DockerDaemon,而是使用* dockerdocker *(DinD在容器中运行容器)来提供一个独立的映像构建环境。但是,存在安全风险,因为运行DinD的容器需要有特权。而且这种方式还有其他问题,比如使用* DockerinDocker *,每一项施工工作都是在干净的环境下进行的,没有历史的痕迹。并发作业工作正常,因为每个构建都有自己的Docker引擎实例,所以它们不会相互冲突。但是,这也意味着作业将会变慢,因为没有层缓存。还有一个由网络重叠引起的docker版本问题。在下面,我们将提到解决这个问题的两种方法。

    方法1:一种新的构造镜子的方法:波德曼

    Podman来自工作流中消除* dockerdaemon *的需求。Podman模拟dockerbuild的所有构造语句,使用unix的经典fork和exec模式执行构造,实现真正意义上的多进程构造,非常优雅。此外,podman还为oci兼容的实现提供构建功能。另外,podman是在没有root权限的情况下构建的,底层原理是podman使用隔离的用户命名空间。这个独立的名称空间将默认名称空间中一系列非特权用户和组的标识映射到新创建的名称空间中一组用户和组的标识。此时,映射到新容器的用户和组的标识都是0,这为新容器提供了所需的权限。由于隶属关系,新容器中的权限只是原始映射用户的文件访问权限。

    # #方法2:在容器中构建图像kaniko

    Kaniko是谷歌推荐的在容器中构建图像的解决方案,也是我们在生产中使用的解决方案。Kaniko并不依赖* dockerdamon *进程,而是根据用户空间中Dockerfile的内容逐行执行命令来构建映像,使得在一些无法获得* dockerdamon *进程的环境下构建映像成为可能,比如标准的* Kubernetescuster *。

    Kaniko作为容器映像运行,需要三个参数:Dockerfile、上下文和远程映像仓库的地址。从下面的语句中可以看出,输入参数中有dockerfile、context和destination

    `cmd=exec.Command("/kaniko/executor",dockerfile,buildContext,destination,"--insecure-pull","--skip-tls-verify")`

    Kaniko会先提取基本镜像的文件系统(DockerfileFROM之后的镜像),然后按照Dockerfile中的描述逐一执行命令。每个命令执行后,它将在用户空间下创建一个快照,并将其与存储在内存中的先前状态进行比较。如果有变化,会新建一个图像图层添加到基础图像中,并将相关修改信息写入图像元数据中。所有命令执行完毕后,kaniko会将最终图像推送到指定的远程图像存储库。

    详细的使用方法:[Kaniko](

    ##dockerfile的构建顺序和缓存

    因为*dockerfile*的构造是顺序的,指令是按顺序执行的。Dockerfile最终构建的图像是一层一层叠加在基础图像上的,所以在这个过程中会产生一个

作者信息

seymour [等级:3] 程序员
发布了 44 篇专栏 · 获得点赞 252 · 获得阅读 24290

相关推荐 更多