Terraformで既存のインフラリソースをインポートする方法
目次
インフラエンジニアの寺岡です。
皆さんは「既存のインフラ構成もTerraformで管理できるようにしたい」と考えたことはないでしょうか。
Terraformではそれを実現するコマンドが用意されているのでこの記事で紹介します。
事前にTerraformを利用せずにVPCを1つ作成しておきました。
今回はこちらをTerraformにインポートしてみます。
ディレクトリ構成
$ tree . ├── README.md ├── provider.tf ├── terraform.tfstate ├── variables.tf └── vpc.tf 0 directories, 5 files
providerとvariableを記述する
インポートする前にproviderとvariableは最低限必要なので記述します。
provider.tf
provider "aws" { access_key = var.access_key secret_key = var.secret_key region = var.region assume_role { role_arn = var.role_arn } }
variables.tf
#################### # Provider #################### variable "access_key" { description = "AWS Access Key" } variable "secret_key" { description = "AWS Secret Key" } variable "role_arn" { description = "AWS Role Arn" } variable "region" { default = "ap-northeast-1" }
AWSのアクセスキーなどは環境変数に保存しておきましょう。
$ export TF_VAR_access_key=XXXXXXXXXXXXXXXXXXXX $ export TF_VAR_secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $ export TF_VAR_role_arn=arn:aws:iam::XXXXXXXXXXXX:role/XXXXXXXXXXXXXXXXXXX
planを実行する
試しにPlanを実行します。
今は何もインポートしていないので「No changes.」で実行が終わります。
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
importを実行する
Terraformで既存リソースをインポートする場合は「terraform import」コマンドを実行します。
コマンドの書式はTerraformのマニュアル(※1)に記載があるのでそちらを参考にして以下のコマンドを実行します。
$ terraform import aws_vpc.vpc vpc-09a9f1827bfd851f4 Error: resource address "aws_vpc.vpc" does not exist in the configuration. Before importing this resource, please create its configuration in the root module. For example: resource "aws_vpc" "vpc" { # (resource arguments) }
エラーが出てしまいました。
インポートするときは「aws_vpc.vpc」のようにリソースの種類と名前を指定することになり
ここで指定したtfファイル上のリソースに対して既存リソースの情報がインポートされることになります。
そのため、予め対応するリソースをtfファイルに記述しておく必要があります。
vpcリソースを記述する
以下のように記載しておきます。
vpc.tf
#################### # VPC #################### resource "aws_vpc" "vpc" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "vpc-tfstate-test" } }
再度importを実行する
再度実行してみます。
今度は問題なくインポートできましたね。
$ terraform import aws_vpc.vpc vpc-09a9f1827bfd851f4 aws_vpc.vpc: Importing from ID "vpc-09a9f1827bfd851f4"... aws_vpc.vpc: Import prepared! Prepared aws_vpc for import aws_vpc.vpc: Refreshing state... [id=vpc-09a9f1827bfd851f4] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
このterraform importは何をやってくれているのでしょうか。
コマンドを実行すると「terraform.tfstate」という名前のファイルが作成されていることがわかります。
terraform.tfstate
{ "version": 4, "terraform_version": "0.12.24", "serial": 1, "lineage": "c0359eb1-d905-e252-2d8d-525710adddb1", "outputs": {}, "resources": [ { "mode": "managed", "type": "aws_vpc", "name": "vpc", "provider": "provider.aws", "instances": [ { "schema_version": 1, "attributes": { "arn": "arn:aws:ec2:ap-northeast-1:485076298277:vpc/vpc-09a9f1827bfd851f4", "assign_generated_ipv6_cidr_block": false, "cidr_block": "10.0.0.0/16", "default_network_acl_id": "acl-0cd8abfed52e0e951", "default_route_table_id": "rtb-08c13269b1b26c9b8", "default_security_group_id": "sg-007ef29e563b6f9c7", "dhcp_options_id": "dopt-6c0f430b", "enable_classiclink": false, "enable_classiclink_dns_support": false, "enable_dns_hostnames": true, "enable_dns_support": true, "id": "vpc-09a9f1827bfd851f4", "instance_tenancy": "default", "ipv6_association_id": "", "ipv6_cidr_block": "", "main_route_table_id": "rtb-08c13269b1b26c9b8", "owner_id": "485076298277", "tags": { "Name": "vpc-tfstate-test" } }, "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" } ] } ] }
中身を見ると先ほどインポートしたリソースの情報が保存されていますね。
Terraformは実行したときに新規作成 or 変更 or 削除を自動で判断してリソースを作成してくれますが
この判断は実行時に読み込んだtfファイルとtfstateに書かれている内容の差分を元に行われています。
つまり、指定した既存リソースをTerraform上で管理するためにはtfstateの内容を変更する必要があり
「指定した既存リソースの情報を読み込みtfstateに追加してくれるコマンド」がterraform importです。
再度planを実行する
terraform importを実行したので再度planを実行してみましょう。
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.vpc: Refreshing state... [id=vpc-09a9f1827bfd851f4] ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
aws_vpc.vpcがTerraform上のリソースとして読み込まれていますね。
enable_dns_hostnamesをfalseに変更してみましょう。
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.vpc: Refreshing state... [id=vpc-09a9f1827bfd851f4] ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # aws_vpc.vpc will be updated in-place ~ resource "aws_vpc" "vpc" { arn = "arn:aws:ec2:ap-northeast-1:485076298277:vpc/vpc-09a9f1827bfd851f4" assign_generated_ipv6_cidr_block = false cidr_block = "10.0.0.0/16" default_network_acl_id = "acl-0cd8abfed52e0e951" default_route_table_id = "rtb-08c13269b1b26c9b8" default_security_group_id = "sg-007ef29e563b6f9c7" dhcp_options_id = "dopt-6c0f430b" enable_classiclink = false enable_classiclink_dns_support = false ~ enable_dns_hostnames = true -> false enable_dns_support = true id = "vpc-09a9f1827bfd851f4" instance_tenancy = "default" main_route_table_id = "rtb-08c13269b1b26c9b8" owner_id = "485076298277" tags = { "Name" = "vpc-tfstate-test" } } Plan: 0 to add, 1 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
差分のみを変更しようとする挙動になっていますね。
まとめ
importコマンドの説明ページ(※2)にも記載されていますが
コマンドで書き換えてくれるのはあくまで「tfstateのみ」です。
つまり、実際のtfファイルについてはtfstateとの差分を見ながら自身で記述する必要があります。
将来的にはtfファイルも自動生成されるように機能追加されるようですが
現在のところは対象が多ければ多いほど辛くなってきます。。。
それを解決するためにterraformer(※3)がOSSとして公開されています。
次回はこちらの使い方をブログにまとめようと思います。
参考URL
※1 https://www.terraform.io/docs/providers/aws/r/vpc.html
※2 https://www.terraform.io/docs/import/index.html
※3 https://github.com/GoogleCloudPlatform/terraformer