我们如何将基础架构管理放在Terraform上并开始生活

图片
我们有4个Amazon帐户,9个VPC和30个最强大的开发环境,阶段,回归-总共1000多种颜色和阴影的EC2实例。 自从我开始为企业收集云解决方案以来,我需要尽一切努力来思考如何使所有这些自动化。

你好 我叫Kirill Kazarin,我是DINS的工程师。 我们正在开发基于云的业务通信解决方案。 在我们的工作中,我们积极使用Terraform,通过它可以灵活地管理我们的基础架构。 我将分享我在此解决方案上的经验。

这篇文章很长,所以就去买爆米花茶吧!

还有一点细微差别-这篇文章是基于版本0.11编写的,在最新版本0.12中发生了很多变化,但是主要的实践和技巧仍然有意义。 从0.11迁移到0.12的问题值得一提!

什么是地形


Terraform是2014年出现的一种流行的Hashicorp工具。

使用该实用程序,您可以使用一种非常友好,易于阅读的声明性语言,将基础架构中的云基础架构作为代码范例进行管理。 它的应用程序为您提供了统一的资源类型和用于基础结构管理的代码实践应用程序,这是开发人员社区早已开发的。 Terraform支持所有现代云平台,使您可以安全且可预测地更改基础架构。

启动后,Terraform会读取代码,并使用云服务提供商提供的插件,通过进行必要的API调用,使基础架构达到所描述的状态。

我们的项目完全位于亚马逊上,基于AWS服务进行了部署,因此我就此着手介绍Terraform的使用。 另外,我注意到它不仅可以用于亚马逊。 它允许您管理所有具有API的内容。

此外,我们管理VPC设置,IAM策略和角色。 我们管理路由表,证书,网络ACL。 我们管理Web应用程序防火墙,S3-bucket,SQS队列的设置-我们的服务可以在Amazon中使用的所有内容。 我还没有看到Terraform无法用基础设施描述的Amazon功能。

事实证明,这是一个相当大的基础架构,用手即可轻松支撑。 但是使用Terraform既方便又简单。

Terraform由什么构成


提供程序是用于处理服务API的插件。 我数了他们一百多个 。 其中包括Amazon,Google,DigitalOcean,VMware Vsphere和Docker的提供商。 我什至在此官方列表上找到了一个提供商,该提供商可让您管理Cisco ASA的规则

除其他外,您可以控制:


这些只是官方提供者,甚至还有更多非官方提供者。 在实验期间,我在GitHub上遇到了一个第三方,但未包含在官方列表提供程序中,该第三方允许使用GoDaddy的DNS以及Proxmox资源

在一个Terraform项目中,您可以使用不同的提供程序,并因此可以使用不同的服务提供程序或技术的资源。 例如,您可以使用GoDaddy的外部DNS在AWS中管理基础架构。 明天,您的公司购买了一家由DO或Azure托管的初创公司。 在决定是否将其迁移到AWS时,您也可以使用相同的工具来支持它!

资源。 这些是您可以使用Terraform创建的云实体。 它们的列表,语法和属性取决于所使用的提供程序,实际上取决于所使用的云。 或者不仅仅是云。

模组 这些是Terraform允许您用来配置配置模板的实体。 因此,模板可以使您的代码更小,可以重复使用。 好吧,他们帮助他轻松地工作。

为什么我们选择Terraform


