Day 14 Terraform import resource

我們進到 IaC 的世界了~那…前面在 AWS 手動建立的各種 resource 怎麼辦?

有兩個選項:

  1. 全部砍掉重新用 terraform 寫!

  2. 把手動建立的 resource import 進 terraform

哪個比較容易呢……?

不好說。

重新用 terraform 寫就要查 terraform resource 的 reference,一點一點把前面手動建立的東西寫出來跟測試,就是用 terraform 把前面做的事情再做一次。這個作法容易踩到的問題是除非了解 AWS web console 幫你做了什麼,不然會在找到對應的 resource 及設定上花不少時間。好處是這樣寫出來並且測試過的 terraform configuration 往往不會有太大問題。

import 是你把現有會動的 resource import 進 terraform,好處是可以保留已經會動的 infrastructure(有時候就是會有各種原因例如宇宙射線太強所以我們不能砍掉重來…),問題是可能以為已經 import 完所有 resource,但實際還是有缺,到了新的乾淨環境才發現怎麼這個不會動、那個不會動的東缺西缺。

這邊筆者用 import 把前面手動建立的 infrastructure 加進 terraform,之後就能用 terraform 繼續修改 cloud resource。(其實是以為 import 比較簡單,結果根本沒有。)

Terraform 1.5 import block

terraform 在 1.5 版推出 import block 功能,可以用 import block 來定義要 import 的 resource,還會自動產生 terraform configuration!

沒這個功能前,要 import 手動建立的 resource 都要先寫出 resource block ⇒ 用 terraform import ⇒ plan 看差異 ⇒ 手動補上 resource block 的參數 ⇒ 直到沒有 changes(說是沒有 changes 但有時候還是可能被 default value 陰到)

1.5 推出 import block 後,可以把 import resource 的操作合併進 plan/apply 的流程,而且不用在那裡用 plan 看差異、補參數。雖然還是會遇到一些 error,但整體來說比原本的 import 方式好多了~

接下來讓我們把前面手動建立的 resource 們都 import 進來吧!

Import ECR repository

先定義 import block,syntax 如下:

1
2
3
4
import {
id = [resource 在 cloud 上的 identifier]
to = [terraform 內 resource 的 id]
}

我們從 ECR repository 開始,id 是 resource 在 cloud 上的 identifier,每種 resource 都不一樣,這裡要參考 resource 文件 aws_ecr_repository 中的 import。ECR repository 的 id 是它的名稱,也就是 my-app

1
2
3
4
import {
to = aws_ecr_repository.repo
id = "my-app"
}

import block 的 to 則是打算產生的 resource block 跟它在 terraform 裡的 id,這邊我們 import 的是 aws_ecr_repository 並且把它的 resource id 訂為 repo

接下來用 plan 指令產生要 import 的 resource 的 configuration:

1
$ terraform plan -generate-config-out=generated.tf

執行後會看到這樣的畫面:

image.png

產生的 configuration 會在 generated.tf 裡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform from "my-app"
resource "aws_ecr_repository" "repo" {
force_delete = null
image_tag_mutability = "MUTABLE"
name = "my-app"
tags = {}
tags_all = {}
encryption_configuration {
encryption_type = "AES256"
kms_key = null
}
image_scanning_configuration {
scan_on_push = false
}
}

把它搬到 main.tf ,現在 main.tf 長這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = "~> 1.5"
}

provider "aws" {
profile = "my"
region = "ap-northeast-1"
}

import {
id = "my-app"
to = aws_ecr_repository.repo
}

resource "aws_ecr_repository" "repo" {
force_delete = null
image_tag_mutability = "MUTABLE"
name = "my-app"
tags = {}
tags_all = {}
encryption_configuration {
encryption_type = "AES256"
kms_key = null
}
image_scanning_configuration {
scan_on_push = false
}
}

接著正式 import:

1
$ terraform apply

看到熟悉的畫面,terraform 準備 import:

image 1.png

輸入 yes 後 resource 順利 import:

image 2.png

我們可以用 terraform plan 查看目前的 terraform configuration 跟 AWS 上的 infrastructure 有沒有什麼不同:

image 3.png

兩邊是一致的!

這就是用 import block 進行 import resource 跟產生 terraform configuration 的方式,接下來我們要把所有前面我們手動建立的 resource 都 import 進來。