Day 04-Terraform 也有 Backend?啥是 Terraform Backend 能吃吗?

Terraform 也有 Backend 之啥是 Terraform Backend 能吃吗?

课程内容与代码会放在 Github 上: https://github.com/chechiachang/terraform-30-days

赛後文章会整理放到个人的部落格上 http://chechia.net/

追踪粉专可以收到文章的主动推播

https://ithelp.ithome.com.tw/upload/images/20210901/20120327NvpHVr2QC0.jpg


Backend 是初学 Terraform 的核心概念,本章节会简述 Backend,并介绍 Remote Backend 的原理。

上一讲 Day 03-Terraform State 之你的 Local State 不是我的 State 我们讨论 State 基本观念,了解 Terraform 是如何使用 State ,协助与远端 resource 的管理。

上堂课最後,我们也探讨使用 Local Backend,将 State 以 .tfstate 档案存放本机,各种优点与缺点。这里我们稍微回忆一下,Local Backend 的问题:

  • Local Backend 不支援多人协作,其他人无法存取本机的 .tfstate 档案,就无法正确操作 Terraform
  • State 内含敏感资料,.tfstate 档案并未加密,产生的资料是明码存放。也不宜上传 git 等版本管理工具
  • State 内含 Terraform lock,可以避免多人同时对相同 resource 一起 apply 变更,Local Backend 不支援多人协作,因舞也无法使用 lock 保护远端的 resource

这些问题该如何解决?是否有更适合多人协作的 Backend?

Terraform Backend

根据官方文件,Backend 主要的功能,就是

  • 储存 State 的资料,提供团队多人协作
  • 提供 State locking,避免多人同时修改

Terraform 整合许多 Backend 供使用这选择,这边简单介绍:

  • Terraform
    • local: 前两堂课使用的 local backend
    • remote: 官方提供,为 Terraform 订做的 terraform cloud 提供远端 State
      公有云
    • azurerm: 使用 Azure 的 Azure Storage 与 Blob 储存 State
    • gcs: 使用 Google Cloud Storage (GCS)
    • s3: 使用 AWS s3 储存 State
    • cos: 使用 Tencent Cloud Object Storage 储存 State
    • oss: 使用 Alibaba Cloud OSS
  • 其他第三方
    • artifactory: jfrog artifactory 上储存 State
    • swift: 使用 OpenStack Object Store
    • kubernetes: 使用 Kubernetes secret 储存
    • pg: 使用 Postgres database 储存
    • consul: 使用 hashicorp consul 储存 State
    • etcd, etcdv3: 使用 etcd 作为 State 储存

所有公有云提供的 Backend 实作原理近似,挑选熟悉的平台参照课程的步骤即可。至於如何选择适合的 Backend,互相比较与优缺点,稍後的课程再跟各位介绍。

本课程着重於公有云,使用 azurerm 作为范例。

Basic Azurerm Backend

这边讲解 Azurerm Backend 的基本观念,事实上非常单纯

基本的要求,是使用 azure storage 存放 .tfstate 档案,将放在本地的 .tfstate 放到 azure storage 上,团队成员只要使用 terraform 执行相同的 .tf 档案,Terraform 就可以自动取得远端 azure storage 中的 .tfstate,进行使用。

这边直接带大家实际使用

azurerm Backend configuration

设定,两个官方各提供一份说明文件

使用 azurerm storage 的前提

  • azure account & credential(az login)
  • azure subscription
  • azure storage account
  • azure storage container

前两者在第一堂课时我们就是先准备好,已经使用了。後面两个看起来十分眼熟?

没错,在前几堂课程的范例 resource,便已经带大家使用 Terraform 在 azure 产生这些 backend 所需的 resource。如果还没产生的同学,可以到这里来:

azure/_poc/foundation

需要的 resource 都在这里产生。使用 terraform output 便可以取得远端 resource 的资料参数。

cd _poc/foundation
terraform output

resource_group_name = "terraform-30-days-poc"
storage_account_name = "tfstate8b8bff248c5c60c0"
storage_container_name = "tfstate"

terraform with remote backend