对于我们自己,我们确定了5个主要原因。 也许从您的角度来看,并不是所有这些都显得很重要:

  • Terraform是不可知的Cloud Multicloud支持实用程序(感谢评论中的宝贵评论) 。 当我们选择此工具时,我们认为:-如果管理人员明天或一周后到我们这里说:“ 伙计们,我们认为-我们不仅要部署到亚马逊。我们有某种项目,我们需要在Google Cloud或Azure中获得基础架构的位置-嗯,您永远不会知道 。” 我们决定,我们希望拥有一个不会与任何云服务严格绑定的工具。
  • 开源 。 Terraform是一个开源解决方案 。 该项目存储库的评级超过1.6万颗星,这很好地证明了该项目的声誉。

    我们不止一次或两次遇到以下事实:在某些版本中存在错误或行为不完全可以理解。 拥有开放的存储库可以确保您确实是一个错误,我们可以通过简单地更新插件的引擎或版本来解决问题。 或者这是一个错误,但是“请稍等两天,我们将发布一个新版本,我们将对其进行修复。” 或:“是的,这令人难以理解,很奇怪,他们将其整理出来,但是有解决方法。” 非常方便。
  • 控制 。 Terraform作为实用程序完全由您控制。 它可以安装在笔记本电脑,服务器上,也可以轻松集成到您的管道中,这可以在任何工具的基础上完成。 例如,我们在GitLab CI中使用它。
  • 检查基础结构的状态 。 Terraform可以并且可以很好地检查基础架构的状态。

    假设您开始在团队中使用Terraform。 您在Amazon中创建一些资源(例如安全组)的描述,然后应用它-它是为您创建的,一切都很好。 还有-笨蛋! 您的同事昨天休假回来,但您还不知道您在这里安排的一切都如此精美,甚至来自其他部门的同事也来了,并手动更改了此安全组的设置。

    如果不与他见面,不说话或以后不承担任何问题,在正常情况下,您将一无所知。 但是,如果您使用Terraform,则即使在此资源上闲置运行计划也将向您显示工作环境有所变化。

    当Terraform查看您的代码时,它会同时调用云提供商的API,并从中接收对象的状态并进行比较:“现在,我做的和以前一样,我还记得什么?” 然后,他将其与代码进行比较,查看还有哪些需要更改的地方。 并且,例如,如果他的故事,他的记忆以及您的代码中的所有内容都相同,但是在那里有所变化,他将向您展示并提出将其回滚。 我认为,这也是一个很好的属性。 因此,对于我们个人而言,这是确保我们拥有不变的基础架构的又一步。
  • 另一个非常重要的功能是我提到的模块 ,而且很重要。 稍后再说。 什么时候我会与工具进行比较。

蛋糕上也有樱桃:Terraform有很多内置函数 。 尽管使用了声明性语言,但是这些功能使我们能够实现一些(不是说编程的)逻辑。

例如,一些自动计算,分割线,转换为小写和大写字母,从该行中删除字符。 我们正在积极地使用它。 它们使工作变得更加轻松,尤其是当您编写一个稍后将在不同环境中重用的模块时。

Terraform与CloudFormation


网络经常将Terraform与CloudFormation进行比较。 选择时我们也问了这个问题。 这是我们比较的结果。

比较方式地貌云形成
多重云支持通过使用各种提供程序,插件可以与任何大型云提供程序一起使用。
牢固地附着于亚马逊。
变更追踪如果有零钱
不在TF代码中,而是在他创建的资源上,TF将能够检测到这一点并允许您纠正这种情况
出现类似功能
仅在2018年11月
条件不支持条件(仅
以三元运算符的形式)。
支持条件。
贮藏
允许您选择几种后端类型,例如本地
在您的计算机上(这是默认行为),在文件共享上,
在S3和其他地方。

有时这很有用,因为tfstate Terraform是作为具有JSON式结构的大型文本文件呈现的。 有时,进入它,阅读它有时很有用-至少能够备份它,因为您永远都不知道。 例如,就我个人而言,我对某些地方受我控制的事实感到平静。
仅在AWS内部某个地方存储状态
资源导入Terraform使导入资源变得容易。 您可以控制所有资源。 您只需编写可表征该对象的代码,或使用Terraforming
她去了同一个亚马逊,从那里获取有关环境的信息,然后以代码形式转储它。
它是机器生成的,不是经过优化的,但这是开始迁移的一个很好的第一步。 然后,您只需输入import命令。 Terraform进行比较,将这种环境置于其状态-现在由它来控制它。
CloudFormation不知道如何。 如果
您之前已经做过一些事情,可以用CloudFormation对其进行重拍然后重新创建它,或者继续进行下去。 不幸的是,没有选择。

如何开始使用Terraform


