この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちわ、ネクストモードの島川です。
terraform import
を使って、for_eachで書いたものをそのままimportする方法を紹介します。既存環境をコード化したいけど、ベタ書きは嫌!なるべくスマートに書きたい。という方に向けた記事です。
環境
$ terraform -v
Terraform v1.0.0
せっかくなので最近リリースされたv1.0.0を使用します。
importする際に必要な情報
基本的なことになりますが、terraform import
をする際に必要な情報はユーザーが定義したname
であったり自動生成されたid
になります。実際のリソースの種類によって変わるのでそこは事前にTerraformのドキュメントを参照してください。
ちなみにAWSのEC2であればインスタンスIDがimportの際に必要な情報になります。(例:i-12345678)
ドキュメントはここ
importする
AWSのEC2をimportする例を今回は紹介します。
for_each
tfファイルの準備
まずはimportするためのtfファイルを書いていきます。分かるのであれば最初から情報を埋めてもいいですし、分からないのであればリソース定義だけしておくでも大丈夫です。今回はリソースの定義だけ最初にしておいてあとから埋める方法で進めようと思います。
- import前のコードの状況
main.tf
locals { ec2_name = { hoge-server-1 = { instance_type = "t3.micro" ami = "ami-xxxxxxxxxx" }, hoge-server-2 = { instance_type = "t2.micro" ami = "ami-xxxxxxxxxx" } } } resource "aws_instance" "foo" { for_each = local.ec2_name }
for_eachをimportする
terraform import
コマンドを使ってimportしていきます。for_eachのリソースは「リソースの種類.リソース名["配列名"]」で表されます。今回の場合は以下のように表すことができます。
- aws_instance.foo["hoge-server-1"]
- aws_instance.foo["hoge-server-2"]
インスタンスIDを確認したのち、実際にimportをしていきます。一点だけ注意点があり、UNIX系OSの場合は要素全体を''
シングルクォーテーションで囲んであげる必要があります。
- 参考
$ terraform import 'aws_instance.foo["hoge-server-1"]' i-1111122222
$ terraform import 'aws_instance.foo["hoge-server-2"]' i-aaaaabbbbb
成功するとこんな表示がでます。
aws_instance.foo["hoge-server-1"]: Importing from ID "i-1111122222"...
aws_instance.foo["hoge-server-1"]: Import prepared!
Prepared aws_instance for import
aws_instance.foo["hoge-server-1"]: Refreshing state... [id=i-1111122222]
importされた内容を確認する。
まずはterraform state list
でリソースがあるか確認します。
$ terraform state list
aws_instance.foo["hoge-server-1"]
aws_instance.foo["hoge-server-2"]
次にterraform state show
で中身を確認していきます。ここでも要素全体を''
シングルクォーテーションで囲む必要があります。
$ terraform state show 'aws_instance.foo["hoge-server-1"]'
# aws_instance.foo["hoge-server-1"]:
resource "aws_instance" "foo" {
ami = "ami-xxxxxxxxxx"
arn = "arn:aws:ec2:ap-northeast-1:123456789123:instance/i-xxxxxxxxxx"
associate_public_ip_address = false
availability_zone = "ap-northeast-1a"
cpu_core_count = 1
cpu_threads_per_core = 2
disable_api_termination = false
ebs_optimized = true
get_password_data = false
hibernation = false
id = "i-xxxxxxxxxx"
instance_initiated_shutdown_behavior = "stop"
instance_state = "stopped"
instance_type = "t3.micro"
ipv6_address_count = 0
ipv6_addresses = []
key_name = "ec2keyname"
monitoring = false
primary_network_interface_id = "eni-xxxxxxxxxxxx"
private_dns = "ip-10-210-10-67.ap-northeast-1.compute.internal"
private_ip = "10.210.10.67"
secondary_private_ips = []
security_groups = []
source_dest_check = true
subnet_id = "subnet-xxxxxxxxxxxx"
tags = {
"Name" = "hoge-server"
}
tags_all = {
"Name" = "hoge-server"
}
tenancy = "default"
vpc_security_group_ids = [
"sg-xxxxxxxxxxxx",
]
capacity_reservation_specification {
capacity_reservation_preference = "open"
}
credit_specification {
cpu_credits = "standard"
}
enclave_options {
enabled = false
}
metadata_options {
http_endpoint = "enabled"
http_put_response_hop_limit = 1
http_tokens = "optional"
}
root_block_device {
delete_on_termination = true
device_name = "/dev/xvda"
encrypted = true
iops = 100
kms_key_id = "arn:aws:kms:ap-northeast-1:123456789123:key/xxxxxxxxxxxx"
tags = {
"Name" = "hoge-server"
}
throughput = 0
volume_id = "vol-xxxxxxxxxxxxx"
volume_size = 20
volume_type = "gp2"
}
timeouts {}
}
.tfファイルを書き足していく
このままterraform plan
をしても必要最低限の情報が無いため失敗します。また必要最低限のamiやinstance typeを追記してもその他の情報がないためインスタンスを作り直す動きをしてしまいます。そのためterraform state show
の内容を元に.tfを書き足していく必要があります。サブネット情報等も必要になるので場合によってはそこからimportをかけていく必要もあります。
まとめ
$ terraform import 'リソースの種類.リソース名["要素名"]' リソース識別子
で、for_each形式の状態でimportすることができます。同じ要領でcountやmoduleもimportすることができます。terraformで作成されたリソースの完全名を把握しておくことが大事です。またこのimportの注意点として本来であれば自動で生成されるはずだったリソースに関しても.tfに記述していくことになりますので、結構時間がかかります。terraformerというツールもありますので、for_eachじゃなくてベタ書きでもいいという場合はその選択肢も考えてみてください。