为了有效地使用Terraform,重要的是将一些关键事项明确化
首先
这篇文章是 2019 年 Terraform Advent Calendar 的第 23 篇文章。
因为讨厌写作欺诈横行而被排除在排名之外,我会努力掩饰一下哈哈w
太长不看 bù
-
- terraform を便利に運用維持管理していくために大事なことがいくつかあります
-
- それらについてそうすることで なぜ 便利になるのか 何が 便利になるのか、があまり真剣に語られることは少ないです
-
- そのせいで初心者に伝わりにくいのかなと思ったので、解消のために言語化する試みです
-
- わかってる人は読まなくていいと思います
-
- 異論は認める
- 基本的にはこれから始める人向け、AWSでWeb系アプリケーションみたいな前提で書いています。それ以外の素敵な使い方をしている場合はそれを教えてほしいし、それなら見てないでカレンダーに記事書けよw
为了有效地运维和维护 Terraform,需要注意以下重要事项。
-
- 使用 tfenv
-
- 使用 direnv
-
- 使用 ansible
-
- 使用 packer
-
- 如果可能的话,不使用 workspace
-
- 时刻运行 CI/CD(始终执行 plan)
-
- 不固定模块的版本(不写 version)
- 始终处理差异。
使用 tfenv
tfenv是一个terraform版本管理工具。
通过在目录中放置.terraform-version文件来指定所使用的terraform版本。
这意味着我们可以向共享库的成员宣布在该目录中使用的terraform版本。
使用tfenv可以使团队成员保持一致。
tfstate文件包含使用的Terraform版本号,而在此版本之前的版本无法更新。
因此,如果成员没有统一步调,不小心安装并应用最新版本,会遇到困难。
在使用工具时保持版本的一致非常重要,尤其是在使用 terraform 时更是必需的,原因已经提到过。
使用 direnv
direnv 是一种 Shell 扩展工具。
它有许多用途,但主要用于设置用户特定和团队共享的环境变量。
其意义类似于 tfenv,在当前目录中使用的环境变量被通知给库的共享成员。
根据12-Factor应用程序的要求,为了将应用程序的行为与变量分离,最好使用环境变量等方式传递,而不是直接在应用程序中进行描述。
具体来说,AWS提供程序的应用程序密钥和秘密密钥(这些通常是用户特定的)以及DataDog提供程序的应用程序密钥(这些通常是一个项目中的共享)可以作为共享使用。
使用direnv,则可以通过将AWS密钥设置为变量名并使用自己的密钥,将数据狗密钥设置为项目共享的密钥,在.envrc.sample等文件中表达出来。
(虽然说法有点那个样子,但可以说这篇文章是为了给那些乌鸦工程师写的,因为存储库中有点文件,而且无法了解每个文件的含义,无法自己查找和理解等等)
通过使用direnv带来的优势在于仅仅表示项目所使用的变量名。在个人责任的范围内,如果能够获得相同的结果,则可以直接使用个人电脑的环境变量,也可以从aws cli的配置中直接使用值(尽管在要求环境变量值的terraform之外的部分可能会产生不同的结果,但这也属于个人责任)
此外,由于一旦进入该目录就会自动应用,如果拥有多个存储库,则无需切换到每个存储库所需的权限,这非常方便。
如果将其作为一种共享信息的表达方式来考虑,不需要强迫使用工具,反而是无法回想起在没有direnv的情况下如何操作的重要性。
3. 使用ansible
只讨论terraform中的ansible,ansible是一种配置管理工具,它的便利之处主要有两个,在terraform的背景下,除了这两个之外是不需要的。
-
- terraform remote state 用の s3 bucket を作る(s3に限らないけど)
- 後述の packer から使用して AMI を構築する
Terraform会在本地配置一个名为terraform.tfstate的文件,但通常会使用s3来将其配置到远程。这个s3存储桶必须在执行Terraform之前存在,因此需要以某种方式先创建它,这就轮到它出场了。只需使用一个简单的Playbook创建一个单独的s3存储桶。谁在手动使用管理控制台创建呢?
通过使用packer创建AMI(请根据实际情况适当替换为其他云平台),可以解放创建实例等资源。相反,如果仍然在各个地方使用ansible来创建尚未AMI化的实例,或者使用aws_instance资源,那么现在就应该重新审视策略。
为了这一区域,我正在为Ansible Advent Calendar 2019的第四天写一篇文章。如果您方便,请看一下。
通过与后续的持续集成/持续交付(CI/CD)相结合,我们可以始终自动生成最新的AMI,并通过terraform将其应用于(例如aws_launch_configuration),从而定期适配到最新的云环境。
当然可以使用Chef或Puppet等工具。只要得到团队成员的同意。
4. 使用packer
packer是一个用于创建AMI(以及其他机器镜像)的配置工具。
正如前面所述,与ansible配合使用可与terraform有很高的兼容性。
准确地说,它只是通过数据源提取生成的AMI,因此具有完全的解耦性。
我认为我们正进入云原生时代,并进入了容器的全盛期。然而,由于仍然有许多场景需要云实例,因此创建适用于各种云实例的机器映像的包装器在共享配置文件(例如packer)方面非常重要。
顺便一提,它也支持docker,但我认为使用cli直接进行docker构建更加直观,所以我们需要根据实际情况做出选择,不必将所有工作都交给packer。
创建机器镜像的好处在于将使用的实例从宠物变为家养动物。换句话说,它变成了一种可一次性使用的实例。不使用时不是停止而是丢弃。下次启动时将是最新状态。
通过这种方式,可以更容易地跟随云服务本身或包裹的最新更新,而不必费力维护放置在数据中心的固定实例,或在服务器机房中放置的裸金属机器硬盘故障而痛苦。
由于 Packer 是和 Terraform 一样的 HashiCorp 产品,所以我对替代软件没太大兴趣,但如果您了解的话,请在评论中告诉我,我会很开心的。
5. 尽量不要使用workspace。
我在第12天的文章中写到了目录分割和工作空间。虽然不是绝对必要,但我个人还是不建议使用工作空间。
有些优秀的人似乎能够在瞬间判断嵌套变量如map或list的位置以及如何处理,但作为一位普通工程师代表,我似乎无法在未来持续保持这一技能。
在考虑工作空间切换成本和防止相关错误的意义下,我认为甚至不需要使用工作空间来进行apply测试。
然而,正如之前的文章所述,我认为适不适合取决于个人的能力和团队工作的情况。
请合理利用。
6. 持续集成/持续交付是持续运行的(总是进行计划)。
我在 GitHub Actions Advent Calendar 2019 的第5天写了一篇关于使用 GitHub Actions 开展terraform CI的文章。
有关CI/CD的解释就不再赘述,但在terraform的上下文中,它的重要性在于始终跟进更新(提供者和模块的更新),这是其含义。
以前,人们在数据中心搭建机器,安装应用程序并运行,然后就不再关注操作系统的更新,甚至还可能连安全补丁都不打(嗯,现在好像还是有这样的情况哈哈)。
如果在云时代进行这样做,未来不久后可能会后悔。
由于云自身的更新,设置方法可能会改变,或者转移到更好的服务上,同时操作系统、库和安全补丁的更新也越来越频繁。此外,terraform本身、供应商和使用的模块也在不断升级,选择不追随这些升级就等于慢慢走向死亡。
terraform plan是用来确认代码和资源之间的差异的。它不仅用于确认代码和资源的状态是否正确,还用于发现意外的更改,以及注意到资源服务方面的规格变更(尽管显示和结果相同)。如果在昨天没有差异,并且没有人进行修改,但出现了差异,那么有40%是云端的问题,30%是模块问题,20%是其他成员的问题,10%是其他因素引起的变动(这是个人的感觉)。
terraform 在2019年发布了v0.12.0版本之后,那些没有在v0.11之前进行版本升级的人肯定遇到了一些困难。(咦?还有人没有完成更新吗?)
如果你所在的公司或团队选择不升级并以忍受数年而不做出改变的觉悟,我建议你尽快远离。否则,作为基础设施工程师或SRE,你将错失成长的机会。
我感觉说得有点跑题,但为了跟进代码以外部分的更新并掌握其变化,我们应始终努力使用持续集成/持续交付(CI/CD)来保持系统的健壮性。
7. 不要固定模块版本(不写版本号)
同样如前所述,可以使用 tfenv 等工具来指定 Terraform 的版本(并不是要求固定版本)。
定期进行 Terraform 的版本更新时,要获得成员的同意后再进行。
同时,在这个时机也应该对 provider 和模块进行版本更新。
terraform init --upgrade
如果平时通过GitHub Actions或其他方法进行terraform的CI,通常不需要在模块源中写入版本号(因为它应该始终以最新状态运行)。
在出现差异难以吸收或存在实际bug等情况下,可以暂时写入版本号以解决问题,但平时建议不写版本号。
大企業那样的人可能会说,既然你管理代码了,版本也应该好好管理,但说实话,这种想法是愚蠢或者无知,简直是浪费时间。
根据上述内容,不仅仅是我自己编写的代码,terraform自身、provider、模块以及云端都在不断更新。虽然我们可以通过代码来管理基础架构,如果在使用的模块中指定版本,就可以知道在特定提交中使用了哪个版本,并且可以回滚到该时间点,但实际上这是不可能的。当云端版本升级,并且相应的功能消失时,我们无法使用该版本。尤其是对于模块来说,如果有错误会进行修复,但不保证旧版本的运行。更重要的是,如果能花时间回顾过去,不如不断向前推进更有意义。
使用.terraform-version来表示Terraform的版本,不需要写module.version来始终保持最新。只有在不可避免地遇到错误等情况时才临时使用module.version。这样做可以使以后的操作更加轻松。
常常專注於吸收差異。
按照前面所述,定期升级 terraform 版本,运行 CI/CD,始终检查计划的差异,以便跟上每天的更新。
只要每天都进行确认,并采用目录分割,即使有更新,每个修正也应该只是微不足道的。
除非像从v0.11到v0.12那样发生了重大变化,或者在像re:Invent或CloudNext这样的大型活动之后,一般情况下都是正常运营范围内的。
相反,如果发生了大量的变更超出了这个范围,我认为这是因为忽略了某些问题,所以请注意避免出现这种情况。
顺便说一下,在我们公司今天突然发现了CI的差异,我们询问了成员,发现该成员的设备上没有差异。
我觉得奇怪,于是查了一下,发现几天前升级了一个模块,进行了相当糟糕的改动。事实上,这是一个可能在很多情况下需要的变更,如果不是相关的情况,可能会有一些垃圾产生,但只是一些小事而已。
每天使用 Terraform 都让我深刻体会到,现代化的基础设施管理基本上是一种幻想,它要依赖于日复一日的实际努力才能实现。
最终
毫不畏惧地说,Terraform 是一个将代码和云资源连接起来的接口。
只要写”A”,就能得到一个”A”的资源。但明天是否还能得到”A”并不确定。
可能通过更新变成”A'”,或者有人搞破坏变成”B”,或者资源破坏丢失。
实际上,可能需要的并不是”A”,而是”C”。
我相信 Terraform 是高效管理这些的最佳选择。
希望这篇文章能对正在使用 Terraform 进行基础设施运营的人们有所帮助。
最后但并非最不重要的是,terraform-jp是一个聚集了对terraform热爱的用户的Slack工作空间。我们希望所有刚刚开始接触terraform的人、对terraform感到困惑的人、希望做出贡献的人以及与terraform相关的所有人都能参与进来。请务必试试加入(请在#自我介绍频道进行自我介绍)。
給一個中文版本的例子:额外奖励
-
- リストにリモートステートを使う、を乗せなかったのは記事のカラーとちょっと違うかな、と思ったから
-
- consul を乗せなかったのは SaaS がないので自前運用が面倒だから
-
- vault を乗せなかったのはこの記事の読者には時期尚早だから
- 外部モジュールを活用する、を乗せなかった以下同上