一般来说,入门非常简单。 以下是简要的第一步:

  1. 首先,创建一个Git存储库,并立即开始存储所有更改,实验以及所有内容。
  2. 阅读入门指南 。 它小巧,简单,相当详细,并且很好地描述了如何使用该实用程序。
  3. 编写一些演示工作代码。 您甚至可以复制某种示例以供日后使用。

我们在Terraform上的实践


源代码


您开始了第一个项目,并将所有内容保存在一个大的main.tf文件中。 这是一个典型示例 (老实说,我是从GitHub获得的第一个示例 )。

没错,但是代码库的大小会随着时间的推移而增长。 资源之间的依赖性也在增长。 一段时间后,文件变得巨大,复杂,不可读,维护不当-随意更改某个位置可能会造成麻烦。

我建议的第一件事是突出显示所谓的核心存储库,即项目,环境的核心状态。 一旦开始使用Terraform创建基础结构或将其导入,您将立即发现以下事实:您拥有一些实体,这些实体一旦部署,配置并很少更改。 例如,这些是VPC设置或VPC本身。 这些是网络,基本的常规安全组,例如SSH访问-您可以编译相当大的列表。

将其与您经常更改的服务保存在同一存储库中没有任何意义。 在单独的存储库中选择它们,然后通过Terraform功能(例如远程状态)将它们停靠。

  • 您正在减少经常直接使用的项目那部分的代码库。
  • 而不是一个包含描述基础结构状态的大型tfstate文件,而是两个较小的文件,并且在特定的时间点您正在使用其中的一个。

诀窍是什么? Terraform制定计划时,即进行计算,计算应更改的内容并应用-它完全重新计算该状态,对照代码,对照AWS中的状态。 您的州越大,计划所需的时间就越长。

我们花了20分钟为生产中的整个环境制定计划时才采用这种做法。 由于我们将不需要频繁更改的所有内容都放入一个单独的核心中,因此我们将制定计划的时间减少了一半。 我们有一个想法,可以进一步减少它,不仅可以分为核心和非核心,还可以分为子系统,因为我们将它们连接在一起并且通常一起更改。 因此,我们说,我们将把10分钟变成3分。但是我们仍在实施这种解决方案的过程中。

更少的代码-更易于阅读


小代码更容易理解,使用起来也更方便。 如果您有一个庞大的团队,并且拥有不同经验水平的人员,请在单独的萝卜中将您很少更改的内容(但在全球范围内删除),并提供更窄的访问范围。

假设您的团队中有初级员工,而您不让他们访问描述VPC设置的全局存储库-这样可以确保自己不会出现错误。 如果工程师在编写实例时犯了一个错误,并且创建了错误的东西-这并不可怕。 而且,如果他在所有机器上安装的选件上出错,中断或使用路由对子网设置进行了某些操作,这将更加痛苦。

核心存储库的选择分几个步骤进行。

第一阶段 。 创建一个单独的存储库。 将所有代码分别存储在其中-并使用此输出描述应在第三方存储库中重用的那些实体。 假设我们创建了一个AWS子网资源,其中描述了它的位置,哪个可用区,地址空间。

resource "aws_subnet" "lab_pub1a" { vpc_id = "${aws_vpc.lab.id}" cidr_block = "10.10.10.0/24" Availability_zone = "us-east-1a" ... } output "sn_lab_pub1a-id" { value = "${aws_subnet.lab_pub1a.id}" } 

然后,我们说我们将该对象的ID发送到输出。 您可以为所需的每个参数进行输出。

这有什么窍门? 描述值时,Terraform会将其分别保存在tfstate核心中。 当您求助于他时,他将不需要同步,重新计数-他将能够从此状态立即将此事交给您。 此外,在非核心存储库中,您将描述与远程状态的这种连接:您具有远程状态诸如此类,它位于S3-bucket中,诸如此类,诸如此类,并且具有密钥和区域。

第二阶段 。 在非核心项目中,我们创建一个指向核心项目状态的链接,以便我们可以引用通过输出导出的参数。

 data "terraform_remote_state" "lab_core" { backend = "s3" config { bucket = "lab-core-terraform-state" key = "terraform.tfstate" region = "us-east-1" } } 

