import ECR repository 後,我們要把 application 有關的 resource 全部 import、改由 terraform 管理。執行 Gitlab Runner 以及單純用來實驗的 MySQL server 的 EC2 instance 不在 import 範圍內,因為它們屬於輔助實驗才產生的 infrastructure,對 application 來說非必要,在不同環境與情境中可能會使用其他方式運行 Gitlab runner 跟 Database。
在 import 跟撰寫 terraform configuration 時,terraform 的 aws resource reference 是好夥伴,我們會在 import 需要知道 id(cloud 上真實 resource 的 identifier,不是 terraform resource id)是什麼、寫 configuration 時查閱有哪些參數可用…等等。
今天我們會先 import 跟網路有關的 resource,分別是 VPC、Subnet、Internet Gateway 以及 Route Table 相關 的 resource。(原本想一口氣把所有 resource import 進來的飛速前進,結果馬上踩到問題,只好一個個慢慢來…)
VPC
1 2 3 4
| import { to = aws_vpc.vpc id = "vpc-04828d35609756ab9" }
|
得到 generated configuration(註:筆者寫此系列文時 configuration generation 的功能還在實驗中,可能後續 syntax 會有所修改):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| resource "aws_vpc" "vpc" { assign_generated_ipv6_cidr_block = false cidr_block = "172.16.0.0/16" enable_dns_hostnames = false enable_dns_support = true enable_network_address_usage_metrics = false instance_tenancy = "default" ipv4_ipam_pool_id = null ipv4_netmask_length = null ipv6_cidr_block = null ipv6_cidr_block_network_border_group = null ipv6_ipam_pool_id = null ipv6_netmask_length = 0 tags = { Name = "my-app" } tags_all = { Name = "my-app" } }
|
附帶 planning failed :)

一樣先把 generated configuration 搬到 main.tf
,接著看看 error 說些什麼?
看起來跟 IPv6 有關,但…我們又沒有要用 IPv6,把相關的參數都刪掉好了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| resource "aws_vpc" "vpc" { assign_generated_ipv6_cidr_block = false cidr_block = "172.16.0.0/16" enable_dns_hostnames = false enable_dns_support = true enable_network_address_usage_metrics = false instance_tenancy = "default" ipv4_ipam_pool_id = null ipv4_netmask_length = null tags = { Name = "my-app" } tags_all = { Name = "my-app" } }
|
再 plan 看看,耶!過了~那我們就直接 apply 把 vpc import 進來。
Subnets
import block:
1 2 3 4 5 6 7 8 9
| import { to = aws_subnet.public_1a id = "subnet-02fbb0ca0bf2d6438" }
import { to = aws_subnet.public_1c id = "subnet-0d219822dd60f4f83" }
|
產生出的 configuration:
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| resource "aws_subnet" "public_1a" { assign_ipv6_address_on_creation = false availability_zone = "ap-northeast-1a" availability_zone_id = "apne1-az4" cidr_block = "172.16.0.0/24" customer_owned_ipv4_pool = null enable_dns64 = false enable_lni_at_device_index = 0 enable_resource_name_dns_a_record_on_launch = false enable_resource_name_dns_aaaa_record_on_launch = false ipv6_cidr_block = null ipv6_native = false map_customer_owned_ip_on_launch = false map_public_ip_on_launch = true outpost_arn = null private_dns_hostname_type_on_launch = "ip-name" tags = { Name = "my-app-public-1a" } tags_all = { Name = "my-app-public-1a" } vpc_id = "vpc-04828d35609756ab9" }
resource "aws_subnet" "public_1c" { assign_ipv6_address_on_creation = false availability_zone = "ap-northeast-1c" availability_zone_id = "apne1-az1" cidr_block = "172.16.1.0/24" customer_owned_ipv4_pool = null enable_dns64 = false enable_lni_at_device_index = 0 enable_resource_name_dns_a_record_on_launch = false enable_resource_name_dns_aaaa_record_on_launch = false ipv6_cidr_block = null ipv6_native = false map_customer_owned_ip_on_launch = false map_public_ip_on_launch = false outpost_arn = null private_dns_hostname_type_on_launch = "ip-name" tags = { Name = "my-app-public-1c" } tags_all = { Name = "my-app-public-1c" } vpc_id = "vpc-04828d35609756ab9" }
|
還是出現 error…QQ

