为了实现一致性、可预测性和可靠性,不变性非常棒,当我在来自世界各地不同云提供商的 Linux VPS 上部署我的应用程序时,我认为没有理由不努力实现操作系统级别的不变性。使用 Packer 等工具来帮助创建操作系统映像,这似乎也是可行的方法。
对于某些云提供商(例如 Digital Ocean),我可以在本地以 qcow2 或 raw 格式构建映像,然后在实例化新的 VPS 时将完成的映像上传到云提供商进行部署。这似乎是最好的选择。
但是其他云提供商(例如德国的 Hetzner)不支持导入您自己的操作系统映像 - 相反,您必须基于他们的源映像之一在其基础架构上构建映像,然后当所有配置正确时,您可以将最终安装快照为可重复使用的映像。事实上,这也是 Packer 的“Hetzner Cloud Builder”所做的。
但是我如何保证最终的 Hetzner 图像具有精确的是否与所有其他云提供商上运行的 CentOS 8 安装相同(直到安装的 RPM 包完全相同,版本号也完全相同)?
我认为解决方案可能是某种声明性工具,它获取 RPM 包和相关版本号列表,并使目标系统与该列表保持一致 - 确保以正确的版本安装任何缺失的 RPM 包,删除多余的 RPM 包,升级较旧的 RPM 包并降级较新的 RPM 包以确保安装所需的版本。
是否存在这样的工具,或者我应该对此完全不同的看法?
有些人可能会争辩说,CentOS RPM 软件包应该始终升级到最新可用版本,但我无法保证所有云提供商都运行相同的操作系统安装 - 这可能会影响我的服务的可预测性和可靠性。
相反,我希望能够在将完整设置(操作系统 + 应用程序)部署到任何云提供商之前对其进行彻底测试,然后部署在所有云提供商之间应相同。这就是我们在应用程序级别使用 Docker 镜像的方式,我不明白为什么我们应该在操作系统级别接受更少的要求。
您的 DevSecOps 同事对于如何实现这些目标有何建议?
答案1
无需基于镜像的更新或不可变主机来设置对安装哪些软件的控制。在
公共镜像的自动更新软件包和不可变镜像的极端之间存在选项。
使用单独软件包的发行版(例如使用 rpm 的 CentOS)可以维护您自己的更新存储库。仅限于您使用的软件包。定期(例如每 4 周)将更新提取到测试存储库中。测试这组冻结的软件包一段时间,然后移至您的稳定存储库。配置所有主机以自动从您的镜像更新,可能按计划进行。当自动化安装软件包作为部署事物的一部分时,其版本是已知的,因为它来自您的镜像。但是,单个主机在应用软件包事务时可能会遇到问题,并且会过时。考虑查询队列中的每个主机以获取特别重要的软件包的版本,可能是某些安全更新。
将操作系统安装克隆为另一个实例非常简单。但是,基于软件包的发行版的映像并非真正不可改变,软件包管理器在实例中仍然可用,特权用户仍然可以更改 /usr 树中的内容。
考虑一个基于镜像更新的发行版,例如核心操作系统。更新必须分层到映像中,然后重新启动才能生效。自定义仅限于少量元数据。CoreOS 尤其仅用于托管容器,但这可能是您的用例。具有可复制的优势,Fedora CoreOS 34.20210904.3.0 是一套定义良好的软件。
不提供上传镜像方式的计算主机可以另行解决。启动具有网络访问权限的救援环境,然后将图像直接下载到磁盘上. 快照以制作模板。
现在可能是出于其他原因评估您选择的发行版的好时机。 CentOS Linux 8 将于 2021 年 12 月结束。 CentOS Stream 是替代品,但它是 RHEL 的上游而不是下游。
答案2
事实上,一旦您在 Hetzner 中创建了 VM,您就可以将其启动到所选择的 LiveCD,其中有 CloneZilla 或 SystemRescue 之类的程序,您可以使用它们来转储/恢复您的映像。
我实际上发现 CloneZilla 映像在不同的云 VPS 提供商之间更具可移植性。
答案3
但是,我如何保证最终的 Hetzner 映像具有与所有其他云提供商上运行的完全相同的 CentOS 8 安装(直到安装的 RPM 包集完全相同,版本号也完全相同)?
如果我正确理解了你想要什么,我会去使用任何“基础设施测试”工具,例如检测它可以让您描述您想要在目标映像/VM 中拥有的内容。
我们用它来验证我们的saltstack/saltproject代码使用它与厨房这样(我们在 CI 工具的作业中运行它)
create
带有 Kitchen 的 N 个虚拟机(可以与 Docker、Vagrant 以及云提供商一起使用)provision
每台机器都有自己的配置文件,包括 Salt、Ansible、Chef、Puppet 或其他verify
使用 Inspec 生成的机器状态
Inspec 让您可以创建某种“单元测试”,但针对基础设施/系统:您可以轻松验证用户和群组是否存在、安装的软件包及其版本、正在运行的服务、TCP/UDP 端口、防火墙规则……
(我也使用 Packer 来创建图像,但目前我不在这种情况下使用 Inspec:我们认为用于创建此图像的代码已经通过了之前的 CI 作业的测试)
因此,回到你的问题:我会在你的 Packer 设置中添加一个 Inspec 验证步骤。此外,它似乎已经作为配置程序集成到 Packer 中https://www.packer.io/docs/provisioners/inspec (我刚刚发现)