第三阶段 。 开始吧! 当我需要为特定子网中的实例部署新的网络接口时,我说:这是数据远程状态,在其中找到该状态的名称,在其中找到此参数,实际上与该名称匹配。

 resource "aws_network_interface" "fwl01" { ... subnet_id = "${data.terraform_remote_state.lab_core.sn_lab_pub1a-id}" } 

当我在非核心存储库中制定变更计划时,Terraform的这个值将成为它的常数。 如果要更改它,那么必须在核心库中进行。 但是,由于这种变化很少,因此不会给您带来太大的麻烦。

模组


让我提醒您,模块是一个独立的配置,由一个或多个相关资源组成。 它作为一个组进行管理:

模块是一件非常方便的事情,这是因为您很少会像这样在真空中创建一个资源,通常它在逻辑上与某物相连。

 module "AAA" { source = "..." count = "3" count_offset = "0" host_name_prefix = "XXX-YYY-AAA" ami_id = "${data.terraform_remote_state.lab_core.ami-base-ami_XXXX-id}" subnet_ids = ["${data.terraform_remote_state.lab_core.sn_lab_pub1a-id}", "${data.terraform_remote_state.lab_core.sn_lab_pub1b-id}"] instance_type = "t2.large" sgs_ids = [ "${data.terraform_remote_state.lab_core.sg_ssh_lab-id}", "${aws_security_group.XXX_lab.id}" ] boot_device = {volume_size = "50" volume_type = "gp2"} root_device = {device_name = "/dev/sdb" volume_size = "50" volume_type = "gp2" encrypted = "true"} tags = "${var.gas_tags}" } 

例如:当我们部署一个新的EC2实例时,我们为其创建一个网络接口和附件,我们通常为其创建一个弹性IP地址,并创建route-53记录,等等。 也就是说,我们至少获得4个实体。

每次用四段代码描述它们都是不方便的。 而且,它们非常典型。 它要求-制作一个模板,然后仅引用该模板,并向其传递参数:一些名称,将其推入哪个网格中,将哪个安全组挂在其上。 非常方便。

Terraform具有计数功能,可让您进一步减少状态。 您可以用一段代码描述一大堆实例。 假设我需要部署20台相同类型的机器。 即使从模板中,我也不会编写20条代码,而是会编写1条代码,在其中指示计数和数字-我需要做多少。

例如,有些模块引用模板。 我只传递特定的参数:ID子网; 与之一起部署的AMI; 实例类型; 安全组设置; 还有其他事情,并向我指出其中有多少事情要做。 太好了,把他们带走了!

明天,开发人员来找我说:“听着,我们想尝试一下负载,请再给我们两个。” 我需要做的是:将一位数字更改为5。代码量保持完全相同。

按照惯例,模块可以分为两种类型-资源和基础结构。 从代码的角度来看,没有什么区别,而是操作员本人引入的更高层次的概念。
资源模块提供标准化的和参数化的,逻辑相关的资源集合。 上面的示例是一个典型的资源模块。 如何与他们合作:

  • 我们通过Source指令指示模块的路径-配置的源。
  • 我们指出版本-是的,此处按“最新和最大”原则操作不是最佳选择。 您没有在项目中每次都包含库的最新版本吗? 但是稍后会更多。
  • 我们将参数传递给它。

我们已连接到模块的版本,而我们只学习了最后一个版本-必须对基础结构进行版本控制(无法对资源进行版本控制,但可以对代码进行版本控制)。 可以删除或重新创建资源。 仅此而已! 我们还必须清楚地知道我们创建了每个基础架构的版本。

基础结构模块非常简单。 它们由资源组成,并包含公司标准(例如,标签,标准值列表,可接受的默认值等)。

对于我们的项目和我们的经验,我们已经长期而坚定地转向使用资源模块,以便通过非常严格的版本控制和审查过程来实现所有可能的事情。 现在,我们正在实验室和阶段一级积极介绍基础结构模块的实践。

