大家都喜欢Alpine的镜像,因为它们很轻,攻击面较小,但也许它们不再是最佳选择。现在又到了谈论distroless版镜像的时候了。
在 SumUp我们经常使用Kubernetes和Docker镜像,所以我们一直在寻找基础镜像的最佳选择。distroless镜像并不是什么新东西,但由于某些原因,我觉得它们并没有得到应有的采纳。
什么是distroless图像?
我不得不说这不是什么新东西,我是说真的。它已经存在很多年了,你可以在以下内容中查看 GoogleContainerTools/distroless:
"distroless无发行版 "只包含你的应用程序和它的运行时依赖。它们不包含软件包管理器、外壳或任何其他你期望在标准Linux发行版中找到的程序。
这足以理解你的容器不会有任何东西,但你正在使用的东西。
我为什么要使用它们?
现在每个人都有一个CI和CD管道,但有时需要花费很长时间来构建、推送和拉动镜像。无发行版的镜像更轻,这意味着拉动和推送更快。
distroless镜像不一定会让你的构建步骤更快,但它们会改善拉取和推送的时间。Docker提供了一个最小当你使用它作为镜像的基础时,它不会创建额外的层。更少的层等于更快的下载和上传。
更快的管道意味着对开发人员的反馈更快,花费的CI时间更少,这在你使用像.NET这样的工具时非常重要。
安全也是一个重要的问题,因为你应该尽可能地减少你的攻击面。如果你不打算使用像sudo或ping这样的工具,你就不应该在你的容器中设置这些工具。
如果你的代码有漏洞,你就不太容易受到导致shell的RCE的影响,但RCE仍然在发生。
- 埃里克-杜兰
应始终避免使用帮助恶意行为者收集更多信息或执行特权升级的工具。你应该看一下 erickduran/docker-distroless-pocREADME。
不应该使用distroless的场景
说什么时候使用distroless很容易,但什么时候不应该使用它们?
如果你想在容器内调试你的应用程序,你可以从shell和其他一些安装的工具中获益,但distroless没有这些工具。显而易见的答案是使用正常的镜像进行开发,而将无发行版保留给生产。
在开发中使用不同的图像使开发人员远离真实的生产环境,这并不理想,但在你的CI管道中创建测试步骤,使用与生产中相同的环境,应该可以解决这个问题。对这种权衡要小心。
那就举个例子吧?
储存库 GoogleContainerTools/distroless有一个关于如何为Golang工具制作无发行版distroless镜像的例子。
这是一个简单易行的例子,主要是因为Golang产生的二进制文件默认没有运行时的依赖性。
相反,让我们假设我们需要创建一个distroless的镜像来使用ping二进制,因为我们将在我们的一个服务中使用它来检查一个主机是否正常。这意味着我们需要找到所有的运行时依赖项,但我将尽可能地保持简单。
我在Ubuntu中运行了ldd命令,它向我们显示了它的依赖性,所以我开发了以下Dockerfile。另外,请注意,并不是每个运行时的依赖都在ldd命令的输出中,我不得不使用其他方法来发现它们。
然而,这并不是最聪明的解决方案。上面的Docker文件创建了一个5.44MB的镜像,我们可以通过使用Alpine而不是Ubuntu来改进它。如果你在Alpine环境中运行同样的ldd命令,你也会有更少更轻的依赖性。
它运行良好,只用了1.43MB,比Alpine图像和我们在第一阶段使用Ubuntu建立的镜像少了约74%的空间。
总结
标题说你应该停止使用Alpine,但我想我向你表明,这只是在正确场合做正确选择的问题。另外,alpine和 scratch将创造出令人惊奇的distroless。
问题是,为你的应用程序建立distroless仍然是相当手动的,并不像你希望的那样有趣。由于它需要开发人员付出更大的努力,所以通常被抛在后面,而支持著名的Alpine镜像。
我认为我们的想法是在生产环境中以及在进行手动和自动测试时使用distroless。你不想让开发人员在调试应用程序时承受更大的压力。
我希望社区给予distroless应有的关注,这将导致更多的改进,比如尽可能地自动创建镜像。