はじめに
こんにちは、そしてこんばんは!
クラウドインテグレーション事業部の大嵩です。
この記事は『クラウドインテグレーション事業部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クラスター構築してみた」が公開される予定です!お楽しみに!