持续集成和持续交付基础
您是否想过拥有数百个应用程序和数百万用户的大公司如何管理他们的持续集成(构建)和持续交付(部署)工作流程?在编写 kafka 消费者、使用 Jaeger 观察跟踪以及使用 OpenTelemetry 收集指标时,我们在之前的一些博客中编写了一些代码。如果我们可以将其中一个应用程序与MinIO一起使用并将它们捆绑在一起并进行部署,那不是很酷吗?
我们将讨论如何在分布式设置中部署 MinIO ,这将使我们能够在本地环境中对其进行测试,在开发环境中进一步验证,并在最终将其带到生产云环境之前添加监控和更改。
如果您是一个每周部署一次的组织,这意味着每次部署都可能是一场奇观,您需要部署工程师的唯一目的是确保部署顺利进行。把部署管道想象成数学;如果你没有每天练习,即使是该学科的老师也会忘记它是如何工作的。这是因为对于不频繁的部署,很难预测和修复错误。当部署没有按计划进行时,团队中的每个工程师都需要知道如何回滚新版本并重新部署旧版本。
另一方面,每天多次部署多个工程师在单个版本中提交的组织不会像每周一次的管道那样感到“CI/CD 疲劳”。他们不需要部署工程师,因为现有工程师在部署发生时会被分配此任务,而无需分配整个角色。但正如我之前提到的,并非所有部署都会按计划进行,因为部署后可能会发现错误或安全漏洞,现在团队中的任何工程师都可以回滚。
在这篇博文中,我们将探讨有关 CI/CD 的一些概念,以及如何应用它在分布式设置中部署 MinIO 集群以及您自己的应用程序,方法是从上游源构建它们,一直到在裸机、GCP、AWS,甚至 Kubernetes 以标准化的方式连接到多个云。凭借您在这里学到的知识,您的管道将有可能构建数千个工件。我们不仅会尽可能使用开源工具,还会使用行业标准工作流程来实现这一目标。

