はじめに
こんにちは、そしてこんばんは!
クラウドインテグレーション事業部の大嵩です。
この記事は『クラウドインテグレーション事業部SRE第三セクションブログリレー企画』の2回目(全6回)の記事になります!
前回は比嘉 東一郎さんの「The Linux Foundation の日本語オンライン講座を試してみた」が公開されました。
本記事では、業務の中でTerraformで管理されていないAWSリソースをインポートすることがありましたので、
備忘録として紹介します。
前提
今回は前提としてEC2インスタンスをインポートすることを想定とします。
まずはterrraformの基本定義を行う
terraformを書くときにはまず基本となる定義が必要となります。
設定パラメータは下記公式ドキュメントを参考にします。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs
私の場合はこのように記述しました。
# provider.tf terraform { required_providers { aws = { source = "hashicorp/aws" } } backend "local" { path = "./terraform.tfstate" } } provider "aws" { region = "ap-northeast-1" }
required_providers
ここで、使用する プロバイダーを定義します。
AWSリソースになりますので、「”hashicorp/aws”」と記述します。
backend “local”
ここで、Terraformの構成情報を保存する場所を定義します。
今回はローカルに保存するため、localとします
provider “aws”
ここでは、定義したプロバイダーに対して設定を記述します。
使用するリージョンを「ap-northeast-1」で設定します。
実際にインポートする
インポートする前に
インポートに移る前に、まず空の定義を記述してあげる必要があります。
以下の通りに本当に空の状態で書きます。
# ec2.tf resource "aws_instance" "test" { }
このとき、Terraform上で扱う定義名はわかりやすく自由に指定して大丈夫です。
(この場合 “test” の部分です。)
インポートを実行する
空の定義ができたらいよいよインポートです。
下記のコマンドを実行します
terraform import aws_instance.test インスタンスID
インポートが成功すると、このようになります
❯ terraform import aws_instance.test インスタンスID aws_instance.test: Importing from ID "XXXX"... aws_instance.test: Import prepared! Prepared aws_instance for import aws_instance.test: Refreshing state... [id=XXXX] 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.
インポート後
コマンドを実行したら、tfstateファイルに下記のようなEC2の構成情報が書き出されます。
# terraform.tfstate { "version": 4, "terraform_version": "1.9.7", "serial": 1, "lineage": "XXXX", "outputs": {}, "resources": [ { "mode": "managed", "type": "aws_instance", "name": "test", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 1, "attributes": { "ami": "ami-0ef29ab52ff72213b", "arn": "XXXX", "associate_public_ip_address": false, "availability_zone": "ap-northeast-1d", "capacity_reservation_specification": [ { "capacity_reservation_preference": "open", "capacity_reservation_target": [] } ], "cpu_core_count": 1, "cpu_options": [ { "amd_sev_snp": "", "core_count": 1, "threads_per_core": 1 } ], "cpu_threads_per_core": 1, "credit_specification": [ { "cpu_credits": "standard" } ], "disable_api_stop": false, "disable_api_termination": false, "ebs_block_device": [], "ebs_optimized": false, "enclave_options": [ { "enabled": false } ], "ephemeral_block_device": [], "get_password_data": false, "hibernation": false, "host_id": "", "host_resource_group_arn": null, "iam_instance_profile": "", "id": "XXXX", "instance_initiated_shutdown_behavior": "stop", "instance_lifecycle": "", "instance_market_options": [], "instance_state": "running", "instance_type": "t2.micro", "ipv6_address_count": 0, "ipv6_addresses": [], "key_name": "", "launch_template": [], "maintenance_options": [ { "auto_recovery": "default" } ], "metadata_options": [ { "http_endpoint": "enabled", "http_protocol_ipv6": "disabled", "http_put_response_hop_limit": 2, "http_tokens": "required", "instance_metadata_tags": "disabled" } ], "monitoring": false, "network_interface": [], "outpost_arn": "", "password_data": "", "placement_group": "", "placement_partition_number": 0, "primary_network_interface_id": "XXXX", "private_dns": "ip-172-31-17-175.ap-northeast-1.compute.internal", "private_dns_name_options": [ { "enable_resource_name_dns_a_record": false, "enable_resource_name_dns_aaaa_record": false, "hostname_type": "ip-name" } ], "private_ip": "172.31.17.175", "public_dns": "", "public_ip": "", "root_block_device": [ { "delete_on_termination": true, "device_name": "/dev/xvda", "encrypted": false, "iops": 3000, "kms_key_id": "", "tags": {}, "tags_all": {}, "throughput": 125, "volume_id": "XXXX", "volume_size": 8, "volume_type": "gp3" } ], "secondary_private_ips": [], "security_groups": [ "default" ], "source_dest_check": true, "spot_instance_request_id": "", "subnet_id": "XXXX", "tags": { "Name": "test-otake", "Owner": "otake" }, "tags_all": { "Name": "test-otake", "Owner": "otake" }, "tenancy": "default", "timeouts": null, "user_data": null, "user_data_base64": null, "user_data_replace_on_change": null, "volume_tags": null, "vpc_security_group_ids": [ "XXXX" ] }, "sensitive_attributes": [], "private": "XXXX" } ] } ], "check_results": null }
上記を元に、空の状態で記述していた、EC2の定義を書き込んでいきます。
# ec2.tf resource "aws_instance" "test" { ami = "ami-0ef29ab52ff72213b" instance_type = "t2.micro" availability_zone = "ap-northeast-1d" vpc_security_group_ids = [セキュリティグループID] #リスト型 subnet_id = サブネットID root_block_device { volume_type = "gp3" volume_size = "8" iops = 3000 throughput = 125 encrypted = false } tags = { Name = "test-otake" Owner = "otake" } }
その他に、キーペアやIAMロールを割り当てている場合、tfstateを見ながら同じように追記します。
TerraformのState情報と差分がないかを確認
記述を追記した後はplanを実行して差分がないことを確認しましょう。
以下の実行結果になれば成功です!!
# コマンド terraform plan # 実行結果 ❯ terraform plan aws_instance.test: Refreshing state... [id=XXXX] No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
まとめ
今回インポートを実行してみて、意外と簡単に後からリソースをTerraformに紐づけて管理することができました!
また、Terraform管理にすることで、マネジメントコンソールよりも効率的に運用作業を実施することができます。
今後も活用していきたいと思います!
この記事がどなたかの参考になりますと幸いです!
次回は田中 俊さんの「CDKでEKSクラスター構築してみた」が公開される予定です!お楽しみに!