【15周年記念 特設サイト】ビヨンドは「2022.4.4」で15周年を迎えました!

【15周年記念 特設サイト】ビヨンドは「2022.4.4」で15周年を迎えました!

【新卒 / キャリア採用】サーバー / クラウドエンジニア 募集中!【大阪】

【新卒 / キャリア採用】サーバー / クラウドエンジニア 募集中!【大阪】

【導入実績300社以上】AWS 構築・運用保守サービス

【導入実績300社以上】AWS 構築・運用保守サービス

【サーバー管理不要】WordPress専用クラウド『WebSpeed』

【サーバー管理不要】WordPress専用クラウド『WebSpeed』

【100URLの登録が0円】Webサイト監視サービス『Appmill』

【100URLの登録が0円】Webサイト監視サービス『Appmill』

【コミュニケーションアプリ開発】LINE アプリ開発サービス

【コミュニケーションアプリ開発】LINE アプリ開発サービス

【ECサイト構築】Shopify カスタムアプリ開発サービス

【ECサイト構築】Shopify カスタムアプリ開発サービス

【音声アプリ開発】Twilio アプリ開発サービス

【音声アプリ開発】Twilio アプリ開発サービス

【Webシステム / サービス開発】SAKARAKU Lab(セカラクラボ)

【Webシステム / サービス開発】SAKARAKU Lab(セカラクラボ)

【取材記事】サーバー系企業ビヨンドが サーバーサイドエンジニアを募集中

【取材記事】サーバー系企業ビヨンドが サーバーサイドエンジニアを募集中

【対談記事】「やっぱクラウド移設っていいですよね」マイネット × ビヨンド エンジニア対談

【対談記事】「やっぱクラウド移設っていいですよね」マイネット × ビヨンド エンジニア対談

ビヨンド公式YouTubeチャンネル「びよまるチャンネル」

ビヨンド公式YouTubeチャンネル「びよまるチャンネル」

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


この記事をかいた人

About the author

寺岡佑樹

2016年ビヨンド入社、現在6年目のインフラエンジニア
MSPの中の人として障害対応時のトラブルシューティングを行いながら
AWSなどのパブリッククラウドを用いたインフラの設計/構築も行っている。
最近はDockerやKubernetesなどのコンテナ基盤の構築や
運用自動化の一環としてTerraformやPackerなどのHashicorpツールを扱うことが多く
外部の勉強会やセミナーで登壇するEvangelistの役割も担っている。

・GitHub
https://github.com/nezumisannn

・登壇経歴
https://github.com/nezumisannn/my-profile

・発表資料(SpeakerDeck)
https://speakerdeck.com/nezumisannn

・所有資格
AWS Certified Solutions Architect - Associate
Google Cloud Professional Cloud Architect