使用模块的建议

  1. 如果您不会写,但使用现成的,请不要写。 特别是如果您是新手。 相信现成的模块,或者至少看看他们是如何做到的。 但是,如果您仍然需要编写自己的消息,请不要在内部使用对提供程序的调用,并应谨慎对待服务提供程序。
  2. 检查Terraform Registry是否不包含现成的资源模块。
  3. 如果要编写模块,则将细节隐藏在引擎盖下。 最终用户不必担心内部实现什么以及如何实现。
  4. 从模块执行输入参数和输出值。 如果它们是单独的文件,则更好。 好方便
  5. 如果编写模块,请将其存储在存储库和版本中。 最好为模块提供一个单独的存储库。
  6. 不要使用本地模块-它们不会被版本化或重复使用。
  7. 避免在模块中使用提供程序描述,因为可以为不同的人不同地配置和应用连接凭据。 有人为此使用环境变量,有人暗示将其密钥和机密存储在文件中,并为其指定了路径。 必须在更高级别上显示。
  8. 仔细使用本地供应商。 它在运行Terraform的计算机上本地执行,但是不同用户的执行环境可能不同。 在将其嵌入CI之前,您可能会遇到各种工件:例如本地exec和运行ansible。 某人拥有不同的发行版,另一个外壳,不同版本的ansible甚至Windows。

一个好的模块的迹象(这里有更详细的说明 ):

  • 好的模块有文档和示例。 如果将每个设计为单独的存储库,则这样做更容易。
  • 它们没有硬编码设置(例如,AWS区域)。
  • 使用设计为默认值的合理默认值。 例如,默认情况下,用于EC2实例的模块不会为您创建类型为m5d.24xlarge的虚拟机,而是为此使用最小t2或t3类型之一。
  • 该代码是“干净的”-结构化,带有注释,没有不必要的混淆,以相同的样式设计。
  • 尽管很困难,但非常希望它配备测试。 不幸的是,我们还没有解决这个问题。

标记


标签很重要。

标记正在计费。 AWS的工具可让您查看在基础架构上花费了多少钱。 我们的管理层确实希望拥有一个可以确定性地查看它的工具。 例如,此类组件之类消耗多少钱,或此类子系统之类,团队之类的环境。

图片

标记是系统的文档。 有了它,您可以简化搜索。 即使只是在屏幕上整齐地显示这些标签的AWS控制台中,您也可以更轻松地理解此实例或该实例类型指的是什么。 如果有新同事来,您可以通过显示以下内容来更轻松地进行解释:“看,就是这里-在这里。” 我们开始如下创建标签-我们为每种资源类型创建了一个标签数组。

一个例子:

 variable "XXX_tags" { description = "The set of XXX tags." type = "map" default = { "TerminationDate" = "03.23.2018", "Environment" = "env_name_here", "Department" = "dev", "Subsystem" = "subsystem_name", "Component" = "XXX", "Type" = "application", "Team" = "team_name" } } 

碰巧的是,在我们公司中,有超过一个团队使用AWS,并且有一些必需标签的列表。

  1. 团队-哪个团队使用多少资源。
  2. 部门-类似于部门。
  3. 环境-资源在“环境”中占优势,但是例如,您可以将其替换为项目或类似的项目。
  4. 子系统-组件所属的子系统。 组件可以属于一个子系统。 例如,我们想看看我们有多少子系统及其实体开始消耗。 例如,在前一个月突然增长了。 我们需要去开发商那里说:“伙计们,这很昂贵。 预算已经接近了,让我们以某种方式优化逻辑。”
  5. 类型-组件的类型:平衡器,存储,应用程序或数据库。
  6. 组件-组件本身,其内部表示法名称。
  7. 终止日期-应该以日期格式删除的时间。 如果不希望将其删除,请设置为“永久”。 我们之所以介绍它,是因为在开发环境中,甚至在某些阶段环境中,我们都有一个压力测试阶段,该阶段会在压力测试期间上升,也就是说,我们没有定期维护这些机器。 我们指出应销毁资源的日期。 此外,您可以基于lambda(一些通过AWS Command Line Interface运行的外部脚本)加强自动化,这将自动销毁这些资源。