看有什麼 error 就修正什麼,這邊我是刪掉兩個 subnet 的 availability_zone_id
、enable_lni_at_device_index
跟 map_customer_owned_ip_on_launch
。
Internet Gateway
import block:
1 2 3 4
| import { to = aws_internet_gateway.igw id = "igw-01bd114b2559c0d00" }
|
太好了,internet gateway 沒有 error,繼續 import。(沒有出現 error 的 import,筆者可能就不放 generated code 了)
Route Table
main route table 的 import block:
1 2 3 4
| import { to = aws_default_route_table.main id = "vpc-04828d35609756ab9" }
|
也沒有 error,持續 import,但看著 route 是空 array 有點小擔心……不過 terraform plan 也沒有說有 changes 就先繼續吧。
public route table 及其 route 們的 import block:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { to = aws_route_table.public id = "rtb-083e58a57744577c7" }
import { to = aws_route.internal id = "rtb-083e58a57744577c7_172.16.0.0/16" }
import { to = aws_route.internet id = "rtb-083e58a57744577c7_0.0.0.0/0" }
|
generated configuration:
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| resource "aws_route_table" "public" { propagating_vgws = [] route = [{ carrier_gateway_id = "" cidr_block = "0.0.0.0/0" core_network_arn = "" destination_prefix_list_id = "" egress_only_gateway_id = "" gateway_id = "igw-01bd114b2559c0d00" ipv6_cidr_block = "" local_gateway_id = "" nat_gateway_id = "" network_interface_id = "" transit_gateway_id = "" vpc_endpoint_id = "" vpc_peering_connection_id = "" }] tags = { Name = "my-app-rt-public" } tags_all = { Name = "my-app-rt-public" } vpc_id = "vpc-04828d35609756ab9" }
resource "aws_route" "internet" { carrier_gateway_id = null core_network_arn = null destination_cidr_block = "0.0.0.0/0" destination_ipv6_cidr_block = null destination_prefix_list_id = null egress_only_gateway_id = null gateway_id = "igw-01bd114b2559c0d00" local_gateway_id = null nat_gateway_id = null network_interface_id = null route_table_id = "rtb-083e58a57744577c7" transit_gateway_id = null vpc_endpoint_id = null vpc_peering_connection_id = null }
resource "aws_route" "internal" { carrier_gateway_id = null core_network_arn = null destination_cidr_block = "172.16.0.0/16" destination_ipv6_cidr_block = null destination_prefix_list_id = null egress_only_gateway_id = null gateway_id = "local" local_gateway_id = null nat_gateway_id = null network_interface_id = null route_table_id = "rtb-083e58a57744577c7" transit_gateway_id = null vpc_endpoint_id = null vpc_peering_connection_id = null }
|
出現了 error:

terraform 幫我們在 aws_route_table.public
resource 的 route
產生了 route 相關的 configuration,但是我們已經有另外 import route resource aws_route.internet
跟 aws_route.internal
了,這兩種 route 的定義方式不能混用 (ref),所以刪掉 aws_route_table.public
裡 route
。
Route table 與 subnet 的 association
沒錯!route table 跟 subnet 之間的 association 關係也是個 resource,寫 IaC 的其中一個困難是 resource 可能拆得很細,遺漏一些細部的 resource 的話它就……不會動。至於要怎麼知道有這麼多細部的 resource?筆者對於不熟悉的服務通常會先看 terraform resource reference 的 example,example 常常有常用的 scenario 可以參考。再來是 terraform 寫完後嘗試用同一份 code 再建立一次新的 infrastructure,看看整個運作是否如預期,不如預期通常是因為缺 resource。
route table 與 subnet 的 association 的 import block:
1 2 3 4 5 6 7 8 9
| import { to = aws_route_table_association.public_1a id = "subnet-02fbb0ca0bf2d6438/rtb-083e58a57744577c7" }
import { to = aws_route_table_association.public_1c id = "subnet-0d219822dd60f4f83/rtb-083e58a57744577c7" }
|
generated configuration:
1 2 3 4 5 6 7 8 9 10 11
| resource "aws_route_table_association" "public_1a" { gateway_id = null route_table_id = "rtb-083e58a57744577c7" subnet_id = "subnet-02fbb0ca0bf2d6438" }
resource "aws_route_table_association" "public_1c" { gateway_id = null route_table_id = "rtb-083e58a57744577c7" subnet_id = "subnet-0d219822dd60f4f83" }
|
把 main.tf 拆成多個 .tf
隨著 import 的 resource 越來越多,main.tf
也越來越龐大。terraform 不只可以在 main.tf
放 resource,在工作目錄下的 .tf
檔案都可以寫 resource。之後還會 import 更多 resource,我們先把網路相關的 resource 都移到 network.tf
。