在容器中运行Buildah的最佳实践

将容器的运行时分为单独的工具组件有什么好处? 特别是这些工具可以开始组合起来以相互保护的事实。



Kubernetes或类似系统中构建容器OCI的想法吸引了许多人。 假设我们有一个不断收集图像的CI / CD,那么像Red Hat OpenShift / Kubernetes这样的东西在组装过程中的负载平衡方面将非常有用。 直到最近,大多数人还是只允许容器访问Docker套接字,并允许执行docker build命令。 几年前我们表明这是非常不安全的,实际上,这比提供无密码的root或sudo还要糟糕。

因此,人们一直在尝试在容器中运行Buildah。 简而言之,我们创建了一个示例 ,说明了如何最好在容器内运行Buildah并将适当的映像放在quay.io/buildah上 。 让我们开始吧...

客制化


这些映像是从Dockerfiles编译的,可以在buildahimage文件夹中的Buildah存储库中找到
这里我们来看Dockerfile稳定版本

# stable/Dockerfile # # Build a Buildah container image from the latest # stable version of Buildah on the Fedoras Updates System. # https://bodhi.fedoraproject.org/updates/?search=buildah # This image can be used to create a secured container # that runs safely with privileges within the container. # FROM fedora:latest # Don't include container-selinux and remove # directories used by dnf that are just taking # up space. RUN yum -y install buildah fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.* # Adjust storage.conf to enable Fuse storage. RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf 

而不是在主机的Linux内核级别上实现的OverlayFS,我们使用容器内的保险丝叠加程序,因为目前OverlayFS仅在Linux功能授予SYS_ADMIN特权时才能挂载。 我们希望在没有任何root特权的情况下运行Buildah容器。 保险丝覆盖比VFS存储驱动程序快得多,并且性能更好。 请注意,使用Fuse启动Buildah容器时,必须提供设备/ dev / fuse。

 podman run --device /dev/fuse quay.io/buildahctr ... RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock 

接下来,我们创建一个目录用于其他存储。 容器/存储支持连接其他只读图像存储的概念。 例如,您可以在一台计算机上配置覆盖存储区域,然后使用NFS将此存储安装在另一台计算机上并使用其中的映像,而无需通过拉动下载。 我们需要此存储,以便能够将主机上的某种图像存储作为卷连接并在容器内使用。

 # Set up environment variables to note that this is # not starting with user namespace and default to # isolate the filesystem with chroot. ENV _BUILDAH_STARTED_IN_USERNS="" BUILDAH_ISOLATION=chroot 

最后,使用BUILDAH_ISOLATION环境变量,我们说默认情况下,Buildah容器应以chroot隔离开头。 由于我们已经在容器中工作,因此此处不需要其他隔离。 为了使Buildah使用分隔的名称空间创建自己的容器,需要SYS_ADMIN特权,为此,有必要削弱该容器的SELinux和SECCOMP规则,这与我们从安全容器中进行构建的安装相矛盾。

在容器内运行Buildah


上面讨论的Buildah容器映像模式允许您灵活地更改运行此类容器的方式。

速度与安全


计算机安全始终是进程速度和对其进行保护的过程之间的折衷方案。 组装容器时,该语句也是如此,因此下面我们将考虑针对这种折衷方案。

上面讨论的容器映像将其存储库保存在/ var / lib /容器中。 因此,我们需要在此文件夹中装入内容,并且这样做的方式将极大地影响容器映像的组装速度。

让我们考虑三个选项。

选项1.如果需要最大的安全性,则可以为每个容器创建自己的容器/图像文件夹,然后通过volume-mount将其连接到容器。 此外,将上下文目录放置在容器本身的/ build文件夹中:

 # mkdir /var/lib/containers1 # podman run -v ./build:/build:z -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable\ buildah -t image1 bud /build # podman run -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable buildah push \ image1 registry.company.com/myuser # rm -rf /var/lib/containers1 

安全性 在这样的容器中运行的Buildah具有最高的安全性:功能工具没有赋予它任何root特权,并且所有SECOMP和SELinux限制都适用于该容器,甚至可以在用户命名空间隔离的情况下运行该容器,并添加--uidmap 0:100000:10000之类的选项。

性能。 但是这里的性能是最低的,因为每次都会将来自容器注册表的任何图像复制到主机,并且从“没有办法”这个词进行缓存是行不通的。 完成工作后,Buildah容器应将映像发送到注册表并销毁主机上的内容。 下次收集容器映像时,将不得不再次从注册表中下载它,因为到那时主机上将不再保留任何内容。

选项2。如果需要Docker级的性能,可以将主机的容器/存储直接安装到容器中。

 # podman run -v ./build:/build:z -v /var/lib/containers:/var/lib/containers --security-opt label:disabled quay.io/buildah/stable buildah -t image2 bud /build # podman run -v /var/lib/containers:/var/lib/containers --security-opt label:disabled \ quay.io/buildah/stable buildah push image2 registry.company.com/myuser 

安全性 这是构建容器的最不安全的方法,因为此处允许容器修改主机上的存储,并且可能会将其潜入Podman或CRI-O中,成为恶意映像。 另外,您将需要禁用SELinux分离,以便Buildah容器中的进程可以与主机上的存储进行交互。 请注意,此选项仍然比Docker套接字更好,因为该容器被其余的安全功能阻止,并且不能仅在主机上启动并运行任何容器。