概念
在我们深入研究工作流程和管道之前,让我们先谈谈一些重要的概念和术语。
人工制品
工件是代码库的版本化捆绑包,可以采用 Docker 映像、Amazon 机器映像、VMDK 或简单 ISO 的形式。在某些情况下,它也可能是 RubyGems、Python PIP 包和/或 NVM 包,等等。捆绑包可以是当前部署的版本、过去进行的部署或尚未发布的未来部署。
工件存储库
构建工件后,需要以版本控制的方式使用它们。我们希望能够上传同一代码库的不同版本,因为我们不想删除生产中使用的工件,以防我们需要在部署新版本后重新部署或回滚。MinIO 可以直接替代任何支持 AWS S3 SDK 和 API 的 repo 这也称为Artifact Registry;这些术语可以互换,如下所示。
持续集成
我喜欢将持续集成视为“持续构建”。当您提交代码更改时,您希望尽快构建工件,以便您可以在代码投入生产之前及时测试和修复错误。
工程师将代码提交到 git 存储库。
自动化工具选择代码库并对其进行广泛测试。
工件被构建、版本化并上传到工件存储库。
持续交付
一旦构建了工件,就需要将它们交付或“持续部署”到适当的开发环境,在准备部署到生产环境之前可以对其进行测试。这就是工程师不仅对代码库而且对代码与基础架构的其余部分的行为方式充满信心的地方。
将构建工件部署到开发环境。
对数据库和存储等其他组件进行集成和压力测试。
将经过测试的代码库部署到生产环境中。
流水线
从构建、测试和部署到各种环境开始,工件需要构建为可重用的工作流,以端到端地自动化工作流。这些 CI/CD 工作流也称为管道。管道通常分为几个步骤,以便工程师在完成每个步骤时对 CI/CD 过程充满信心。他们在这个过程中获得的信心越大,他们可以在代码库上进行的测试就越多,最终部署到生产中也会更加顺利。该空间中可用的一些工具是:
GitHub 操作
亚搏体育应用程序 CI/CD
詹金斯 (OG)
AWS 代码管道
GCP 云构建
圈子CI
SLA 反转
构建和部署管道依赖于基础设施的各个部分,这些基础设施反过来又决定了管道的 SLA。例如,在构建工件时,代码存储库、上游存储库和/或 DNS 的可用性决定了构建管道的 SLA,而 GCP、AWS 和/或 VMware 可用性为我们提供了部署管道的 SLA。您可以在此处阅读有关 SLA 反转的更多信息。
基础架构即代码
基础架构即代码 (IaC) 是一种可执行文档。它列出了应用程序读取的指令,以在不实际使用任何 GUI 或 CLI 的情况下调出资源(裸机、AWS、GCP)。基础设施的任何变化都需要进行编码和测试。在为基础设施编写代码时,单元、集成和验收测试是最重要的。您可以在此处阅读有关 IaC 的更多信息。
供给者
供应者从注册表中提取工件并使用元数据来供应资源。使用基础架构即代码将允许您对代码库进行编码和版本控制。
烤和炸
烘焙是专为特定应用而打造的神器。
Frying 是一个通用的工件,可以在许多应用程序中使用。
这最好用一个例子来说明。工程师必须在机器上本地测试 MinIO。每次他们启动 VM 时,它都会安装 MinIO 包并即时拉取依赖项。这是油炸。过去,每个新虚拟机启动大约需要七分钟,这变得非常乏味。为了解决这个问题,我们“烘焙”了一个新的 VM 映像,其中包含所有依赖项,并在构建期间安装了 MinIO 依赖项。在烘焙了现在预装了所有依赖项的新 VM 之后,MinIO 集群在大约 7 秒内启动。作为一个额外的好处,它是稳定和可重复使用的。如果你注意到我们说烘焙和煎炸,而不是对抗。您不必在二者之间做出选择,因为可以对图像进行部分烘烤和其余部分的烘烤,选择最适合应用程序的图像并进行相应调整。一般来说,你烘焙的图像越深,它们与油炸图像相比就越稳定。
十二因素应用程序
有许多不同的方法可以设计应用程序来与 CI/CD 管道的各个部分一起工作。其中之一是十二因素应用程序设计。需要考虑的一些关键事项是:
使用声明式格式进行设置自动化,以最大限度地减少新开发人员加入项目的时间和成本
与底层操作系统有一个干净的合同,在执行环境之间提供最大的可移植性
应用程序适合部署在现代云平台上,无需服务器和系统管理
最大限度地减少开发和生产之间的差异,实现持续部署以实现最大的敏捷性
并且可以在不对工具、架构或开发实践进行重大更改的情况下进行扩展。
工具
到目前为止,我们已经讨论了很多概念,但橡胶是如何与路面接触的呢?让我们简要谈谈您可以用来为您的管道提供动力的一些工具。有多种工具,从可以在本地安装的开源工具到可以以最少的开销使用的 SaaS。此管道的目标是使用尽可能少的包装器脚本将它们粘合在一起,因此没有自行开发的解决方案来维护或加入人员。
封隔器
Packer 允许您以版本控制基础架构即代码的形式定义构建工件的步骤。Packer 直接从上游拉取 Docker 映像、AWS 机器映像或 ISO,并构建一个自定义工件,然后可以将其上传到各种工件存储库。
流浪汉
构建工件后,您需要一种在笔记本电脑上对其进行本地测试的方法。Vagrant 允许您从注册表中将自定义工件部署为虚拟机或 Docker 映像。通过这种方式,您可以避免使用云中的资源,并在笔记本电脑上进行本地开发。
供给者
Provisioner 基本上是 API 驱动的云不可知工具,通常只能与具有 API 的资源交互以启动基础设施。供应器以声明方式用 JSON 或 YAML 编写,只要有 API 来处理请求,我们就可以在 AWS、GCP 或裸机上供应资源。它是声明性的,因为代码定义了基础设施的最终结果。你不一定关心它是如何达到那个状态的,你也不应该关心。一些常见的配置工具是:
地貌
AWS Cloudformation
GCP 部署管理器
服务发现和 KV Store
虽然大多数设置都可以在构建过程中配置,但主机名或基于数据中心或区域的数据库设置等一些东西只能在部署阶段构建工件后才能配置。我们还需要这些服务是可发现的,以便可以自动生成配置生成和服务依赖项。这个空间中可用的一些工具是
等等
领事
金库
Vault 使用 Consul 键/值存储作为后端来存储秘密。出于安全和其他原因,这些不能在构建过程中进行硬编码。事实上,Consul 和 Vault 服务器都可以在同一个实例上运行。
工件存储库
还有更多,但以下是一些最受欢迎的
泊坞枢纽
捷蛙工坊
港口
码头
AWS 弹性容器注册表 (ECR)
GCP 容器注册表 (GCR)
最小IO
在与管道的其余部分集成时,MinIO 非常通用。MinIO 可以作为Harbor 的 S3 后端来存储工件,实际上 MinIO 也可以作为Artifactory 的 S3 后端。
此外,当您使用 Terraform 而不是将状态存储在本地磁盘上时,您可以使用 Vagrant 快速配置 MinIO 集群并将 Terraform 状态数据存储在那里,从而允许多个用户访问 Terraform 状态。当然,在生产中请确保您使用Terraform在分布式设置中运行它。
管道
下面的工作流程突出显示了该过程的构建管道部分。如您所见,Base/L1 可重复用于创建 App/L2 工件。除了最初的来源,Upstream vs Registry,工作流程保持不变。

