CBSD:第一部分——生产环境
作者:OLEG GINZBURG
2012 年,我作为 Nevosoft 的 IT 系统管理员工作,这是一家小型游戏开发公司,所有的服务器基础设施都基于 FreeBSD 操作系统开发。当时,没人听说过 Kubernetes 和 Docker,但得益于 FreeBSD Jail,公司的服务器通过将所有组件分开,每个服务都使用独立的 Jail 容器,从而受益。如今,FreeBSD 拥有十几个(甚至更多)容器编排程序,尽管在 2012 年时,选择并不广泛。那时有 ezjail,但它是为独立服务器提供的解决方案。我们的安装环境有三十到四十台物理服务器,每台服务器上运行着十到二十个容器。除了基本的创建操作外,删除、启动和克隆容器,公司的系统管理员还需要更高级的功能,如远程服务器上的容器管理、容器从一台服务器迁移到另一台服务器的能力,以及将容器保存为可移植镜像的功能。这些结果是通过创建简单的 shell 脚本实现的。然而,2013 年,出于应用专有软件的需要,导致公司开始迁移到 Linux。因为到那时,所有创建的 shell 脚本在功能上已经与 ezjail 平起平坐,某些情况下还增加了独特的功能(例如,最初有 TUI—基于文本的用户界面),于是决定将这些脚本集合合并,并以相同的标题发布到 FreeBSD Ports Tree 中。这标志着 CBSD 项目的开始。
与其他管理系统的比较
如今,FreeBSD 至少支持三十种用于管理容器和虚拟机的工具。在 FreeBSD 平台上有 bhyve,从这里开始,列表逐渐变长。2022 年标志着 CBSD 项目的十周年——它持续更新并继续扩展。到目前为止,它是 FreeBSD 平台上最古老的虚拟环境管理系统之一。虚拟环境不仅意味着基于 Jail 的容器化,还支持基于 bhyve、XEN 和 QEMU / NVMM 超级虚拟机监控器的虚拟机。
该项目的开发基于以下概念和哲学:
既关注单一模式的安装,也关注由多个主机构成的环境;
有机会与其他解决方案集成;
对变化保持开放,并从大局出发思考:越大的构想,潜力越大;而较小的想法通常不容易扩展;
保持简洁和灵活的使用方式。
“简单就是终极的复杂。”——列奥纳多·达芬奇
围绕 CBSD 已经出现了广泛的工具包:Web 界面、用于将任务传递给分布式 CBSD 节点的消息代理服务、API 服务以及用于与其交互的瘦客户端。
最后,CBSD 是一个原生的 FreeBSD 产品,而不是一个尝试移植 Linux 解决方案的项目。
了解更多关于项目目标的信息:https://www.bsdstore.ru/en/cbsd_goals_ssi.html
了解更多关于项目开发的信息:https://www.bsdstore.ru/en/cbsd_history_ssi.html
子项目
CBSD 不仅是面向最终用户的产品,也是参与构建复杂解决方案的元素之一,通过委派创建和管理 CBSD 虚拟环境的功能,能够节省大量工时。因此,存在多个独立的项目和发行版,用于展示和获取有关 CBSD 工作重用的见解:
Reggae(由 Goran Mekic 开发)使用 CBSD 自动化 DevOps 任务;
发行包 https://k8s-bhyve.convectix.com/(k8s-bhyve)展示了能够快速(从几秒钟到 1 分钟)启动设置在 bhyve 超级虚拟机监控器上的 Kubernetes 集群的能力;
发行包 https://clonos.convectix.com/ 具有为 CBSD 上的 bhyve 创建容器和虚拟机构建 Web/UI 界面的能力;
发行包 https://myb.convectix.com/(MyBee)使用户能够通过 CBSD 与云镜像进行交互,而无需使用 UI 和 CLI:可以通过向 CBSD API 发送 HTTP 请求(例如,使用 curl 工具)或使用 nubectl 瘦客户端(https://github.com/bitcoin-software/nubectl)来获取虚拟机。
CBSD 和 Jail 容器:实际应用
让我们更好地了解可用的 CBSD jail 操作方法。网站上有关于初始 CBSD 安装和自定义过程的描述,假设你已经拥有运行时版本。设置容器的方式有多种:
选项 1:命令行对话格式。这种方法不需要学习各种可能的 jail 参数,因为脚本会自动回忆它们:
cbsd jconstruct
选项 2:通过 TUI 的对话格式。这种方式也适合初学者,因为与第一种选项一样,不需要了解可能的参数和命令:
cbsd jconstruct-tui
这两种对话框的输出是生成文本配置文件,其中包含 jcreate 脚本的参数集合,你可以直接从 TUI 界面或命令行调用该脚本。
选项 3:使用配置文件或命令行参数。
与之前的方法相比,这种方法较为复杂,因为它需要了解可配置参数的名称,但它适合于环境开发的自动化。你可以通过以下方式合成配置文件模板:
启动: cbsd jcreate jconf=<文件路径>
此外,也可以直接通过命令行参数指定选项,而无需使用配置文件:
配置文件和命令行参数可以结合使用:
选项 4:类似 Vagrant 的风格:CBSDfile
这是一种描述 CBSD 虚拟环境的标记方式,允许同时描述容器设置并在创建时进行操作自定义(例如,将文件复制到容器文件系统并配置服务)。尽管在一个 CBSD 文件中可以描述无限数量的环境,并通过调用 cbsd up
和 cbsd destroy
来创建和删除它们,但这种标记方式对于某些目录结构来说更为用户友好,通常每个目录仅描述一个环境,例如:https://github.com/cbsd/cbsdfile-recipes/tree/master/jail
此外,通过 CBSD 文件格式创建的环境的独特能力与本地环境以及通过 CBSD API 的环境无关。
Jail 模板
我们不会详细讨论典型的容器工作操作,因为这些内容已经在 网站 上描述。我们将介绍一些 CBSD 项目的创新,旨在简化在 jail 中引用,特别是与容器模板的工作。模板是容器描述和配置的方法。对于容器来说,它可以被导出为可移植的镜像。容器可以包含一个标准的运行时环境,但在大多数情况下,它们用于服务/应用程序的隔离和通过镜像进行分发。这种方式有其优缺点。容器方法的一些优点包括服务部署的速度、不会影响基本系统环境,以及能够提交依赖项的版本,使得应用程序完全正常运行。
谈到这种方法的缺点,最主要的问题是安全性,特别是当使用没有自包含构建脚本(模板)的容器或镜像时。这使得对容器进行操作性软件更新变得困难(例如,修复 0-day 漏洞),并且容易出现后门,这些后门可能是图像收集者故意或无意留下的。考虑到安装某些软件的复杂性,通常会发现容器中配置的服务是手动放置的,或者丢失了组装说明。
另一个缺点是容器服务配置的复杂性。有些镜像可以通过环境变量配置有限数量的参数,尽管这并不总是足够的。一个例子是动态配置,当需要为 WEB 服务器添加和配置多个虚拟主机(vhost)并在数据库管理系统(DBMS)中设置多个数据库时。对于这样的任务,有一个专门的软件部分,称为配置管理。该类别中最知名的产品包括 Ansible、Chef、Puppet、Rex 和 SaltStack。然而,它们通常是为了适应经典环境而优化的。CBSD 可以结合配置管理器的全部功能和基于容器的方法,从而获得带有管理服务的容器。CBSD 中使用的模板有两种类型:
静态(经典)模板,主要仅包含安装软件。例如,CBSD 的一个模板是 sambashare 容器。
类似的模板可以在其他项目中找到:例如,Fockerfile 示例中的 nginx 模板(focker 项目):
或者,这是 BastilleBSD 项目中 RabbitMQ 模板的示例,其中 CMD 文件的内容是:
PKG 文件内容:
这些模板的实用性有限,因为它们只是以另一种形式编写了两行 shell 命令:
这些模板更为复杂,涵盖了服务配置文件的复制,并且在某些情况下,配置过程会伴随着通过复杂的 sed/awk 结构的处理,整个容器配置过程也会包括这些步骤。
作为一般原则:
a) 这是一项不可逆的操作,旨在一次性使用:无法回滚或更改配置,除非重新创建容器;
b) 这种模板对其维护要求很高:即使容器中进行了一次小的服务更新,源配置文件也可能会发生实质性变化;
c) 无法保证服务会正常运行,或者在配置错误的情况下无法回滚到以前的运行时版本;
d) 在 sed/awk 操作和切换到使用配置管理程序之间,难以找到合适的界限。
这是问题的解决方案,也是 CBSD 项目的主要信息:不要重新发明轮子,而是在可能的情况下重复使用他人的工作。许多开发者维护着配置管理模块,因此我们建议为了节省时间,使用他们的工作来委派配置管理,并使用原生的工具来处理配置。为了实现这一目标,CBSD 从 2016 年起引入了 forms 脚本。CBSD 的 Forms 功能用于获取和保存用户参数,以适合配置模块的 YAML 格式——一种特殊的中间件。Puppet 被选为配置管理系统,但也可以使用其他任何框架。
为使用模板准备 CBSD
为了更好地理解,假设我们创建一个 jail1 容器,并将 redis 服务模板应用于它。
目前,预计 CBSD 已正确安装和配置:你可以启动一个容器,并且 cbsd dhcpd
命令会为客户端分配能够访问互联网的地址(例如通过 NAT)。这是 pkg 操作和包安装在容器中所必需的条件。
必须安装 Git 来从公共仓库 https://github.com/cbsd 安装 CBSD 插件。如果尚未安装,安装 git(约 220 MB)或其轻量版 git-lite(约 40 MB):
从 CBSD 基础分发版中包含的配置文件创建系统容器 cbsdpuppet1。这一步需要在每个新的 CBSD 主机上执行一次:
cbsd puppet1 容器不应运行,因为它只执行一个功能——它包含了 CBSD 用于配置容器的 puppet7 安装包。
安装 CBSD puppet 模块——这是可选功能,不包含在基本分发版中。该模块包含了由 CBSD 项目检查的 puppet 模块。这一步需要在每个新的 CBSD 主机上执行一次:
安装 redis 服务配置模块。这一步需要在每个新的 CBSD 主机上执行一次:
创建一个容器,名称任意,在其中我们将获取 redis 服务,例如:jail1:
(注意:参数 runasap=1
意味着容器将立即启动)
最后一步:将 redis 服务模板应用到我们的 jail1 容器中:
将出现熟悉的 TUI 界面,显示 Redis 模块的参数,你可以根据需要进行配置:
让我们保留默认参数,并通过 [COMMIT] 操作选择它们。脚本运行完成可能需要一段时间(取决于互联网连接速度,因为模块从官方仓库 pkg.FreeBSD.org 安装 redis 服务器),因此你需要再次确认容器中的服务已安装并正在运行:
通过重新使用 cbsd forms 调用,你可以随时重新配置服务。此外,forms 会保留以前的值,并且在初始化时始终输出当前数据。例如,让我们更改一组参数:
将端口设置为 7777;
设置连接到 redis 服务器的密码;
将 maxmemory 参数设置为 4g;
将 maxmemory_policy 参数设置为 noeviction。
应用新参数后,检查状态:
大多数 Puppet 模块会承诺进行不正确的数据验证、配置文件验证和服务状态检查。因此,由于无效参数输入导致无法服务的服务的可能性,比静态模板要小得多。
现在我们已经了解了 TUI 界面,让我们转向自动化。cbsd forms 允许通过环境变量接受模板的参数,从而省略交互式对话。为了查看某个特定模板接受哪些变量,可以使用 vars
参数并指明所需模块:
Forms 会在常规参数的名称前添加 H_
前缀,以减少与系统全局变量发生潜在冲突的可能性。让我们第三次重新配置 redis 端口(将其设置为 9999),但不使用交互模式(inter=0
):
请注意应用模板时输出的值:
这是模板工作结果导出的 CBSD 变量的输出信息。参数化格式可以通过配置文件 forms_export_vars.conf
在目录 ~cbsd/etc
中设置。
查看其默认值:
https://github.com/cbsd/cbsd/blob/v13.0.18/etc/defaults/forms_export_vars.conf
这些值可以自动导出到文件或各种服务发现服务,如 Consul。在这种情况下,你的集群会自动获取这些值,可以用于构建 SOA(面向服务的架构),但这是另一个话题。
除了 redis,这里 还有其他服务配置模板:命名为 modules-forms-XXXX
的仓库。例如,尝试使用以下模板:
• modules-forms-memcached
• modules-forms-mysql
• modules-forms-grafana
• modules-forms-rabbitmq
• modules-forms-postgresql
• modules-forms-elasticsearch
注意:尽管传统上 1 个服务对应 1 个容器,但对于 CBSD forms,你可以将多个模板应用于同一个环境,从而一次性获得所有服务。
它是如何工作的
Puppet 模块(或任何其他类似系统)包含了在 99% 的情况下采用值参数形式的参数,这些参数通常采用 YAML 格式进行参数化。为了方便用户,CBSD 提供了一个 TUI 界面来处理基本表单,在这个界面中,与 HTML 表单类似,以下元素可以存在:
• 单选按钮(布尔类型的值为 true/false、yes/no);
• 复选框元素;
• 已知特定值的下拉菜单;
• 自定义输入框用于相对用户输入;
为了将参数保持在通用形式中,CBSD forms 使用 SQLite3 数据库——一种描述参数输入的表单,存储输入的值。记录(写入)格式是通用的,既适用于 TUI 对话框的自动生成(CBSD forms),也适用于 WEB/HTML 表单(ClonOS),如下例所示。让我们使用 CBSD forms 所需的格式创建一个 SQLite3 数据库:
让我们详细谈谈这些行中的一些内容。对我们来说,最重要的表格列是:
param
– 直接的参数名称,表示我们希望获取的值;desc
– 相关的描述(如果适用);def
– 默认值;new
– 用户输入的新值;type
– 字段类型:inputbox、delimiter、password、group_add、group_del、radio、checkbox。
接下来的两行可以添加两个参数,我们希望获取的值是:FreeBSD 和 DragonFlyBSD,每个都有自己的默认值,并且都使用 inputbox 字段格式,因此用户可以自由地输入任意字符串值。
在这个表单上运行 cbsd forms 脚本:
输出将是一个动态构建的表单,用于处理参数:
redis 服务的表单结构更为复杂,因为它包含布尔类型和下拉菜单类型的字段元素。让我们来看一下表格:
我们以表格 memory_policy_select 为例,这是 memory_policy 参数的选择类型变体表:
在 WEB 界面中,自动生成的表单(截图来自 ClonOS)如下所示:
其中,maxmemory 策略参数位于特定的下拉菜单元素中。
TUI 界面提供了类似的选择:
注意
所有 CBSD TUI 对话框都可以通过类似的基于 SQL 的表单来描述,这些表单目前仅用于与模板的工作。
在获取并处理参数后,cbsd forms 之后,cbsd puppet 模块介入了操作。接下来发生的事情如下:
使用 nullfs 挂载 overlay 文件系统,将 cbsdpuppet1 系统容器中的 puppet7 包文件挂载到目标容器(jail1)的
/tmp/XXX
目录;将包含模块参数的 YAML 文件呈现到目标容器(jail1);
获取 puppet apply 指令,应用于可配置容器(jail1),以便从
/tmp/XXX
目录应用 puppet 清单。
例如,以下是应用参数时 nullfs 挂载点的样子:
服务完成并重新配置后,临时的 nullfs 文件系统将被卸载,因为它们已经不再需要。因此,如果我们查看上述示例中的 jail1 容器中已安装的软件,将不会看到 puppet7 包或它依赖的文件。
换句话说,通过使用 cbsdpuppet1 容器,你无需在每个容器中安装 puppet7 和必要的依赖项——配置应用不依赖于有限容器中是否存在任何系统软件。
尾声
cbsd forms 是 CBSD 框架在处理基于 jail 的容器时最强大的功能之一,它在 CBSD 和配置管理器之间架起了桥梁。因此,CBSD 项目通过适当的 Puppet 模块为 FreeBSD 提供支持,而不是依赖 sed/awk 脚本支持和静态模板。如果某个模块能够在 FreeBSD 环境中运行,你可以通过 cbsd forms 透明地使用它。这对特定的 CBSD 用户和所有 FreeBSD 上的 Puppet 用户都有好处。如果你使用其他配置系统,可以通过使用 cbsd forms 脚本调用其他系统。
CBSD 项目支持基于现有模板的即用型镜像的振荡和分发,你可以通过 CBSD 仓库使用 cbsd repo 和 cbsd images。请参阅内联文档和示例:
在系列文章的下一篇中,我们将探讨 CBSD 的虚拟机管理功能。
OLEG GINZBURG 生活在俄罗斯,担任 X5 Retail group 的 DevOps 工程师。他自 ZX Spectrum(译者注:英国公司 Sinclair Research 于 1982 年发布的个人电脑。)以来便热爱计算机科学,是 Unix 爱好者和 FreeBSD 爱好者。他是 FreeBSD 的推广者,并参与多个项目:CBSD、ClonOS、MyB、K8Sbhyve、以及 AdvanceBSD group。
最后更新于
这有帮助吗?