之後新建的 .tf 资料夹,希望改用 azurerm backend,以 _poc/container_registry 为范例,使用 remote backend,在 provider.tf 的 terraform block 中,增加 backend {} block,依据 backend 文件 说明,填入在 _poc/foundation 中纤产生的参数。

terrform {
  backend "azurerm" {
    resource_group_name  = "terraform-30-days"
    storage_account_name = "tfstatee903f2ef317fb0b4"
    container_name       = "tfstate"
    key                  = "container_registry.tfstate"
  }
  ...
}

_poc/container_registry 内的 terraform {} 有设定使用 backend,terraform init 的时候便会使用

cd _poc/container_registry
terraform init

Initializing the backend...

Successfully configured the backend "azurerm"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding hashicorp/azurerm versions matching "~> 2.65.0"...
- Installing hashicorp/azurerm v2.65.0...
- Installed hashicorp/azurerm v2.65.0 (signed by HashiCorp)

Terraform has been successfully initialized!

以下的 plan 与 apply 的步骤都相同

terraform plan

terraform apply

在成功 apply 後,我们可以检查本地的档案,发现不再像之前有 .tfstate 档案产生了

ls -al

.terraform
.terraform.lock.hcl
provider.tf
registry.tf
variables.tf

parallel collaboration

我们参照上节课的范例,使用 _poc_container_registry_cloned 来模拟一下多人协作时,State 是如何运作的。

首先,_poc/container_registry_cloned 里面只有 soft link 档案。

cd _poc/container_registry_cloned
ls -al

provider.tf -> ../container_registry/provider.tf
registry.tf -> ../container_registry/registry.tf
variables.tf -> ../container_registry/variables.tf

init 後,本地产生 .terraform 资料夹,里头是 backend 的设定,以及最新从远端下载的 terraform.tfstate,内容是完整的 .tfstate 档案。

terraform init

Initializing the backend...
Successfully configured the backend "azurerm"! Terraform will automatically
use this backend unless the backend configuration changes.
Terraform has been successfully initialized!

ls -al 
.terraform
provider.tf -> ../container_registry/provider.tf
registry.tf -> ../container_registry/registry.tf
variables.tf -> ../container_registry/variables.tf

cat .terraform/terraform.tfstate

plan 与 apply 时,terraform 会自动将远端的 State 拉到本地快取。

terraform plan

No changes. Your infrastructure matches the configuration.

如此便可以在不同资料夹,甚至多台电脑上,只要透过 terraform.backend{} 的设定,找到远端的 State,就可以使用同一份 State 同时协作。

State locking

Azurerm backend 还有带 state locking 功能。每当有团队成员正在使用远端 state 的时候,terraform 会自动在 azurerm storage state 上面打上 lock,当另一位成员试图存取同一份 state 的时候,後来的成员的 terraform 指令会跳出 locked 讯息,并阻止 terraform 运作。

为何需要 state locking?

想像今天远端有一台 VM instance,团队成员 che 使用 terraform 修改 VM instance 的名称,同时另一位成员也恰好想更改同一台 VM,如果没有 state locking,两个更改 VM 的 API requests 都一起送到 azure 上,会发生什麽事情?

这就会产生无法预期的错误,要看网路速度,以及 azure 对多重 request 的处理了,可能是先来先赢,或是後来的 overwrite,或是 request 冲突导致 azure 回传错误;许多 request 修改 VM 需要时间,重复修改也可能会被公有云直接拒绝,...,这些情形都很有可能损坏远端的 resource。为了避免 apply conflict 发生,Terraform 使用 State locking

  • 成员 A 开始 terraform apply
  • Terraform 将远端 State 打上 lock uuid
  • 成员 A terraform apply VM update 费时两分钟,apply...
  • 成员 B 刚好也上来改 VM,terraform plan
  • 成员 B Terraform 试图存取 state 时,就会看到 State lock,知道不是当前本机的 lock,跳出警告,并中断 terraform 操作