Layer 0 (L0), Foundation Artifact:Foundation 是 ISO、Docker 镜像、Canonical、RedHat、Docker,甚至 AWS 和 GCP 发布的 AMI。这些是基本的标准 Linux 发行版,可以从任何公共存储库中提取。例如 Ubuntu 20.04 和 22.04 或基本的最小 Python Docker 映像。
第 1 层 (L1),基础工件:这是安装有基础包、监控和安全最佳实践的组织特定操作系统的地方。这些在所有应用程序之间共享。例如指标、监控和日志记录。我们不应该拥有这些;这些工件通常由基础架构团队构建和维护。
第 2 层 (L2),应用程序工件:特定于应用程序的配置、程序包、GPU 驱动程序。示例可以是数据科学、Web、redis、MinIO、Memcache 或特定于应用程序的类似内容。Base artifacts (L1) 可以被重用来生成新的 MinIO 服务器 artifacts。如果您最终得到很多 L2 工件,请不要太惊讶。这些工件也可能由开发人员创建,因此他们可以在用于生产之前使用 Vagrant 测试他们的 Docker 容器。
注意:通常 L0 和 L1 之间的比率应为 1:1,并且应用程序工件 (L2) 不应重复用于烘焙较新的工件(L3 或更高版本),因为依赖链会变得笨拙。
再举一个例子,让我们假设在一个 MinIO 版本中存在安全漏洞。如果 L1 工件易受攻击,则从中创建的任何 L2 工件也容易受到攻击。假设您有一个 L3 工件,那是另一个也必须修补的层。如果您只有少数工件,这可能不是问题,但此管道有可能生成数千个工件:尝试找出依赖链!另一个例子是内核安全补丁。如果 L1 容易受到攻击,那么任何由此构建的 L2 工件也容易受到攻击,需要打补丁。
基础架构目标不同于应用程序目标。从基础架构的角度来看,所有环境,甚至是开发环境,都被视为“生产环境”。为什么?好吧,我很高兴你问。如果开发或阶段环境中的 MinIO 出现故障,它最终会影响开发人员,因此就 devops 而言,他们被视为“生产”。同时MinIO在部署到生产环境之前需要进行测试,我们也不能直接部署到开发者使用的环境中。
我们通过将我们的 MinIO 集群分离到不同的环境中来实现这一点。
基础设施环境
沙盒
金丝雀
居住
应用环境
发展
分期
质量保证
生产
Ops(所有应用程序环境使用的公共服务)
每个基础设施环境都可以拥有所有(或部分)应用程序环境;层次结构如下:
沙盒
发展
分期
金丝雀
发展
分期
质量保证
生产
行动
居住
发展
分期
质量保证
生产
行动
通过这种方式,我们实际上可以在应用到实时环境之前在金丝雀环境中应用生产更改。
牛与独角兽
资源的命名和设计应该更多地为牛而不是独角兽。如果我们想开始像对待牛一样对待资源,名称应该提供足够的信息,以便您知道 MinIO 在哪里运行,但同时尽可能随机,这样就不会发生冲突。这样做的好处是您可以避免出现独特的雪花,并且因为没有模式而使自动化变得困难。
一个建议是使用以下格式:
ROLE-UUID.APP-ENV.INFRA-ENV.REGION.fqdn.com
例子:
minio-storage-f9o4hs83.dev.canary.ap-south-1.fqdn.combase-web-l0df54h7.prd.live.us-east-1.fqdn.com
最后的想法
让我们回顾一下我们在这篇文章中讨论的内容。我们深入研究了一些 CI/CD 概念、涉及的工作流程以及一些我们可以用来为管道提供动力的工具。我们向您展示了 MinIO 可以在构建过程和部署过程中集成的不同方式。
我们在这里讨论的只是冰山一角,我们鼓励您实现自己的版本。在以后的博客中,我们将向您展示当您使用我们讨论的工具实施时的情况,为您提供管道的整体端到端视图。
事实上,如果您最终实现了自己的版本,请在Slack上给我们留言!