全球范围内,应用程序正在向本地迁移。企业希望对自己的数据有更多控制权,并且已经厌倦了为从公有云获取其自身数据而支付出站费用。除了成本之外,当资源与未知组织共享时,还有安全问题,或者说缺乏安全。由于所有内容都是共享的,因此漏洞可能会蔓延并影响您的系统。
随着平均企业运行在 4 个云(包括本地私有云)上,标准化配置、编写脚本和尽可能地自动化变得至关重要。这将减轻数据管理负担,同时仍让每个人都能访问所需的数据。
虽然企业将事物迁移到本地,但它们正在重新评估云支出,重点关注数据重力——云不是一个地方,而是一种运行模式——软件、工具和 Kubernetes 使得构建自己的云成为可能。他们使用最佳应用和云服务构建数据湖、AI/ML 和分析解决方案,然后使用 MinIO 复制数据到所需位置。但他们如何跨云保持一致性呢?
配置管理系统应运而生。这些工具例如 Chef、Puppet、Salt、Ansible 和 Terraform,通过减少技术债务并简化持续管理和扩展的要求,使 DevOps 团队成员的生活更轻松。这些工具不会手动执行每个操作,而是以幂等的方式(即以相同的方式和同时地)在数千台服务器上执行相同的操作。
在本博文中,我们将重点介绍 Puppet 和 Salt,因为它们是最流行的基于拉取的配置管理系统——每个系统都依赖于始终在节点上运行的代理,作为守护进程或 cron 作业。然后,该代理从远程位置(例如主服务器)“拉取”配置和设置。维护一组经过批准的中央配置意味着所有代理都执行一致的本地操作。
主-代理与无主无头架构
让我们谈谈如何扩展后端系统以支持前端系统。在这种情况下,让我们具体谈谈配置管理系统。这些系统通过确保配置在 10 台或 1,000 台服务器上保持一致的方式工作,以幂等的方式,这意味着无论在节点上运行配置多少次,最终结果都应该相同。如果结果不相同,系统的幂等性将确保系统恢复到其期望状态。简而言之,这就是这些配置管理系统的工作原理。它们通常具有声明性——您不必编写控制逻辑,只需说明任务的期望结果即可。这是因为在构建基础设施组件时,存在如此多不同的活动部件,以至于很难想到所有需要自己编写的逻辑。
当您只有少数服务器(例如大约 10 个代理和 1 个主服务器)时,每个服务器的配置运行速度相当快,没有必要使系统比必要的更复杂。但是,当您有超过 1,000 个节点需要配置时该怎么办?我自己在过去管理超过 8,000 台服务器的经验中,只有一个主服务器是不够的,因为系统根本无法以可扩展的性能运行。我们找到的解决方案是使用 5-6 个主服务器支持配置管理系统,并随着前端系统数量的增加而扩展到更多主服务器。现在,这是一个复杂的配置管理系统,随着时间的推移,它只会变得更加复杂。
为了像我们那样扩展(如果您也这么做,请不要感到沮丧,因为每个人都这么做),我们需要解决系统的网络方面。 使用多个主服务器,您还需要配置负载均衡器或反向代理(如 Nginx)才能将负载分配到主服务器之间,因为通常您只能配置一个主服务器进行通信。好吧,为什么不使用轮询(RR)DNS 呢?虽然这在表面上似乎是一个可接受的解决方案,但 RR DNS 会根据每个请求将请求随机发送到不同的服务器。因此,如果您有多个请求,它们将被定向到不同的主服务器,如果并非所有主服务器都已同步,则节点将应用旧配置和新配置,这非常难以调试。由于 RR DNS 的这种不可预测性,我们不建议将其用于有状态应用程序。
假设您已经扩展了您的环境,您将如何维护高可用性? 当负载均衡器出现故障或需要维护时会发生什么?因此,您需要一种方法将负载分配到多个负载均衡器之间,现在您已经遇到了扩展的硬性限制,因为配置和维护这个死胡同比它值得的还要痛苦。
如果我们去掉整个主服务器-负载均衡器流程并简化我们的架构,难道不会很酷吗?我们可以用更简单的东西替换整个后端,但要求不产生额外的技术债务吗?
是的,我们可以。答案是每个人都喜欢的软件定义的对象存储,MinIO。组织已经在其生态系统中使用 MinIO 作为关键的基础设施工具,用于各种目的,例如数据管道、开发人员代码和工件的存储、对象存储、ElasticSearch 索引、日志文件,甚至用于 Snowflake 的外部 SQL 表——使用范围确实无处不在。同样,MinIO 能否帮助我们克服扩展配置管理系统的障碍?
是的。在这些基于拉取的配置系统中,通常还有另一种方法称为无主无头配置。在所有这些实例上仍然运行着一个代理,但没有主服务器。相反,所有需要应用于节点的文件和配置都存储在应用配置的节点的本地。通过将其设置为无头模式,MinIO 充当所有需要应用于系统的工件和配置的中央存储。MinIO 的优势在于,即使您是第一次为了这个特定目的而设置它,您也会立即从我们构建到其中的所有性能、持久性和可扩展性中受益。
MinIO 安全、加密和复制
作为一名 DevOps 工程师,我有机会管理数千台服务器,而且这些服务器在任何时候都处于运行状态。我学到的一件事是,随着面向用户的系统的发展,您需要扩展支持这些前端系统的后端系统。但是,正如您将在本文后面看到的那样,扩展配置管理不像其他管理功能那样简单。
如今的配置管理工具无法扩展,因为它们之间的通信效率太低。代理之间存在太多身份验证、重新身份验证和重新连接,主服务器上的资源(如 CPU 和驱动器空间)太少——所有这些都会导致代理速度变慢。更具体地说,存储配置数据、秘密、非敏感数据和其他文件的系统需要速度快。虽然这些文件不一定很大,但它们经常从数千个节点并发访问,这些节点试图以惊人的速度拉取这些小文件。对于这些类型的操作,简单的单一 HDD 和普通文件系统是不够的,并且随着越来越多的节点尝试拉取数据,它将崩溃。此外,您可能需要根据管理的代理数量以及您需要存储数据的时长来增加磁盘大小。例如,如果您拥有一个高吞吐量系统,并且您的系统处于高度监管的行业中,需要 7-8 年的数据保留期限,那么这可能需要更大的磁盘大小和存储容量。为了解决这些问题,DevOps 团队会做一些非常了不起的事情,例如从头开始构建所有内容,并将它们拼凑在一起,以扩展他们的后端系统。如果我们可以用更具弹性和可扩展性的东西替换这些配置管理系统的后端,难道不会很酷吗?特别是当这个新的后端的技术债务很低,以至于我们甚至不必考虑它的时候?
MinIO 是这里完美的解决方案,因为我们正在通过双管齐下的方法来实现这一点。首先,MinIO 通过其内置的 站点到站点复制 架构消除了对复杂 Agent-MultiMaster-MultiLoadBalancers 系统的需要,该架构易于配置和扩展,不仅在同一区域内,而且跨多个位置。其次,MinIO 从一开始就秉承性能、速度和简洁的设计理念——这是我们的信条。我们 建议 用户和客户使用纯 JBOD 模式下的商品硬件,以确保底层基础设施尽可能简单和高效。MinIO 是高性能和可扩展性的完美结合,这使得每个数据密集型工作负载都触手可及。MinIO 能够提供惊人的性能——最近的基准测试 显示,仅使用 32 个现成的 NVMe SSD 节点,GET 的速度即可达到 325 GiB/s(349 GB/s),PUT 的速度可达到 165 GiB/s(177 GB/s)。
让我们看看如何实现这一点。
我们将建立一个地理分布式基础设施,在全球三个不同的站点部署一个多节点多驱动器的 MinIO 集群。这将使我们能够了解复制在规模化时的工作原理,并提供对地理负载均衡和高可用性所需基础设施的见解。
自从我们引入 多站点主动-主动 复制以来,我们的重点一直是提高复制性能,而不会对现有集群操作造成额外的性能下降。这使您能够将数据复制到多个数据中心和云中,以满足日常运营需求和灾难恢复需求,从而即使一个站点离线也不会降低全球可用性。复制配置完全由服务器端处理,采用“设置即忘却”的理念,使用 MinIO 的应用程序无需进行任何修改,所有内容都由服务器端处理。
MinIO 对对象进行加密,在存储层使用服务器端加密 (SSE) 在写入操作中保护对象。MinIO 以极高的效率执行此操作——基准测试表明 MinIO 能够以接近线速的速度加密/解密。
MinIO 如何实现如此高的效率和性能?
MinIO 使用的秘诀是称为 SIMD; 单指令多数据 的技术。通常,您一次只能发送一个 CPU 指令并等待响应,然后再发送下一个指令。这非常低效,尤其是在每秒执行数千甚至数百万次加密和解密指令时。MinIO 利用 SIMD 在单个 CPU 请求中发送多个指令。MinIO 是用 GoLang 的汇编语言编写的,因此我们尽可能接近硬件层,以充分利用通常未充分利用的 CPU 能力来大规模执行加密操作。
MinIO 还包括
- 加密:MinIO 支持在 Rest 和在 Transit 中加密。这确保数据在从发出调用到对象放入存储桶的整个交易过程中都被加密。
- 位腐烂保护:数据在物理磁盘上损坏的原因有很多。可能是由于电压尖峰、固件错误或其他原因造成的错误读写。MinIO 确保这些错误能够被实时捕获并修复,以确保数据完整性。
- 分层:对于不太常访问的数据,您可以将其转移到运行 MinIO 的另一个冷存储中,这样您就可以在最佳硬件上优化最新数据,而无需使用未使用的空间。
- 擦除编码:MinIO 使用此数据冗余和可用性功能来实时重建对象,而无需任何额外的硬件或软件,而不是使用本地 RAID 和节点复制的组合来确保数据的冗余,这会增加性能开销。
设置 MinIO
在这种情况下,我们将假设有两个独立的数据中心或区域,并且您在这两个数据中心中都运行 MinIO。在站点 1 中,我们将设置 minio1
集群,在站点 2 中设置 minio2
集群。这两个集群都将配置为进行站点到站点复制,因此无论将数据添加到哪个站点,MinIO 都会确保数据复制到其他站点。随着您添加更多区域或数据中心,您可以稍后扩展到 N 个站点。至关重要的是,您要为每个新区域创建一个新站点,以便跨区域和其他网络流量保持在最低限度,并提供额外的弹性和地理负载均衡,以便您能够更快地下载数据。
如果您尚未设置 MinIO 集群,请参阅 安装和部署 MinIO — 用于 Linux 的 MinIO 对象存储,并下载 MinIO 客户端 (mc)。
让我们在两个集群之间设置复制
$ mc admin replicate add minio1 minio2
Requested sites were configured for replication successfully.
验证两个站点是否已正确配置
mc admin replicate info minio1
SiteReplication enabled for:
Deployment ID | Site Name | Endpoint
f96a6675-ddc3-4c6e-907d-edccd9eae7a4 | minio1 | http://<site1_public_ip>
0dfce53f-e85b-48d0-91de-4d7564d5456f | minio2 | http://<site2_public_ip>
检查以确保复制正常工作
mc admin replicate status minio1
Bucket replication status:
No Buckets present
Policy replication status:
● 5/5 Policies in sync
User replication status:
No Users present
Group replication status:
No Groups present
通过在 minio1 中创建存储桶来进行测试
/opt/minio-binaries/mc mb minio1/testbucket
将任何对象添加到存储桶中
/opt/minio-binaries/mc cp my_object minio1/testbucket
列出其他站点(在本例中为 minio2)中的对象
/opt/minio-binaries/mc ls minio2/testbucket
[2023-08-14 18:52:09 UTC] 3.0KiB STANDARD my_object
配置配置管理系统
让我们看看来自不同配置管理提供商的几个无主配置。
Salt
在无主配置中运行 salt minion 使您能够在本地拥有配置,而无需调用主节点。此设置的目标是完全从 MinIO 站点到站点复制集群的本地 minion 文件中运行 Salt 状态。
让我们使用下面的脚本引导 salt minion。您可以在任何操作系统上运行它,但在本例中,我们将它设置在 Ubuntu 上。
curl -L https://bootstrap.saltstack.com -o bootstrap_salt.sh
sudo sh bootstrap_salt.sh
我们需要配置使用 local
文件而不是连接到 remote
salt 服务器。为此,请更改 file_client
,如下所示。
file_client: local
这将确保 salt minion 不与远程服务器通信,而是使用磁盘上本地可用的文件和 pillar。
在 MinIO 集群中创建一个存储桶,并将 salt 状态从本地镜像到 MinIO1 存储桶
/opt/minio-binaries/mc mb minio1/salt
使用 mirror
命令将 salt 状态和文件镜像到 MinIO salt
存储桶
mc mirror ~/salt_states/ minio1/salt
由于我们在该过程的早期设置了站点到站点复制,因此 salt 文件将自动复制到另一个站点,无需任何额外步骤。
现在 MinIO salt
存储桶包含所有必要的文件和状态,MinIO 将充当 Salt 的“服务器”,本质上是用更强大、更快、更能承受高负载的后端来替换 Salt 主服务器。
现在,我们将把这些文件和状态复制到各个节点,以便我们可以在这些节点上本地运行 salt-call
命令,并将配置应用到该节点。
mc cp --recursive minio1/salt/ /srv/salt/
这将确保 salt 状态文件递归地复制到位于 /srv/salt
的本地文件系统中,salt-call
将在使用 --local
标志时从该文件系统中读取。
salt-call --local state.apply -l debug
调试标志将提供运行的详细输出,这将有助于解决在应用状态时可能出现的任何问题。
接下来,我们将向您展示将 MinIO 作为服务器后端集成到另一个配置管理中是多么容易,这次是 Puppet。
Puppet
Puppet 的工作方式类似于 Salt,因为它是一种基于拉取的配置模型。让我们看看如何在 Puppet 中设置无主/无头配置。
让我们在我们的节点上安装 puppet 先决条件,从 puppet 代理相关的包开始。在 Ubuntu 节点上安装 Puppet APT 存储库
wget http://apt.puppetlabs.com/puppetlabs-release-trusty.deb
dpkg -i /tmp/puppetlabs-release-trusty.deb
apt-get update
apt-get install puppet
打开节点上的 /etc/puppet/puppet.conf
中的 Puppet 配置文件,并将整个文件替换为以下配置设置
[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$confdir/facter
在上面的设置中,$confdir
等效于节点上的目录路径 /etc/puppet
。
在节点上设置了无主无头 Puppet 代理后,让我们在 MinIO 端设置存储桶。在 MinIO 集群中创建一个存储桶,并将 puppet 模块和清单从本地镜像到 MinIO 1 存储桶
/opt/minio-binaries/mc mb minio1/puppet
使用 mirror
命令将 puppet 模块和文件镜像到 MinIO puppet
存储桶
mc mirror ~/puppet_modules/ minio1/puppet
使用 mc cp
将这些模块和清单复制到各个节点,以便我们可以在这些节点上本地运行 puppet agent
命令,并将清单应用到该节点。
mc cp --recursive minio1/puppet/ /etc/puppet/
本教程假设您在 /etc/puppet/manifests/site.pp
中已经有一个文件,该文件在我们在节点上运行 mc cp
时已下载,其内容如下
node default {
# Include modules that run on all the nodes
}
最后但并非最不重要的是,运行 puppet 命令以应用更改
puppet apply /etc/puppet/manifests/site.pp
…
Notice: Finished catalog run in 0.03 seconds
如您所见,我们现在拥有一个端到端解决方案,其中 MinIO 充当 Puppet 服务器,保存所有模块、清单和配置数据,而节点可以根据数据中心运行节点的位置从 MinIO 集群中拉取数据。
将所有内容整合在一起
我们向您展示了如何使用 MinIO 作为无主无头配置管理系统的后端。但是,如您所知,我们尽量提供整个过程的全面视图,以便您可以了解我们为何做这些事情背后的原因。
DevOps 的优秀管理者会知道,即使是基础设施中最小的更改也需要进行跟踪。本着这种精神,我们建议将您的 Salt、Puppet 或任何其他配置管理放入 git 版本控制中。在这种情况下,我们需要代码库位于 git 存储库中,以便我们可以在 mirror
到 MinIO 存储桶之前 git 克隆/拉取最新的文件。
在我们查看如何执行此操作之前,您可能想知道,为什么不使用诸如 `git clone` 之类的工具,并在每个节点上运行它以拉取配置?虽然这是可能的,但 `git clone` 非常低效,因为随着越来越多的服务器执行 `git clone`,您的内部 `git` 基础设施上的负载会越来越大。这会产生级联效应,可能会减慢您的代码更改速度,并且扩展 `git` 集群非常复杂。
您可以通过两种方式执行此操作
- 您可以编写一个简单的脚本,在某个堡垒或某种常见的 DevOps 节点上执行
git clone
和 git pull
,然后 mc mirror
到 MinIO 存储桶,如下所示
git clone https://github.com/org/puppet_modules.git /etc/puppet
mc mirror ./puppet_modules/ minio1/puppet
但是,此方法的缺点是您需要有一个单独的进程(例如 cron 或 git 后挂钩),以便每次存储库有新提交时都会运行此脚本。
- 推荐的方法是使用 GitHub Actions 或 Jenkins 作业,每当进行新提交或更好的是每当添加新标签时,该作业都会运行
mc mirror
。
git tag 0.1.0
mc mirror ./puppet_modules/ minio1/puppet
此方法不需要您每次更新存储库时都使用单独的脚本,而是只要存储库提交或标记,文件就会镜像到 MinIO 存储桶。
让我们在本地节点上使用一个小型的包装器 bash 脚本将所有内容整合在一起,该脚本将通过 cronjob 运行,并将该脚本保存为 /etc/my_puppet_run.sh
#!/bin/bash -e
mc cp --recursive minio1/puppet/ /etc/puppet/
puppet apply /etc/puppet/manifests/site.pp
对上述脚本使用 Chmod,使其可执行。
chmod +x /etc/my_puppet_run.sh
如您所见,该脚本非常简单,只有两行,这实际上是您真正需要的。接下来,让我们设置一个 cronjob,使用上面的脚本每 30 分钟运行一次。
*/30 * * * * /etc/my_puppet_run.sh
就这么简单。
Salt-N-Puppet:推它
为了回顾,在这篇博文中,我们通过将 MinIO 作为基础设施拼图中不可或缺的核心部分,展示了无主无头方式的 Puppet 和 Salt 等配置管理系统之间的区别。我们将 MinIO 以可扩展的分布式方式设置起来,因为基础设施即代码 (IaC) 系统需要与依赖 Puppet 或 Salt 的前端设备和其他基础设施设备一样可扩展、灵活、弹性和强大,甚至更强大。通过将文件和配置存储在 MinIO 中,配置管理系统能够实现高性能、可扩展性,并与 KMS 和 IDP 等企业功能无缝集成。
如果您对如何构建由 MinIO 支持的无主无头配置管理系统有任何疑问,请随时在Slack上与我们联系!