构建 CI/CD 构建管道

到目前为止,在我们CI/CD 系列中,我们已经讨论了一些高级概念和术语。在本期中,我们将深入构建管道的实际阶段,展示其在实现中的样子。
我们将深入探讨烘焙和油炸,展示它在 MinIO 分布式集群构建过程的不同阶段中的外观。在此过程中,我们将使用基础设施即代码来确保所有内容都使用 Packer 和 Jenkins 进行版本控制和自动化。
为了让开发人员能够轻松使用我们的分布式 MinIO 设置,而无需在云中启动资源,我们将使用 Vagrant 对其进行测试。我们大多数笔记本电脑都足够强大,可以尝试一些东西,但我们已经习惯了云,因此我们倾向于首先查看那里。但我们将改变这种看法,向您展示在本地创建类似云的环境是多么容易,该环境配备了 MinIO 对象存储,只需使用您的笔记本电脑即可。
MinIO 镜像
这是烘焙阶段。为了尽可能地自动化此过程,我们将使用构建工具来创建 MinIO 的 L2 镜像,该镜像可用于启动任何类型的 MinIO 配置。这不仅使我们能够遵循基础设施即代码的最佳实践,而且还为任何未来的更改提供版本控制。
MinIO 构建模板
我们将使用 Packer 以一致的方式构建机器可读的镜像。Packer 允许您从多个输入(如 ISO、Docker 镜像和 AMI 等)中获取源代码,并通过将构建的镜像上传到 Amazon Elastic Container Registry (ECR)、Google Container Registry (GCR)、Docker Hub、Vagrant Cloud 和其他几个输出(甚至本地磁盘)来对构建的镜像进行后处理。
安装非常简单;您可以使用 brew
或者,如果您正在寻找其他发行版,请访问 Packer 下载 页面。
Packer 最初推出时,它只使用 JSON 作为模板语言,但如您所知,JSON 不是最适合人类编写的语言。机器很容易使用 JSON,但如果您必须编写一个巨大的 JSON 块,则此过程容易出错。即使省略单个命令也会导致错误,更不用说您无法在 JSON 中添加注释了。
由于上述问题,Packer 转向 HashiCorp 配置语言或 HCL(也由 Terraform 使用)作为首选模板语言。我们编写了一个 HCL Packer 模板 来构建 MinIO 镜像,让我们详细了解一下。
对于我们所有的代码示例,我们将在此处粘贴代码的关键部分,并且我们提供了完整的端到端工作示例,可在 GitHub 上下载。主模板将放在 main.pkr.hcl 中,变量(以 var
开头的任何内容)将放在 variables.pkr.hcl 中。
将仓库克隆到您的本地设置中,您将在其中运行 Packer 构建
我们将使用 virtualbox
来构建 MinIO 镜像。安装 Virtualbox
然后在 main.pkr.hcl 中将其定义为第一行的源代码
**注意:** 在文章中,我们将引用指向 GitHub 仓库中您可以在其中看到完整代码的特定行的链接,与上面类似。您可以单击这些链接以转到代码中的特定行。
让我们为将要构建的 MinIO 镜像设置一些基本参数。我们将定义名称、CPU、磁盘、内存以及与镜像配置相关的几个其他参数。
为了构建自定义镜像,需要提供源。源可以是本地相对路径(相对于运行packer
命令的路径)或在线URL。
源需要按照Packer尝试使用的顺序提供。在以下示例中,我们提供了一个本地源和一个在线源;如果本地源可用,则会跳过在线源。为了加快构建速度,我已经预先下载了ISO并将其添加到`${var.iso_path}`目录中。
我们创建的镜像需要一些默认设置,例如在配置过程中设置主机名、SSH用户和密码。这些命令作为 preseed.cfg 启动过程的一部分执行,该过程通过http服务器提供。
该镜像将使用我们编写的一些脚本进行自定义,这些脚本位于 scripts/ 目录中。我们将使用shell
供应器来运行这些脚本。
接下来,让我们运用我们在 上一篇博文中 学到的一些概念,特别是烘焙和煎炸镜像。在本教程中,我们将烘焙MinIO二进制文件和服务依赖项,例如MinIO所需的用户名和组。我们将其烘焙而不是煎炸,因为无论我们如何配置和启动镜像,这些都将保持不变。
我们将设置要安装的MinIO版本以及服务运行所在的用户名和组。
大多数安装步骤都隐藏在与模板分离的专用 bash 脚本中,但它们将从模板中调用。这使整体模板保持简洁易懂,更易于管理。以下是我们将使用的脚本列表
我不会过多介绍每个脚本的具体功能,因为大多数脚本都是设置基本 Linux 镜像所需的简单样板代码——可以将其视为我们安装的 L1 阶段。
我想要重点介绍的文件是 minio.sh,我们在其中烘焙 MinIO 二进制文件。
MinIO 二进制文件是从上游下载的,MINO_VERSION
变量在之前的几个步骤中已设置为环境变量,在安装期间可用。
安装二进制文件后,它需要用户和组,我们分别创建了它们,以便 MinIO 服务可以以它们的身份运行
通常,对于每个新的 MinIO 版本,我们应该构建一个新的镜像,但在紧急情况下,您可以在不升级整个镜像的情况下升级二进制文件。我将在煎炸阶段向您展示如何操作。
构建镜像后,我们必须告诉 Packer 如何处理它。这就是后处理器发挥作用的地方。您可以定义 多个 后处理器,但这里我们将介绍其中的三个。
vagrant
后处理器构建一个可以被 Vagrant 使用的镜像。它创建 Vagrant VirtualBox,可以使用 Vagrantfile(稍后将详细介绍 Vagrantfile)启动它。.box
文件存储在output
中定义的位置,可以本地导入。
shell-local
后处理器允许我们在本地运行 shell 命令,packer
命令执行的位置可以进行后清理和其他操作。在本例中,我们将删除输出目录,以避免与下一次 Packer 运行构建冲突。
- 在本地拥有镜像很棒,但如果您想与团队中的其他人甚至组织外部的开发人员分享您优秀的 MinIO 镜像怎么办?您可以手动分享之前生成的 box 镜像,但这可能很麻烦。相反,我们将镜像上传到 **Vagrant 云注册表**,任何想要使用您的 MinIO 镜像的人都可以从那里获取。
将镜像上传到注册表另一个好处是可以对镜像进行版本控制,即使将来升级了镜像,用户也可以将其固定到特定版本,并根据需要进行升级。
为了将 MinIO 镜像上传到 Vagrant Cloud,我们需要一个访问令牌和用于创建 Vagrant Cloud 帐户的帐户用户名。在接下来的步骤中,我们将向您展示如何获取此信息。
MinIO 镜像注册表
访问 https://app.vagrantup.com 创建一个 Vagrant Cloud 帐户。请务必遵循以下说明。
为了使用 Vagrant Cloud,我们需要预先创建一个与 Packer 配置中 `vm_name` 相同的仓库。
按照以下步骤创建用于上传镜像的仓库。
在 Vagrant Cloud 中还需要创建令牌,以便在上传构建后的镜像之前进行身份验证。请遵循以下说明。
构建 MinIO 镜像
此时,您应该已经拥有一个 Packer 模板来构建自定义 MinIO 镜像,以及一个用于上传镜像的注册表。这些都是我们在实际开始构建之前所需的所有先决条件。
进入包含 `main.pkr.hcl` 模板文件所在的目录,您会看到我们在之前的步骤中讨论过的一些其他文件。
构建过程需要有效的变量值才能在构建过程中传递,否则会失败并尝试使用默认值。具体来说,在这种情况下,我们需要传递 Vagrant Cloud 的**令牌**和**用户名**。您现在可以在 variables.pkr.hcl 中直接编辑这些值,但由于安全原因,请勿将包含这些值的该文件提交到仓库。在后面的自动化阶段,我们将向您展示另一种设置这些变量的方法,这种方法不需要编辑任何文件,并且更安全。
这些变量的值之前是在创建 Vagrant Cloud 帐户时创建的。您可以将这些值添加到 `default` 键中。
在构建镜像时,还需要升级镜像版本,这样每次构建镜像都会有唯一的版本。我们使用一种叫做 Semver 的格式系统,它允许我们根据发布的类型设置 主版本号.次版本号.修订版本号。首先,我们总是从 0.1.0
开始,每次发布都需要进行递增。
设置完变量和其他设置的有效值后,让我们确保我们的模板经过检查和验证以正常工作。
确认一切正确后,在 Packer 中运行 build
命令
这将启动构建过程,该过程可能需要 15-20 分钟,具体取决于您的机器和网络速度,以构建和上传整个镜像。
打开 VirtualBox 管理器查看 Packer 启动的 VM。它将具有分配给变量 vm_name
的名称。双击 VM 以打开 Java 控制台,其中包含实时预览屏幕截图,您可以在其中看到操作系统安装过程。
以下是开头和结尾的代码片段,其中间散布了一些 MinIO 部分。
前往 https://app.vagrantup.com 仪表板查看新上传的镜像
MinIO 分布式集群
这是煎炸阶段。我们现在发布了一个可以被我们的团队和任何想要运行 MinIO 的人使用的镜像。但我们如何实际使用这个发布的镜像?我们将使用 Vagrant 在本地启动虚拟机,类似于我们如何使用 Terraform 启动云实例。
MinIO Vagrantfile
好消息是我们已经为你写了 Vagrantfile,我们将逐步讲解它,这样你就可以理解如何在 分布式 模式下部署 MinIO。你可以在裸机、Kubernetes、Docker 和其他环境的生产环境中使用这些相同的步骤。唯一的区别是你可能想使用类似 Terraform 或 CDK 的东西来启动这些,因为它们管理的不仅仅是虚拟机或容器,还包括 DNS、CDN 和托管服务等其他云资源。
进入 vagrant
目录,该目录位于与 packer
相同的 ci-cd-build
目录中。如果你仍然在 packer
目录中,可以运行以下命令
使用以下命令安装 Vagrant,以及 vagrant-hosts
插件,该插件将允许我们使用主机名在虚拟机之间进行通信。
DNS 的工作方式非常简单,因为该插件基本上在每个虚拟机的 /etc/hosts
文件中编辑了其他在 Vagrantfile 中启动的虚拟机的详细信息。这可以手动完成,但为什么我们要手动完成呢,我们可以自动化呢?请注意,所有虚拟机都必须使用相同的 Vagrantfile 启动,因为 vagrant-hosts
不会跟踪两个独立的 Vagrantfile 之间的主机。
为了理解 Vagrantfile,你必须对 Ruby 有点了解,但如果你不了解,也没关系——它非常类似于 Python,所以我们将带你逐步讲解它的每一个部分。下面你可以看到我们如何为启动 MinIO 集群所需的一些基本参数定义变量。
大多数这些可以保持默认设置,但我建议注意 BOX_IMAGE
。盒子镜像用户名当前设置为 minioaj
,应该使用你在构建 Packer 镜像时选择的用户名进行更新。
除了上述变量外,你不需要编辑任何其他内容。它们非常容易理解,并严格遵循 MinIO 分布式设置指南。但是,无论如何,让我们一起浏览整个文件,以便我们更好地理解到目前为止我们学到的概念。
以下循环将根据MINIO_SERVER_COUNT
中指定的数量创建虚拟机。在本例中,它将循环 4 次,同时定义虚拟机设置,例如 4 个虚拟机的主机名和 IP 地址,以及它们将使用的镜像。
接下来,我们需要使用MINIO_DRIVE_COUNT
定义每个服务器集的驱动器数量。您可能已经注意到,我们不仅在数值上循环,而且还从b
开始并递增(c、d、e...)驱动器字母。这样做的原因是,Linux 中的驱动器以字母命名,例如 sda、sdb、sdc 等等。我们从sdb
开始,因为sda
被/
根磁盘占用,其中安装了操作系统。
在本例中,这 4 个服务器中的每一个都将有 4 个磁盘,总共 16 个磁盘。将来,如果您更改设置,最简单的方法是将 MINIO_SERVER_COUNT x MINIO_DRIVE_COUNT 相乘即可得出磁盘总数。
上一步只创建了一个虚拟驱动器,就像我们在裸机上添加了物理驱动器一样。您仍然需要配置磁盘分区并将其挂载,以便 Linux 可以使用它们。
使用parted
为这 4 个磁盘(b、c、d、e)中的每一个创建一个 ext4 /dev/sd*1
分区。
格式化已创建的分区并将它们添加到/etc/fstab
中,以便每次重新启动虚拟机时,这 4 个磁盘都会自动挂载。
这时,我们将挂载我们创建的磁盘,并设置 MinIO 服务启动所需的适当权限。在配置完所有磁盘组件后,我们将添加卷和凭据设置/etc/default/minio
。我们将启用 MinIO,但尚未启动它。在虚拟机启动后,我们将同时启动所有虚拟机,以避免 MinIO 在一定时间内找不到其他节点时发生的超时错误条件。
我们设置了一些与虚拟机相关的设置,但最重要的是,此代码片段中的最后一行使用 `vagrant-hosts` 插件同步所有虚拟机上的 `/etc/hosts` 文件。
到目前为止,您一定想知道为什么我们没有将所有这些 shell 命令直接烘焙到 Packer 构建过程中的 minio.sh 脚本中。为什么我们反而将这些设置作为 Vagrantfile 配置过程的一部分进行处理?
这是一个非常好的问题。原因是我们希望根据每个用例修改磁盘设置 - 有时候,您可能需要在 MinIO 集群中添加更多节点,而其他时候您可能不需要每个节点 4 个磁盘。您不希望为每个驱动配置创建唯一的镜像,因为这样会导致成千上万个类似的镜像,唯一的区别是驱动配置。
您也不想使用 MinIO 的默认 root 用户名和密码,因此我们构建了一个允许您在配置时修改这些信息的流程。
如果您想升级 MinIO 二进制版本,但又不想每次都构建新的 Packer 镜像怎么办?这很简单,只需添加一个包含下载和安装 MinIO 二进制文件的命令的 `shell` 块,就像我们在 Packer 的 minio.sh 脚本中所做的那样。以下示例伪代码可以帮助您入门
这就是您作为 DevOps 工程师需要运用最佳判断,找到烘焙和处理之间的平衡的地方。您可以选择在 Packer 构建过程中烘焙所有配置,也可以选择在配置过程中灵活地处理配置。我们希望通过此思考,帮助您在开发自己的设置时获得启发。
启动 MinIO 集群
现在,我们已经非常了解集群的部署内部机制。现在剩下的就是使用 Vagrant 在 Virtualbox 上部署集群。
设置以下环境变量,以便虚拟机能够自动检测磁盘。
确保您位于与 `Vagrantfile` 相同的位置,并运行以下命令
您的输出应该与上述内容类似,状态设置为 `未创建`。这是因为我们尚未配置节点。
最后,重头戏来了!配置我们 MinIO 集群中的 4 个节点。
确保您看到了以下输出 ==> vagrant: 功能:磁盘
,因为这验证了环境变量 VAGRANT_EXPERIMENTAL=disks
已正确设置。随着每个 VM 启动,其输出将以主机名作为前缀。如果配置过程中出现任何问题,请查看此主机名前缀以查看哪个 VM 发出了消息。
命令执行完毕后,再次运行 vagrant status
以验证所有节点是否都处于 running
状态。
所有节点都应该处于running
状态。这意味着节点正在运行,如果在配置过程中没有看到任何错误输出,那么我们Vagrantfile
中的所有shell命令都已成功运行。
最后但并非最不重要的一点,让我们启动实际的MinIO服务。如果您还记得,我们启用了该服务,但没有启动它,因为我们希望所有节点首先启动。然后,我们将使用vagrant ssh
命令几乎同时启动所有服务,该命令将使用此bash循环登录所有4个节点。
使用journalctl
命令确认,查看日志并验证所有4个节点上的MinIO服务是否已正确启动。
您应该在minio-4
中看到类似以下示例的输出。16 Online
意味着所有4个节点上的16个驱动器都在线。
将来,如果您想自己启动自定义的MinIO集群,您现在拥有所有必要的工具。
自动执行MinIO构建
从技术上讲,您可以在此停止并继续您的快乐旅程。但我们知道您总是想要更多MinIO,所以我们将更进一步,向您展示如何自动化此过程,这样您就不必每次都手动运行Packer构建命令。
安装Jenkins
使用以下命令安装并启动Jenkins
Jenkins启动后,它会要求您设置一些凭据,这应该非常简单。设置好凭据后,您需要确保已安装git插件,请按照以下步骤进行。
配置 MinIO 构建
让我们创建一个构建配置来自动化 MinIO 镜像的 Packer 构建流程。但在此之前,我们前面提到过,还有其他方法可以设置 Packer 变量的值。使用环境变量,variables.pkr.hcl 中的值可以通过在变量名前添加前缀 PKR_VAR_varname
来覆盖。在下一步中,我们将使用环境变量来覆盖一些变量,而不是直接编辑文件。
请按照以下步骤配置构建。
在“构建步骤”部分,我们添加了一些命令。以下内容可以复制粘贴到您的配置中。
执行 MinIO 构建
配置完构建作业后,就可以执行构建了。请按照以下步骤操作。
构建成功后,请访问 https://app.vagrantup.com 验证镜像是否已成功上传。
总结
在这篇博文中,我们展示了如何将 MinIO S3 兼容的对象存储在分布式模式下从构建到在笔记本电脑上配置的整个流程。这将帮助您和您的开发人员快速启动并运行生产级 MinIO 集群,并在本地使用整个功能集而不影响效率。
让我们简单回顾一下我们执行的操作。
- 我们创建了一个 Packer 模板,用于从头开始创建 MinIO 镜像。
- 我们使用 Vagrant 作为供应器,以便我们能够使用镜像在本地进行开发。
- 我们利用 Jenkins 自动将镜像上传到 Vagrant 云,以便将来构建。
我们演示了您必须在“烘焙”和“油炸”之间取得平衡。每个组织的需求都不一样,所以我们不想划清界限来说明“烘焙”应该在哪里结束,“油炸”应该在哪里开始。作为 DevOps 工程师,您需要评估以确定最适合每个应用程序的方案。我们构建 MinIO 的目的是为了提供您运行自己的对象存储所需的灵活性和可扩展性。
如果您自己实现了这一点,或者在我们的流程中添加了其他功能,请在 Slack 上告诉我们!