性能。 这是最大值,因为完全涉及缓存。 如果Podman或CRI-O已设法将所需的映像下载到主机,则容器内的Buildah进程将不必再次下载它,并且基于该映像的后续程序集也将能够从缓存中获取必需的映像。

选项3。此方法的本质是将一个项目中的多个图像与一个用于容器图像的共享文件夹合并。

 # mkdir /var/lib/project3 # podman run --security-opt label:level=s0:C100, C200 -v ./build:/build:z \ -v /var/lib/project3:/var/lib/containers:Z quay.io/buildah/stable buildah -t image3 bud /build # podman run --security-opt label:level=s0:C100, C200 \ -v /var/lib/project3:/var/lib/containers quay.io/buildah/stable buildah push image3 \ registry.company.com/myuser 

在此示例中,我们不会在启动之间删除项目文件夹(/ var / lib / project3),因此项目内的所有后续构建都利用了缓存。

安全性 介于选项1和2之间。一方面,容器无法访问主机上的内容,因此,不能将不良内容滑入Podman / CRI-O图像存储中。 另一方面,作为其项目的一部分,一个容器可能会干扰其他容器的组装。

性能。 这比在主机级别使用共享缓存更糟,因为您不能使用以前使用Podman / CRI-O已经下载的图像。 但是,在Buildah下载映像之后,可以在项目内的任何后续构建中使用该映像。

额外的存储空间


容器/存储具有诸如附加存储之类的酷功能,这是由于容器引擎可以在启动和构建容器时以只读覆盖模式使用外部图像存储。 实际上,您可以将一个或多个只读存储添加到storage.conf文件,以便在容器启动时,容器引擎在其中查找所需的映像。 而且,仅当他在任何这些存储库中都找不到映像时,他才会从注册表中下载映像。 容器引擎将只能写入可写存储...

如果您向上滚动并查看我们用来构建镜像quay.io/buildah/stable的Dockerfile,则有以下几行:

 # Adjust storage.conf to enable Fuse storage. RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock 

在第一行中,我们修改容器映像中的/etc/containers/storage.conf,告诉存储驱动程序在/ var / lib / shared文件夹中使用“ additionalimagestores”。 在下一行中,创建一个共享文件夹并添加几个锁定文件,以免容器/存储设备受到滥用。 基本上,我们只是创建一个空的容器映像存储。

如果在此文件夹上方安装容器/存储,Buildah将能够使用映像。

现在回到上面讨论的选项2,当Buildah容器可以在主机上对容器/存储进行读写操作时,由于Podman / CRI-O级别的图像缓存而具有最佳性能,但是由于它可以直接写入,因此安全性最低。在存储中。 现在,我们将在这里固定更多的存储,以充分利用两个世界的优势。

 # mkdir /var/lib/containers4 # podman run -v ./build:/build:z -v /var/lib/containers/storage:/var/lib/shared:ro -v \ /var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable \ buildah -t image4 bud /build # podman run -v /var/lib/containers/storage:/var/lib/shared:ro \ -v >/var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable buildah push image4 \ registry.company.com/myuser # rm -rf /var/lib/continers4 

请注意,/ var / lib / containers /存储主机以只读模式安装在容器内的/ var / lib / shared中。 因此,在容器中工作时,Buildah可以使用以前使用Podman / CRI-O(高速)下载的任何图像,但只能写入其自己的存储(高速)。 还要注意,这样做是在不禁用容器的SELinux分离的情况下完成的。

重要细微差别


在任何情况下都不应从基础存储中删除任何图像。 否则,Buildah容器可能会飞出。

这还不是全部好处。


其他存储功能不限于上述情况。 例如,您可以将所有容器映像放置在共享的网络存储中,并授予对所有Buildah容器的访问权限。 假设我们有数百个CI / CD系统经常用来构建容器映像的映像。 我们将所有这些映像集中在一个存储主机上,然后使用首选的网络存储工具(NFS,Gluster,Ceph,ISCSI,S3 ...)为所有Buildah或Kubernetes节点打开共享存储。

现在,足以将该网络存储安装到/ var / lib / shared上的Buildah容器中,而这一切-Buildah容器不再需要通过pull下载图像。 因此,我们放弃了预填充阶段,并立即准备推出容器。

当然,可以在现有的Kubernetes系统或容器基础结构中使用它来在任何地方启动和执行容器,而无需通过拉动下载映像。 此外,容器注册表接收到推送请求以将更新的映像加载到其中,可以自动将该映像发送到共享的网络存储,在该网络中,该映像立即可用于所有节点。

容器映像的大小有时可以达到数GB。 附加存储的功能使您无需按节点克隆此类映像即可完成操作,几乎可以立即启动容器。

此外,我们目前正在开发新的叠加体积安装功能,它将使容器组装更快。

结论


在Kubernetes / CRI-O,Podman甚至Docker中的容器内运行Buildah是真实的,并且比使用docker.socket更简单,更安全。 我们极大地提高了使用图像的灵活性,现在您可以通过各种方式启动它们,以在安全性和性能之间实现最佳平衡。

附加存储的功能使您可以加快甚至完全消除将映像下载到节点的过程。

Source: https://habr.com/ru/post/zh-CN470928/


All Articles