现在-如何标记。

我们决定为每个组件做一个自己的标签映射,在其中列出所有指定的标签:何时终止它,指的是什么。 他们很快意识到这很不方便。 由于代码库在不断增长,因为我们有30多个组件,而这样的30段代码很不方便。 如果您需要更改某些内容,则可以运行并进行更改。

为了标记正确,我们使用Locals实体。

 locals { common_tags = {"TerminationDate" = "XX.XX.XXXX", "Environment" = "env_name", "Department" = "dev", "Team" = "team_name"} subsystem_1_tags = "${merge(local.common_tags, map("Subsystem", "subsystem_1_name"))}" subsystem_2_tags = "${merge(local.common_tags, map("Subsystem", "subsystem_2_name"))}" } 

您可以在其中列出一个子集,然后将其相互使用。

例如,我们将一些常用标签删除到这种结构中,然后由子系统删除了特定标签。 我们说:“采用此块并添加例如子系统1。对于子系统2,添加子系统2”。 我们说:“标签,请使用通用标签,并在标签中添加类型,应用程序,名称,组件及其名称。” 如果突然需要,结果非常简短,清晰,集中。

 module "ZZZ02" { count = 1 count_offset = 1 name = "XXX-YYY-ZZZ" ... tags = "${merge(local.core_tags, map("Type", "application", "Component", "XXX"))}" } 

图片

版本控制


模板模块(如果使用它们)必须存储在某个地方。 每个人最有可能启动的最简单方法是本地存储。 就在同一目录中,只是您描述了某个子目录的子目录,例如,某种服务的模板。 这不是一个好方法。 它很方便,可以快速修复和快速测试,但是以后很难重用并且很难控制

 module "ZZZ02" { source = "./modules/srvroles/ZZZ" name = "XXX-YYY-ZZZ" } 

假设开发人员来找您说:“因此,我们需要在基础结构中以这样的配置来配置实体。” 您编写了它,并以本地模块的形式在其项目的存储库中进行了编写。 部署-出色。 他们测试说:“会的! 在生产中。” 我们上台,进行压力测试,生产。 每次按Ctrl-C,Ctrl-V; Ctrl-C,Ctrl-V。 在进行销售时,我们的同事拿走了它,从实验室环境中复制了代码,将其转移到另一个地方并在那里进行了更改。 而且我们得到了已经不一致的状态。 使用水平缩放,当您拥有我们拥有的尽可能多的实验室环境时,这只是个玩笑。