Acquiring state lock. This may take a few moments...
Error locking state: Error acquiring the state lock: ConditionalCheckFailedException: The conditional request failed
Lock Info:
  ID:        86ea49f6-255d-074e-97d8-dcd0e8d6c250
  Path:      _poc/container_registry/terraform.tfstate
  Operation: apply
  Who:       chechia@chechias-MacBook
  Version:   1.0.1
  Created:   2021-07-29 13:13:27.894319 +0000 UTC
  Info:


Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.
  • 成员 B 知道有其他成员在操作,摸摸鼻子去喝咖啡
  • 成员 A 的 terraform apply 顺利完成,远端 VM 的状态更新成 A 期待的结果,terraform 确认动作完成,自动解锁 state lock
  • 成员 B 再次 terraform plan,refresh state 时就会发现远端 VM 已经变成 A 的形状
  • 成员 B 发现 state 有变,也知道其他成员改过 .tf 档案,执行 git pull A 的程序码,确保 .tf 档案是最新的
  • 成员 B 依据远端状态变更,在 .tf 档案做作相应调整
  • 成员 B 再次 terraform apply,完成工作

State locking 自动确保多人协作的工作流程是安全的,不会有 apply conflicts 发生。使用 terrform 宜尽量量使用支援 locking 的 backend。

Backend additional features

许多 backend 还有提供额外的功能,例如公有云的 storage,不管是 azure storage, aws s3, 或是 google storage 都有自己的附加功能,使用这些附加功能也能加强 terraform state 的管理。

例如我们可以进一步设定 azure storage

  • iam 存取控管,保护 state 资料
  • 搭配 azure vault,进行 state 自动加解密,避免明码档案储存
  • azure blob 也有档案版本控制功能,可以对不同版本的 state 进行管理,ex. 保存 20 个版本的 state

公有云提供的 storage 是最容使用且管理方便,其他 backend 各有各自特性,选择 backend 时宜多方比较。我们有空再谈 backend 的比较。

优劣

Azurerm vs local

  • 更方边的多人协作
  • state locking 保护
  • 费用: azurerm 是计价服务,依据档案容量与存旅游量计费,由於 .tfstate 档案并不会太大,使用公有云储存体是非常便宜
  • 其他加值功能,这部分我们之後有机会再做介绍

Source code

附上两个 Github Terraform 源码,由於 Backend 与 State 的功能并不复杂,里头也没有太过难的程序码,熟悉 golang 的朋友不妨快速看过,会对 Terraform 有更明确的了解。细节若稍後有篇幅我们再来细讲。

Homework

  • 尝试修改,plan,apply,destroy 下列 resource
    • _poc/container_registry
    • _poc/security_group
    • _poc/virtual_network
  • 透过 azure web console,container registry,使用 web console 更改,或是使用 terraform 更改设定
  • destroy 以下内容以节省费用,我们目前不会再用到。当然同学还是可以自由练习
    • _poc/container_registry
  • 选择另一个 backend,并阅读其说明文件
    • 如果手边取得 backend,则依照设定试着改用这个 backend
    • 如果有问题,欢迎与底下留言

Q&A

请问我需要在每个不同的资料夹都设定 terraform.backend 吗?感觉很不 DRY (don't repeat yourself)

没错,当使用 terraform 久了,很快就会发现这个问题,有没有可能精简 .tf 档案呢?请见下堂课。

References


<<:  Day 4 - hello world!!

>>:  Day 4 - 透过 RKE 架设第一套 Rancher(上)

[Python学习笔记] 文件I/O-Day2

读取键盘输入 input函数 读取和写入标准输入和输出 开启的txt档案会写入 程序中的"...

OpenStack Neutron 介绍 — OVN Plug-in 架构

本系列文章同步发布於笔者网站 上一篇讲述了 OVN Plug-in 在 OpenStack 中的参考...

20.移转 Aras PLM大小事-自制快速新增专案工作产出文件

在11sp12仍然有个问题,在代理商这边始终无法解决 因此又自行新增按钮来处理问题 1.在表单Act...

[Day 28] 建立注册的画面及功能(十二) - 寄出注册通知信

寄送会员通知信 Laravel基於SwiftMailer函式库开发了一套邮件套件, 可以支援多种服务...

Day 2 浮点运算及记忆体

今天先来谈一下浮点运算的问题,在ARMv8的架构下,主要还是依IEEE 754的规定来作运算标准,唯...