Day 02-是在 Hello?什麽都要 Hello 一下之 Hello Terraform

软功就是什麽都要 Hello 一下之 Hello terraform

这张就会开始动手做了,还没设定 terraform / cloud account 的请先看上一篇:Day 01-Workshop Azure Get-Started

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

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

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

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


本篇介绍 terraform 基本设定与操作指令,并使用 terraform 管理公有云上的 resource

这里指的 resources 有明确定义,底下会说明

Prerequisite

这个课程包含许多公有云上的 resource 范例,建议参与 workshop 的观众都要有 Azrue 的 account,取得Azrue account 设定方法在这边

如果是第一次使用公有云,或是想省一点钱的朋友,可以参考 Azure 公有云提供的 Free Tier 免费额度

Hello Azure

本课程主要以 Azure Cloud 为主要范例,然而不管使用哪做公有云,Terraform 操作的基本观念都类似

依照官方文件安装 Azure-cli

brew install azure-cli

az version

然後使用 az login,透过网页登入帐号,这个指令会在本机留下 azure 的 credential

az login

[{
    "cloudName": "AzureCloud",
    "homeTenantId": "1234567-my-home-tenant-id",
    "id": "1234567-my-id",
    "isDefault": true,
    "managedByTenants": [],
    "name": "my-subscription",
    "state": "Enabled",
    "tenantId": "1234567-my-tenant-id",
    "user": {
      "name": "my-email",
      "type": "my-user"
    }
}]
...

Auth to Azure

使用 terraform 管理 azure cloud 的 resources,自然 terraform 需要取得有效的 auth credentials,才能存取 Azure Cloud 的 API

  • 由於我们已经执行 az login,az-cli 会在预设的路径留下 credential (~/.azure/)
  • terraform azure provider 会搜寻预设的路径,使用 azure credential 管理远端公有云上的 resources
  • 可以看一下 az-cli 在本机留下什麽 登入资讯与 credentials
ls -al ~/.azure/

cat ~/.azure/azureProfile.json

Terraform content

在执行任何 terraform 程序码前 .tf 或 .hcl,我们先看一下内容

azure/_poc/foundation/ 为例

cd azure/_poc/foundation/

ls

main.tf
provider.tf
output.tf

三个 azure 的 resource,如果不熟的就需要查一下上面的官方文件。这边提供不精准的对照

  • azure / aws resource group ~= gcp project
  • azure storage container ~= aws s3 / gcp storage

上面是後续 terraform 会需要的 azure resource,这边尝试把他产生出来

First Terraform Command: terraform init

终於,执行第一个 terraform command,terraform init

terraform init

Initializing the backend...

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

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

所有 terraform module 要正确运作前都需要 init,init 做了许多事情,这边先看 log

Plan

参考文件的说明 terraform plan

简单说就是会 diff .tf 档案,以及 azure cloud 上面的实际内容,有落差会显示差异,然後输出变更计画。复杂的说我们大概第四天见 basic state

terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "southeastasia"
      + name     = "terraform-30-days"
    }

  # azurerm_storage_container.main will be created
  + resource "azurerm_storage_container" "main" {
      + container_access_type   = "private"
      + has_immutability_policy = (known after apply)
      + has_legal_hold          = (known after apply)
      + id                      = (known after apply)
      + metadata                = (known after apply)
      + name                    = "tfstate"
      + resource_manager_id     = (known after apply)
      + storage_account_name    = "tfstate"
    }
  ...

Plan: 3 to add, 0 to change, 0 to destroy.

────────────────────────────────────────────────────────────────────────────────────────────────────

main.tf 里面写了 4 个 resources,一个是 random id,另外三个是 azure resource。这边 terraform plan 的计画,认为应该要 create 三个物件。

Plan: 3 to add, 0 to change, 0 to destroy.

依据 .tf 与实际公有云上的 resource 差异,也有可能会有 change 或是 destroy

目前就先当作是,工程师写下想要的 .tf 状态,terraform 会帮你『多退少补』

Apply

Plan 之後,我们知道 terrform 计画的结果,如果与我们想得符合(ex. 3 to add plan 符合我们的预期),表示 .tf 与 plan 没有问题,这时就可以使用 terraform apply 真的把 request 送到 Azure 上,产生我们缺少的 resource