因此,一个好的方法是为每个模块创建一个单独的Git存储库,然后引用它。 我们将所有事物都集中在一个地方-良好,方便,可控制。

 module "ZZZ" { source = "git::ssh://git@GIT_SERVER_FQDN/terraform/modules/general-vm/2-disks.git" host_name_prefix = "XXX-YYY-ZZZ" 

预料到问题,您的代码将如何到达生产环境。 为此,将创建一个单独的项目,该项目将重用已准备和经过测试的模块。

太好了,我们有一个集中更改的代码源。 我接受,撰写,准备并设定好自己,明天早上我将在生产环境中进行部署。 建立了一个经过测试的计划-太好了,走吧。 此刻,我的同事在良好的意愿的指导下,去优化了一些内容,并添加到了该模块中。 碰巧这些更改破坏了向后兼容性。

例如,他添加了必须传递的必要参数,否则模块将无法组装。 或者,他更改了这些参数的名称。 我是早上来的,我严格限制更改时间,开始制定计划,Terraform从Git提取状态模块,开始制定计划并说:“糟糕,我不能。 还不够,您已重命名。” 我很惊讶:“但是我没有这样做,如何处理?” 如果这是很久以前创建的资源,那么在进行此类更改之后,您将不得不在所有环境中运行,以某种方式进行更改并产生外观。 这很不方便。

可以使用Git标签修复。 我们自己决定使用SemVer表示法,并制定了一条简单的规则:一旦模块的配置达到某个稳定状态,即可以使用它,便在该提交上放置一个标记。 如果我们进行更改并且它们没有破坏向后兼容性,那么我们将在标记处更改次设备号,如果它们中断了,则将更改主设备号。

因此,在源地址中,附加一个特定的标签,如果至少提供您以前拥有的东西,它将始终被收集。 让模块版本继续进行,但是在适当的时候我们会来,当我们真正需要它时,我们将对其进行更改。 而且在此之前起作用的是,至少不会中断。 这很方便。 这就是我们的GitLab中的样子。

图片

分枝


使用分支是另一重要实践。 我们已经为自己制定了一条规则,即您只能从主人那里进行更改。 但是,对于您要进行和测试的任何更改,请创建一个单独的分支,进行尝试,试验,制定计划并查看进展情况。 然后执行合并请求,然后让同事查看代码和帮助。

图片

哪里存储tfstate


您不应该将状态存储在本地。 您不应该将状态存储在Git中。

当某人在推出非主服务器的分支时获得其tfstate(状态已保存)时,我们就为此而烦恼。然后他通过合并打开了它,有人添加了自己的tfstate,结果是合并冲突。 或结果是没有它们,但是状态不一致,因为“他已经拥有了,但我还没有”,然后解决所有问题是不愉快的做法。 因此,我们决定将它存储在一个安全的版本中,但是它应该位于Git之外。

S3非常适合此情况:据我所记得, 确切地说四个9,也许是五个 ,它可以提供HA。 它提供了开箱即用的版本控制功能,即使您破坏tfstate,也可以随时回滚。 而且,他还与DynamoDB结合使用非常重要,在我看来,DynamoDB从0.8版开始就已经学习了这个Terraform。 在DynamoDB中,您有一个铭牌,Terraform在其中记录它正在阻止状态。

也就是说,假设我要进行一些更改。 我正在开始制定计划或开始应用它,Terraform进入了DynamoDB,并说它在此板中显示此状态被阻止的信息; 用户,计算机,时间。 此时此刻,我的同事在远程工作,或者在距我几张桌子的地方工作,但专注于工作却看不到我在做什么,他的同事也决定需要进行一些更改。 他制定了一个计划,但稍后发布了。

Terraform进入动态,看到-锁定,断开,告诉用户:“抱歉,tfstate被某些东西阻止了。” 一位同事看到我现在正在工作,他可以​​走近我说:“听着,我的更换机更重要,请让我。” 我说:“好”,我取消计划,删除该块,而是,即使您正确执行该块也会被自动删除,而不会中断Ctrl-C。 一位同事去做。 因此,我们确保自己不会遇到两个人都在改变某些事情的情况。

合并请求


我们在Git中使用分支。 我们将合并请求分配给同事。 此外,在Gitlab中,我们几乎使用了所有可用于协同工作的工具,用于合并请求,甚至只是一些池:讨论您的代码,对其进行审阅,设置进行中或发出的问题,诸如此类。 这是非常有用的,对工作有帮助。

另外,在这种情况下,回滚也更容易,您可以返回到先前的提交,或者,例如,如果您决定不仅要从向导中应用更改,还可以简单地切换到稳定分支。 例如,您创建了一个功能分支,并决定首先从该功能分支进行更改。 一切正常后,然后进行更改,然后再更改为主控。 您在分支机构中应用了更改,意识到出了点问题,切换到了主服务器-未更改,应用说,他返回了。

流水线


图片

我们决定需要使用配置项流程来应用更改。 为此,我们基于Gitlab CI,编写了一个使变更应用程序自动化的管道。 到目前为止,我们有两种类型:

  • 主分支的管道(主管道)
  • 所有其他分支的管道(分支管道)

早午餐管道有什么作用?它开始自动代码验证(例如,愚蠢地检查输入错误)。然后,它开始制定计划。观察您的合并请求的同事可以立即打开已构建的计划,不仅可以看到代码-而且还可以看到您添加的内容。他还将看到它如何落在您的基础架构上。这是清楚而有用的。

图片

在向导中,此处又添加了一个步骤。区别在于您的计划不仅是生成的,而且还保存为工件。Terraform的另一个非常有用的功能是可以将计划另存为文件,然后应用它。假设您提出了合并请求并将其搁置一旁。一个月后,他们想起了他,决定返回。您的代码已经走得很远了。由于您保留了计划的工件,因此可以将其应用于当时需要的对象。

图片

在我们的情况下,该伪像然后被转移到下一步,由人工执行。也就是说,我们对更改进行了单点应用。

地形的缺点


功能介绍尽管Terraform具有相当多的内置函数,但并不是所有的内置函数都像我们想的那样好。

它具有令人不舒服的功能,例如“元素”-在某些情况下,由于缺乏经验,其行为可能与您预期的不一样。

例如,您使用一个模块,将计数传递给该模块-要部署的实例数,例如,传输按可用性区域细分的子网列表。转移,应用,增加计数,仍然应用。现在,您决定将增加的子网列表转移到该列表。您有了网格,决定再使用一个可用区。您需要更改列表的第二部分,并且count通过一个元素映射到此列表。

假设您在此实例之前有4个可用区和5个实例,然后添加了另一个可用区-它将保留前四个可用区。大约第五个他会说:“现在我将重新创建它。”而你不想!您只希望有新的来。这些错误来自Terraform处理列表的性质。

三元运算符。条件只是三元运算符。我们确实缺乏条件。不过,我想要一些更熟悉的If and Else。可惜他们不是-也许他们会搭便车。

团队合作的挑战。如果您有一个庞大的团队或一个大型项目,用于大量环境,或两者兼而有之,则Terraform将变得难以使用而不使用某些CI。

没有CI,您将在计算机上从本地环境进行更改。根据我们的经验,这导致您为自己创建了一个分支,开始了它的尝试,并尝试了它-忘记了进行合并,忘记了进行更改。好痛

例如,您和您的同事在计算机上具有相同的版本。然后,我站点上的一位同事更新了版本。第二天,开始进行更改,Terraform进行检查,发现在tfstate中所需的Terraform版本更高,并说:“不,我不能,请更新我。”当您有一个用于更改的小窗口时,不容易看到您首先需要更新该实用程序。

当您拥有CI时,例如,在管道容器中只有一个实体-您可以确保自己不会在实用程序中找到此类版本。

最后,损坏或未使用的代码可能会在向导中堆积。每当您离开家时都懒得等到建立整个环境的计划时。您将尝试仅通过更改来通过目标选项构建应用程序。例如,您添加了一个实例并说:“ Terraform应用目标实例”或安全组。但是在这种情况下,如果发生故障(例如某些配置已过时),则在构建完整计划时会看到它。

您将需要花费大量的精力和时间来使此更新。无需提出这个问题。如果存在配置项-我们只是强行说Terraform将完全构建计划,则您可以推动更改。让他制定计划,然后去做其他事情。他建造了它,您看到了它,然后以人工制品的形式将其拿下,然后便开始应用它。它纪律。

Terraform不是灵丹妙药


他将不允许您做什么:

  • Terraform , . , , . , , , . , , , .

    , — Tfstate, , . . « , » — .

    , -, , - — . , . , — .
  • Terraform , . Terraform . 怎么了 , . . , , AZ - -. , North Virginia, 6 . . , , : «, ». — . — , , Terraform .
  • Terraform . , — 200 , 198 , 5. . , API . las
  • 而且,他不能考虑某些名称必须唯一。例如,您要制作一个S3存储桶。这是该地区的一项全球服务,即使您未在帐户中创建使用该名称的服务,也不是其他人没有创建该服务。当您使用Terraform创建它时,它会完美地建立一个计划,开始创建它,然后Amazon会说:“对不起,已经有人有了这个。” 这是无法预先预见的。仅当您尝试用手先进行操作时,尽管这与练习相反。

无论如何,Terraform是目前最好的。而且我们继续使用它,对我们有很大帮助。

Source: https://habr.com/ru/post/zh-CN470543/


All Articles