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 進來的飛速前進,結果馬上踩到問題,只好一個個慢慢來…)
import {
to = aws_vpc.vpc
id = "vpc-04828d35609756ab9"
}
得到 generated configuration(註:筆者寫此系列文時 configuration generation 的功能還在實驗中,可能後續 syntax 會有所修改):
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,把相關的參數都刪掉好了:
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 進來。
import block:
import {
to = aws_subnet.public_1a
id = "subnet-02fbb0ca0bf2d6438"
}
import {
to = aws_subnet.public_1c
id = "subnet-0d219822dd60f4f83"
}
產生出的 configuration:
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
。
import block:
import {
to = aws_internet_gateway.igw
id = "igw-01bd114b2559c0d00"
}
太好了,internet gateway 沒有 error,繼續 import。(沒有出現 error 的 import,筆者可能就不放 generated code 了)
main route table 的 import block:
import {
to = aws_default_route_table.main
id = "vpc-04828d35609756ab9"
}
也沒有 error,持續 import,但看著 route 是空 array 有點小擔心……不過 terraform plan 也沒有說有 changes 就先繼續吧。
public route table 及其 route 們的 import block:
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:
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 關係也是個 resource,寫 IaC 的其中一個困難是 resource 可能拆得很細,遺漏一些細部的 resource 的話它就……不會動。至於要怎麼知道有這麼多細部的 resource?筆者對於不熟悉的服務通常會先看 terraform resource reference 的 example,example 常常有常用的 scenario 可以參考。再來是 terraform 寫完後嘗試用同一份 code 再建立一次新的 infrastructure,看看整個運作是否如預期,不如預期通常是因為缺 resource。
route table 與 subnet 的 association 的 import block:
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:
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"
}
隨著 import 的 resource 越來越多,main.tf
也越來越龐大。terraform 不只可以在 main.tf
放 resource,在工作目錄下的 .tf
檔案都可以寫 resource。之後還會 import 更多 resource,我們先把網路相關的 resource 都移到 network.tf
。