terraform apply

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

重点:养成好习惯,一定要把 apply 的内容仔细看完,再输入 yes。不看直接 apply 会遭到第一天引言所说的报应

NOTE: Always double check before type yes.

Terraform local files

apply 下去,会需要一些时间,terraform 会回报已经花费的时间。

执行完成後,可以观察到两件事

  • 透过 azure web console 可以看到真的有 resource group, storage account, ... 物件产生出来
    • 这是我们想要完成的工作:透过 terraform 管理远端的 azure 物件,成功!
  • 本地的 azure/_poc/foundation/ 资料夹下多了一些东西

这边看一下 terraform 在本地留下什麽东西

ls -al

drwxr-xr-x  .terraform
-rw-r--r--  .terraform.lock.hcl
-rw-r--r--  main.tf
-rw-r--r--  output.tf
-rw-r--r--  terraform.tfstate
-rw-r--r--  terraform.tfstate.backup

这些档案对 terraform 都有不同功能,我们预设会把这些档案隐藏,并且 gitignore。在现阶段我们只要知道 terraform apply 完後在本地产生一些东西。

plan again

既然 apply 完成,我们可以在 terraform plan 一次看看,会产生出什麽计画

terrafrom plan

...
Plan: 0 to add, 0 to change, 0 to destroy.

这表示目前的 azure/_poc/foundation/ 资料辖下的 .tf 内容,与远端的 azure 上的 resource 是相同的

  • 远端的状态是我们想要控制达成的状态
  • 见 code 如见人,不用上云看

Potential Error: name is already taken

这边有个常见错误先提醒:azrue storage account 的名称是 global unique,(~所以要抢 id~),命名有冲突的话, terraform API 发到 Azure 上,Azure 会回传 error

