方法 交流电 (基础设施即代码)不仅包含存储在存储库中的代码,还包含围绕该代码的人员和流程。 是否可以重用从软件开发到基础设施管理和描述的方法? 在阅读本文时记住这个想法是个好主意。
这是我的抄本
幻灯片和视频
中文版 俄罗斯版 - 试运行 2019-04-24
斯普鲁格 DevopsConf 视频(RU) 2019-05-28 DINS DevOps 晚间视频(RU)2019-06-20 幻灯片
作为 bash 历史的基础设施
假设你来到一个新项目,他们告诉你:“我们有 基础架构即代码”。 事实证明 作为 bash 历史的基础设施 或者例如 作为 bash 历史记录的文档。 这是一个非常真实的情况,例如,Denis Lysenko 在一次演讲中描述了一个类似的案例
带着某种愿望,我们可以说 作为 bash 历史的基础设施 这就像代码:
- 再现性:您可以获取 bash 历史记录,从那里运行命令,顺便说一下,您可能会获得工作配置作为输出。
- 版本控制:您知道谁进来以及他们做了什么,这并不是事实,这不会引导您在出口处找到工作配置。
- 故事:谁做了什么的故事。 只是如果您失去服务器,您将无法使用它。
怎么办呢?
基础架构即代码
甚至像这样奇怪的案例 作为 bash 历史的基础设施 你可以拉着它的耳朵 基础架构即代码,但是当我们想做一些比旧的 LAMP 服务器更复杂的事情时,我们会得出这样的结论:这段代码需要以某种方式修改、改变、改进。 接下来我们要考虑之间的相似之处 基础架构即代码 和软件开发。
干燥
在一个存储系统开发项目中,有一个子任务
- 通过ssh登录这里并执行命令。
- 将文件复制到那里。
- 更正此处的配置。
- 在那里启动服务
- ...
- 利润!
对于所描述的逻辑,bash 是绰绰有余的,特别是在项目的早期阶段,刚刚开始的时候。 这
原来还有DRY(Do not Repeat Yourself)这样的做法。 这个想法是重用现有的代码。 这听起来很简单,但我们并没有立即想到这一点。 在我们的例子中,这是一个平庸的想法:将配置与脚本分开。 那些。 如何单独部署安装、单独配置的业务逻辑。
适用于 CFM 的 SOLID
随着时间的推移,该项目不断发展并
单一责任原则
每个类只执行一项任务。
无需混合代码并制作单一的神圣意大利面怪物。 基础设施应该由简单的砖块组成。 事实证明,如果您将 Ansible 剧本分成小部分,阅读 Ansible 角色,那么它们会更容易维护。
开闭原则
开闭原则。
- 开放扩展:意味着可以通过创建新的实体类型来扩展实体的行为。
- 禁止更改:由于扩展了实体的行为,因此不应对使用这些实体的代码进行任何更改。
最初,我们在虚拟机上部署了测试基础设施,但由于部署的业务逻辑与实现是分离的,所以我们添加了部署到裸机,没有任何问题。
里氏替换原则
芭芭拉·利斯科夫的替代原则。 程序中的对象必须可以用其子类型的实例替换,而不改变程序的正确执行
如果你从更广泛的角度来看,它并不是任何特定项目的功能都可以在那里应用 坚硬的,一般都是关于CFM的,比如在另一个项目上需要在各种Java、应用服务器、数据库、OS等之上部署一个盒装的Java应用程序。 使用这个例子,我将考虑进一步的原则 坚硬的
在我们的例子中,基础设施团队内部达成了一项协议:如果我们安装了 imbjava 或 oraclejava 角色,那么我们就有了一个 java 二进制可执行文件。 这是必要的,因为上游角色取决于此行为;他们期望 java.lang. 同时,这允许我们将一个 java 实现/版本替换为另一个 java 实现/版本,而无需更改应用程序部署逻辑。
这里的问题在于,在 Ansible 中不可能实现这一点,因此团队内部出现了一些协议。
接口隔离原则
接口分离原则:“许多特定于客户端的接口比一个通用接口更好。
最初,我们尝试将应用程序部署的所有可变性放入一个 Ansible playbook 中,但很难支持,并且当我们指定了外部接口(客户端期望端口 443)时,可以从单个基础设施中组装基础设施具体实现的砖块。
依赖倒置原则
依赖倒置的原理。 较高级别的模块不应依赖于较低级别的模块。 两种类型的模块都必须依赖于抽象。 抽象不应该依赖于细节。 细节必须依赖于抽象。
这里的示例将基于反模式。
- 其中一位客户拥有私有云。
- 我们在云中订购了虚拟机。
- 但由于云的性质,应用程序部署与虚拟机所在的虚拟机管理程序相关联。
那些。 高级应用程序部署逻辑依赖于较低级别的虚拟机管理程序,这意味着重用此逻辑时会出现问题。 不要那样做
互动效果
基础设施即代码不仅涉及代码,还涉及代码与人之间的关系,涉及基础设施开发人员之间的交互。
总线系数
假设您的项目中有 Vasya。 Vasya 了解您的基础设施的一切,如果 Vasya 突然消失会发生什么? 这是一个非常真实的情况,因为他可能会被公共汽车撞到。 有时候这种情况会发生。 如果发生这种情况,并且关于代码、其结构、工作原理、外观和密码的知识没有在团队中分布,那么您可能会遇到许多不愉快的情况。 为了最大限度地减少这些风险并在团队内分配知识,您可以使用各种方法
配对消除
这不像
另一个特殊情况是事件呼叫。 在出现问题时,一群值班人员和相关人员聚集在一起,任命一名领导者,他分享他的屏幕并表达思路。 其他参与者跟随领导者的想法,从控制台监视技巧,检查他们没有错过日志中的一行,并了解有关系统的新知识。 这种方法通常很有效。
代码审查
主观上,使用代码审查来传播有关基础设施及其工作原理的知识更有效:
- 基础设施由存储库中的代码描述。
- 更改发生在单独的分支中。
- 在合并请求期间,您可以看到基础架构中的更改增量。
这里的亮点是审稿人是根据时间表一一选出的,即您有可能会进入一个新的基础设施。
代码风格
随着时间的推移,评审期间开始出现争吵,因为…… 审稿人有自己的风格,审稿人的轮换以不同的风格堆叠他们:2个空格或4个,camelCase或snake_case。 不可能立即实施这一点。
- 第一个想法是推荐使用linter,毕竟大家都是工程师,大家都很聪明。 但不同的编辑器、操作系统,不太方便
- 这演变成一个机器人,它为每个有问题的提交写入 slack 并附加 linter 输出。 但在大多数情况下,还有更重要的事情要做,而代码仍然没有修复。
绿色建造大师
随着时间的流逝,我们得出的结论是,未通过某些测试的提交不能被允许进入 master。 瞧! 我们发明了Green Build Master,它在软件开发中已经实践了很长时间:
- 开发工作正在一个单独的分支中进行。
- 测试正在该线程上运行。
- 如果测试失败,代码将不会进入母版。
做出这个决定是非常痛苦的,因为…… 引起了很多争议,但这是值得的,因为...... 评论开始收到风格上没有差异的合并请求,随着时间的推移,问题区域的数量开始减少。
IaC测试
除了样式检查之外,您还可以使用其他方法,例如,检查您的基础设施是否可以实际部署。 或者检查基础设施的变化不会导致金钱损失。 为什么需要这个? 这个问题既复杂又哲学,最好用一个故事来回答:不知何故,Powershell 上有一个自动缩放器,它没有检查边界条件 => 创建了比必要的更多的虚拟机 => 客户花费了比计划更多的钱。 这不是很令人愉快,但是很可能在早期阶段发现这个错误。
有人可能会问,为什么要让复杂的基础设施变得更加复杂? 就像代码测试一样,基础设施的测试不是为了简化,而是为了了解基础设施应该如何工作。
IaC 测试金字塔
IaC 测试:静态分析
如果你一次性部署整个基础设施并检查它是否正常工作,你可能会发现这需要花费很多时间并且需要很多时间。 所以,基础一定是见效快的东西,有很多,而且涵盖了很多原始的地方。
Bash 很棘手
让我们看一个简单的例子。 选择当前目录中的所有文件并复制到另一个位置。 我首先想到的是:
for i in * ; do
cp $i /some/path/$i.bak
done
如果文件名中有空格怎么办? 好吧,我们很聪明,我们知道如何使用引号:
for i in * ; do cp "$i" "/some/path/$i.bak" ; done
做得好? 不! 如果目录中没有任何内容怎么办,即通配符不起作用。
find . -type f -exec mv -v {} dst/{}.bak ;
现在做得好了吗? 不...忘记文件名中可以包含什么 n
.
touch x
mv x "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir
静态分析工具
当我们忘记引号时,可能会发现上一步的问题,为此,自然界中有很多补救措施
语言
工具
打坏
红宝石
蟒蛇
ansible
IaC 测试:单元测试
正如我们从前面的例子中看到的,linter 并不是万能的,不能指出所有的问题区域。 此外,通过类比软件开发中的测试,我们可以回忆起单元测试。 立即想到的是
一开始我们谈到 坚硬的 我们的基础设施应该由小砖块组成。 他们的时代已经到来。
- 基础设施被分为小块,例如 Ansible 角色。
- 部署某种环境,无论是 docker 还是虚拟机。
- 我们将 Ansible 角色应用到这个测试环境中。
- 我们检查一切是否按我们的预期运行(我们运行测试)。
- 我们决定好还是不好。
IaC 测试:单元测试工具
问题,CFM 测试是什么? 您可以简单地运行脚本,也可以使用现成的解决方案:
CFM
工具
Ansible
厨师
厨师
盐堆
testinfra 示例,检查用户 test1
, test2
存在并且在一个组中 sshusers
:
def test_default_users(host):
users = ['test1', 'test2' ]
for login in users:
assert host.user(login).exists
assert 'sshusers' in host.user(login).groups
选择什么? 问题复杂且模糊,下面是 2018-2019 年 github 上项目变化的示例:
IaC 测试框架
问题出现了:如何将它们组合在一起并启动它? 能
CFM
工具
Ansible
厨师
Terraform
2018-2019 年 github 上项目变更示例:
分子对比测试厨房
最初我们
- 并行创建虚拟机。
- 应用 Ansible 角色。
- 运行检查。
对于 25-35 个角色,工作时间为 40-70 分钟,时间很长。
下一步是过渡到 jenkins/docker/ansible/molecule。 从本质上讲,一切都是一样的
- Lint 剧本。
- 排列角色。
- 启动容器
- 应用 Ansible 角色。
- 运行测试基础设施。
- 检查幂等性。
40 个角色的检查和十几个角色的测试开始需要大约 15 分钟。
选择什么取决于很多因素,例如使用的堆栈、团队的专业知识等。 这里每个人自己决定如何结束单元测试问题
IaC 测试:集成测试
基础设施测试金字塔的下一步将是集成测试。 它们类似于单元测试:
- 基础设施被分为小块,例如 Ansible 角色。
- 部署某种环境,无论是 docker 还是虚拟机。
- 对于此测试环境适用 许多 Ansible 角色。
- 我们检查一切是否按我们的预期运行(我们运行测试)。
- 我们决定好还是不好。
粗略地说,我们不会像在单元测试中那样检查系统单个元素的性能,而是检查整个服务器的配置方式。
IaC 测试:端到端测试
在金字塔的顶端,我们受到端到端测试的欢迎。 那些。 我们不会检查单独的服务器、单独的脚本或基础设施的单独块的性能。 我们检查许多服务器是否连接在一起,我们的基础设施是否按我们的预期运行。 不幸的是,我从未见过现成的盒装解决方案,可能是因为...... 基础设施通常是独特的,难以模板化和创建测试框架。 结果,每个人都创建了自己的解决方案。 有需求,但没有答案。 因此,我会告诉你什么是为了促使其他人做出正确的想法,或者是为了让我觉得一切都是很久以前就在我们之前发明的。
一个有着丰富历史的项目。 它用于大型组织,可能你们每个人都间接接触过它。 该应用程序支持许多数据库、集成等。 了解基础设施可能是什么样子的是大量的 docker-compose 文件,了解在哪个环境中运行哪些测试是 Jenkins。
这个方案运行了相当长的一段时间,直到在框架内
研究想法更进一步,在 openshift 中他们发现了 APB(Ansible Playbook Bundle)这样的东西,它允许您将如何将基础设施部署到容器中的知识打包。 那些。 关于如何部署基础设施有一个可重复、可测试的知识点。
所有这一切听起来都不错,直到我们遇到异构基础设施:我们需要 Windows 来进行测试。 因此,关于什么、在哪里、如何部署和测试的知识都在 jenkins 中。
结论
基础设施即代码
- 代码在存储库中。
- 人际交往。
- 基础设施测试。
链接
英文版本 从个人博客交叉发帖 - 试运行 2019-04-24
斯普鲁格 DevopsConf 视频(RU) 2019-05-28 DINS DevOps 晚间视频(RU)2019-06-20 从编写超过 300,000 行基础设施代码中汲取的经验教训 &文字版 将基础设施即代码集成到持续交付管道中 测试基础设施即代码 Ansible角色的有效开发和维护 Ansible 不是 bash!
来源: habr.com