利用Kaniko构建容器镜像

本期我们来聊一聊一个名叫Kaniko的开源项目。
Kaniko项目最初于2018年由谷歌提出。Kaniko的创建之初是寻求在执行容器镜像构建时消除对特权账户的依赖。如果您一直关注本系列文章,那么现在您将已经知道,无特权的容器镜像构建是注重安全性的公司最需要的功能之一。这与在Kubernetes集群中构建容器镜像类似。
Kaniko是如何工作的?

方法
kaniko使用您熟悉的方式用来构建容器镜像;包含构建指令和构建上下文的Dockerfile,其中包含Dockerfile和镜像所需的任何其元素。
但是,与原生的Docker客户端构建命令不同,它执行构建步骤时不需要Docker守护程序
Kaniko使用自己的“executor”执行构建步骤,该构建步骤在容器(可能是Kubernetes pod)中运行。当然,需要使构建上下文对容器或pod可用,使得它能在构建中被使用。因为构建步骤是在容器内执行的,所以仍然最终依赖Docker守护程序或其他容器运行时,但重要的区别是构建步骤本身是由执行程序代码执行的。
“executor”遍历Dockerfile中定义的每个构建步骤。它拉取为构建阶段准备的源镜像,并解压缩其rootfs。然后,它按顺序执行每个Dockerfile指令,并随其添加或更改rootfs的内容。如果对rootfs进行了更改,则“executor”对文件系统做快照化,更改“ diff”层,并在必要时更新镜像元数据。通过将文件系统的先前状态与Dockerfile指令执行后的状态进行比较,可以实现快照。除了操作完全在用户空间中执行之外,这与overlayfs之类的copy-on-write文件系统的行为并无不同。构建步骤完成后,将diff层依次添加到基础镜像中以形成新镜像。
你可能会问“最后怎样处理镜像?镜像会不会随着容器或Pod消失”
“executor”一定希望镜像制作命令中可以指定镜像仓库的名字,这样新的镜像就可以被推送到镜像仓库,从而完成镜像制作的全过程。
下面的一段YAML文件定义了运行在Kaniko“executor”的pod:

spec:

containers:

- name: executor

image: gcr.io/kaniko-project/executor:latest

args: [

  "--context",

  "git://github.com/mycorp/my-app.git",

  "--destination",

  "quay.io/mycorp/my-app:1d03df1",

        ]

构建上下文
在定义构建上下文源时,Kaniko非常灵活。卷挂载可用于指定包含上下文的本地目录(到容器),并且上面的示例着重说明了如何使用git存储库作为源。
联想到Kaniko的出身,如果云存储不能被Kaniko用作构建上下文的来源是令人难以置信的。毫无疑问,Kaniko支持使用由三个主要公有云服务商提供的对象存储解决方案。

构建缓存
容器镜像构建的一个极其重要的部分是能够利用之前镜像构建过程中的调用步骤,该调用通常因此目的而被缓存。如果构建步骤将产生相同的输出,则构建器将使用缓存的内容,而不是重新执行构建步骤。
Kaniko提供了两种缓存功能来增强镜像构建:
1. 源镜像可以下载到本地卷中共享,“executor”容器在调用时即可使用。这样可以避免“executor”容器在每次调用时都提取相同的源镜像,从而节省了构建时间。为此,Kaniko提供了“暖心”的功能。您只需要将需要缓存的镜像和其他相关镜像存放在指定的本地目录即可。

  1. 在镜像构建期间创建的中间镜像层也是构建缓存的关键要素。Kaniko启用了在执行RUN Dockerfile指令期间创建镜像的缓存,但是这些镜像存储在远程镜像仓库。在“executor”处理RUN指令之前,指定的镜像仓库会检查对应层。如果找到,则将其从镜像仓库中提取,而不是从正在执行的指令中提取。

安全
由于Kaniko避免使用Docker守护进程的build API端点来执行构建步骤,因此在安全性方面有很大帮助。可执行程序可以作为非特权容器运行,不需要将Docker守护进程套接字安装到该容器中。这是在Kubernetes上的Pod中安全运行容器映像构建过程中的重要一步。
不利之处在于,构建步骤可能需要以root(uid = 0)用户身份执行。一般而言,容器应以非root用户身份运行-容器中的root就是主机上的root。如果基本镜像的rootfs组件被root用户拥有,或者需要以root特权执行命令,那么Kaniko毫无办法。
以root用户身份运行执行程序容器这类问题可以有扑救措施。通过提供额外的隔离措施,可以保护运行“executor”序容器的主机。 Google自己的gVisor就是这种隔离的一个很好的例子,Kata Containers运行时也是如此。

结论
Kaniko是镜像构建器工具的新工具之一,其目的是消除对Docker守护程序的长期依赖。它很好地做到了这一点,并在Kubernetes集群中提供了可靠的容器镜像构建体验。这样就可以避免通常用Docker守护程序进行构建相关的安全隐患。因此,Kaniko是一种主流的镜像构建工具,它的常规功能也作为Tekton Pipelines的后端构建任务。
但广受欢迎的Kaniko并没有完全实现无根容器镜像构建,而且还延续了基于Dockerfile的构建的顺序性。

原文链接: Container Image Building with Kaniko
(翻译:吴世曦)