╷
│ Error: Error creating Azure Storage Account "tfstate": storage.AccountsClient#Create: Failure sending request: StatusCode=0 -- Original Error: autorest/azure: Service returned an error. Status=<nil> Code="StorageAccountAlreadyTaken" Message="The storage account named tfstate is already taken."
│
│   with azurerm_storage_account.main,
│   on storage_account.tf line 1, in resource "azurerm_storage_account" "main":
│    1: resource "azurerm_storage_account" "main" {
│
╵

请使用低碰撞机率的命名

细节请 google terraform azure storage account

Hashicorp doc: storage account,的参数有描述说明

name - (Required) Specifies the name of the storage account. Changing this forces a new resource to be created. This must be unique across the entire Azure service, not just within the resource group.

3 steps Terraform

terraform 三步骤

  • init
  • plan
  • apply

基本 debug 三步骤

  • 读 azure cloud 文件
  • 读 hashicorp resource 文件
  • retry

养成查文件的习惯,不只是 terraform 需要,想要熟悉 public cloud infrastructure 都要时常查找文件

About random

resource random id 後续课程有机会再聊

Remove Storage Container

接下来尝试 destroy 所有刚刚产生的 resource

  • 使用最爱的编辑器,更改
  • 在所有 resource block {} 前面在加 comment,或是直接删除
vim azure/foundation/main.tf

...
#resource "azurerm_storage_container" "main" {
#  name                  = "tfstate"
#  storage_account_name  = azurerm_storage_account.main.name
#  container_access_type = "private"
#}
...

然後我们再次 plan 这个 directory 的 module

terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_storage_container.main will be destroyed
  - resource "azurerm_storage_container" "main" {
      - container_access_type   = "private" -> null
      - has_immutability_policy = false -> null
      - has_legal_hold          = false -> null
      - id                      = "https://tfstatef4380b8b1152083e.blob.core.windows.net/tfstate" -> null
      - metadata                = {} -> null
      - name                    = "tfstate" -> null
      - resource_manager_id     = "/subscriptions/6fce7237-7e8e-4053-8e7d-ecf8a7c392ce/resourceGroups/terraform-30-days/providers/Microsoft.Storage/storageAccounts/tfstatef4380b8b1152083e/blobServices/default/containers/tfstate" -> null
      - storage_account_name    = "tfstatef4380b8b1152083e" -> null
    }

Plan: 0 to add, 0 to change, 3 to destroy.

terraform 的计画显示想要 destroy 3 个物件

Plan: 0 to add, 0 to change, 3 to destroy.

这边注意:

  • 我们确实是想要删除远端 resource,所以把 main.tf 里面的 resource block {} 删除
  • 确定是我们要的结果,并且仔细检查 destroy 掉的 resource 内容
  • 才执行 terraform apply

destroy 的时候永远 double check,很多infrastructure destroy 掉,就是『趴!没了!』,例如前言所提到的 database

  • 删掉 infrastructure 有可能会影响其他 infrastructure,如果彼此有依赖关系的话
    • ex. 删除 storage account 同时也会让 storage container 失效,要格外注意
    • 正确使用 terraform 可能可以帮你预测这些依赖性的效果

确认後就放心 apply

terraform apply

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

一样需要花飞一点时间,让 Azure destroy resource

  • 完成後去 azure web console 检查,3 个 azure resouces 都删除了

Resources

这边提到的 resources 在官方文件中也有明确的定义,有几个不同面向

  • 一个是本地 .tf 中的 resource 描述,是 hcl 语言。细节大约是在第 14 天左右会说明
  • 先当作一个一个 resource block {}
  • 一个是远端实际的 azure resource / 或说是 azure object,例如一个 resource group / 一个 VM / 一个 VM

resource 的行为由 provider 定义,azurerm provider 就定义:如何把 .tf resource 变成 azure resource 的 API request,丢到 Azure 上去,产生 resource

Directory Structure

看一下资料夹结构

tree -L 1 azure
azure
├── KNOWN_ISSUES.md
├── _poc
├── dev
├── env.tfvars
├── foundation
├── modules
├── prod
├── stag
├── terragrunt.hcl
└── test

7 directories, 3 files

terraform plan 预设会以一个 directory 作为 root module,

  • 使用高阶程序语言比喻,可能是程序进入点的概念

我们刚开始会使用 _poc 的内容做示范,只是为了展示 terraform 功能,之後会把 _poc 内的 resource 全部移除

底下这些则是依照不同环境切分的资料夹,是 terragrun 官方建议的资料夹结构,我们在第 7-8 天左右会细讲

  • foundation
  • dev
  • stag
  • prod

Homework

Now, try the following practice

  1. 增加一个全新的 storage container resource block,也就是说 apply 玩会有两个 storage container
  2. 另外找一个 azure/poc 内的资料夹来 init, plan, apply 看看
  3. 尝试更改 resource block {} 里面的参数 variables,例如 name, ...等等设定
  4. 检查 local state 档案
  • 使用最爱的编辑器,打开 terraform.tfstate 档案看看内容
  • 执行 terraform destroy
  • destroy 後,再次检查 terraform.tfstate 的内容

Summary

第二天,我们跟 terraform 説 hello。目前为止我们知道

  • terraform 以某种机制 sync
    • 本地 .tf 内容的描述
    • 远端 azure cloud 的实际 resource
  • terraform 会在 plan 结果显示
    • add, change, 或 destroy
    • 多退少补
  • Terraform 宣告式的 declarative 描述 resource block
  • provider 会处理实际 sync 的这个行为
  • 养成好习惯:每次 apply 都 double check

<<:  Day 02 HTML<表格标签>

>>:  Day-1 开始玩怀旧游戏机的事前准备导览篇

透过 Composer 安装、更新、移除 PHP 套件或框架(PHP, Composer套件管理)

之前有打过一篇文章 透过 npm 安装和指定版本、更新和指定版本、移除套件 介绍 node 的套件管...

【Day05】Data Flow 与 State

Data Flow 中文直译为资料流, React 中文圈通常说法是 单向资料流/单一资料流, 如字...

【第十六天 - 动态规划 介绍】

Q1. 动态规划(Dynamic Programming)是什麽 ? Dynamic program...

Day 6 - 原型 (5): 帖子页的元件组合

前言 利用刚设计好的帖子页元件, 组合成帖子页。 元件组合 建立一个属於帖子页的frame 先在Pa...

Day 17 - SwiftUI开发学习1(按钮)

我们统整一下前16天的内容,我们花了很多的时间学习swift语言的基本,学完语言之後我们要开始进入到...