手動で構築したやつもterraform化したい!
そんな願いを叶えるのがimport。
例えばcloudfrontの設定を1からコード化するのは非常に……
辛い汗
ならば一旦手動で作り、からのimportして相違直して、
あとで変数化すれば工数が圧倒的に少ない!
というわけで今回は既存にあるインスタンスをterraform化してみます。
・追記
v0.10.1からtfstateファイルをbackendで管理している場合、
自動的にs3に反映されるようになったので以下のs3にcpする必要はありません。
■config.tf
tfstateファイルはbackendでS3に管理しています。
1 2 3 4 5 6 7 |
terraform { backend "s3" { bucket = "test-terraform-file" key = "test/terraform.tfstate" region = "ap-northeast-1" } } |
■terraform apply
apply時に必ずローカルにterraform.tfstate.backupが作られるので
これが命!
1 2 3 4 5 6 7 8 |
$ terraform apply aws_vpc.terraform-test_vpc: Refreshing state... (ID: vpc-xxxxxxxxx) aws_internet_gateway.terraform-test_GW: Refreshing state... (ID: igw-xxxxxx) aws_security_group.terraform-test: Refreshing state... (ID: sg-xxxxxxx) aws_subnet.public-c: Refreshing state... (ID: subnet-xxxxxxx) ~省略~ Apply complete! Resources: 0 added, 0 changed, 0 destroyed. |
・terraform.tfstate.backupからterraform.tfstateにコピー
1 |
$ cp terraform.tfstate.backup terraform.tfstate |
■fix ec2 tf file
・aws_ec2.tf
既にvpc,セキュリティグループ、EC2,EIP作成をコード化してます。
26行目に今回importしたいインスタンス名を追記します。
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 |
##EC2(terraform-test01) resource "aws_instance" "terraform-test01" { ami = "${var.ami}" instance_type = "${var.instance_type}" disable_api_termination = false key_name = "infra-verification" vpc_security_group_ids = ["${aws_security_group.terraform-test.id}"] subnet_id = "${aws_subnet.public-a.id}" ebs_block_device = { device_name = "/dev/sdf" volume_type = "gp2" volume_size = "${var.volume_size}" } tags { Name = "terraform-test01" } } ##EIP(terraform-test01) resource "aws_eip" "terraform-test01" { instance = "${aws_instance.terraform-test01.id}" vpc = true } ##EC2(web01) resource "aws_instance" "web01" { } ##EIP(web01) resource "aws_eip" "web01" { } |
■terraform import
https://www.terraform.io/docs/import/usage.html
上記web01のインスタンスとEIPをインポートしてみます。
どうやら公式にはインスタンスの場合インスタンスID、
EIPはアロケーションIDを指定します。
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 |
$ terraform import aws_instance.web01 i-xxxxxxxxxxxx aws_instance.web01: Importing from ID "i-xxxxxxxxxxx"... aws_instance.web01: Import complete! Imported aws_instance (ID: i-xxxxxxxxxxx) aws_instance.web01: Refreshing state... (ID: i-xxxxxxxxxxx) 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. Import does not generate configuration, so the next step is to ensure that the resource configurations match the current (or desired) state of the imported resources. You can use the output from "terraform plan" to verify that the configuration is correct and complete. $ terraform import aws_eip.web01 eipalloc-xxxxxxxx aws_eip.web01: Importing from ID "eipalloc-xxxxxxxx"... aws_eip.web01: Import complete! Imported aws_eip (ID: eipalloc-xxxxxxxxx) aws_eip.web01: Refreshing state... (ID: eipalloc-xxxxxxxxx) 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. Import does not generate configuration, so the next step is to ensure that the resource configurations match the current (or desired) state of the imported resources. You can use the output from "terraform plan" to verify that the configuration is correct and complete. |
できた!
■terraform.tfstate copy to S3
先程importしたものがtfstateに書き込まれているので
このまま$ terraform planとやっても
ローカルのtfstateを見てしまうので何も相違はありません。
上記のようにS3にtfstateファイルを管理しているのでコピーします。
1 |
$ aws s3 cp terraform.tfstate s3://test-terraform-file/test/ |
・terraform init
一旦ローカルに同期させます。(しなくていいかも)
■terraform plan
さあここで相違しまくってるので修正します。
参考にするのはtfstateファイルに全てJSONで書かれているので
照らし合わながら進めていきます。
地道な戦い…..
むむ!
(forces new resource)となってるのでなんか設定違うような….
このままだとインスタンスdestroyされる!w
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 |
$ 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_eip.web01: Refreshing state... (ID: eipalloc-xxxxxxxxxx) ~省略~ The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read. Note: You didn't specify an "-out" parameter to save this plan, so when "apply" is called, Terraform can't guarantee this is what will execute. -/+ aws_instance.web01 (new resource required) ami: "ami-3bd3c45c" => "ami-3bd3c45c" associate_public_ip_address: "true" => "<computed>" availability_zone: "ap-northeast-1a" => "<computed>" disable_api_termination: "false" => "false" ebs_block_device.#: "0" => "1" ebs_block_device.2659407853.delete_on_termination: "" => "true" (forces new resource) ebs_block_device.2659407853.device_name: "" => "/dev/sdf" (forces new resource) ebs_block_device.2659407853.encrypted: "" => "<computed>" (forces new resource) ebs_block_device.2659407853.iops: "" => "<computed>" (forces new resource) ebs_block_device.2659407853.snapshot_id: "" => "<computed>" (forces new resource) ebs_block_device.2659407853.volume_size: "" => "30" (forces new resource) ebs_block_device.2659407853.volume_type: "" => "gp2" (forces new resource) ephemeral_block_device.#: "0" => "<computed>" instance_state: "running" => "<computed>" instance_type: "t2.micro" => "t2.micro" ipv6_address_count: "" => "<computed>" ipv6_addresses.#: "0" => "<computed>" key_name: "kagi" => "kagi" network_interface.#: "0" => "<computed>" network_interface_id: "eni-xxxxx" => "<computed>" placement_group: "" => "<computed>" primary_network_interface_id: "eni-xxxxxxxxx" => "<computed>" private_dns: "ip-xxxxxxxx.ap-northeast-1.compute.internal" => "<computed>" private_ip: "xxx.xxx.xxx.xxx" => "<computed>" public_dns: "ec2-xxx-xxx-xxx-xx-.ap-northeast-1.compute.amazonaws.com" => "<computed>" public_ip: "xx.xxx.xxxx." => "<computed>" root_block_device.#: "1" => "<computed>" security_groups.#: "0" => "<computed>" source_dest_check: "true" => "true" subnet_id: "subnet-xxxxxxx" => "subnet-xxxxxxxxx" tags.%: "1" => "1" tags.Name: "web01" => "web01" tenancy: "default" => "<computed>" volume_tags.%: "1" => "<computed>" vpc_security_group_ids.#: "1" => "1" vpc_security_group_ids.3161430275: "sg-xxxxxxx" => "sg-xxxxxxx" Plan: 1 to add, 0 to change, 1 to destroy. |
■after fix… terraform plan
単純な間違えでしたw
それではplanして相違なかったらapplyしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ 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_eip.web01: Refreshing state... (ID: eipalloc-xxxxxxxxx) aws_instanceweb01: Refreshing state... (ID: i-xxxxxxxxxx) 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, Terraform doesn't need to do anything. |
キタコレ!
1 2 3 4 5 |
$ terraform apply aws_eip.web01: Refreshing state... (ID: eipalloc-xxxxxx) aws_instance.web01: Refreshing state... (ID: i-xxxxxxxxxx) ~省略~ Apply complete! Resources: 0 added, 0 changed, 0 destroyed. |
問題なし!
■まとめ
これで手動で作ったのも問題なくterraform化できましたが、
変数化できないのでちゃんと1から作ったほうがいいですね。(無理してやらないほうがいい)
別AWSにリプレイスとかなった場合に変数化してればメンテする必要ないので。。
ちなみにv0.10だとbackendで管理している場合はローカルtfstateファイルが反映されないバグがあるようで
いくらterraform planしても相違がないというw
↓
https://github.com/hashicorp/terraform/issues/15735
※追記
terraform 0.10.1でバグ治った臭い(後で試してみる)
→普通にローカルからbackend(s3)に反映された!
バグ直しありがとう!!
https://github.com/hashicorp/terraform/pull/15768
0件のコメント