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

※1https://www.terraform.io/docs/providers/aws/r/vpc.html
※2https://www.terraform.io/docs/import/index.html
※3https://github.com/GoogleCloudPlatform/terraformer

 

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
2
読み込み中...
2 票, 平均: 1.00 / 12
41,973
X facebook はてなブックマーク pocket

この記事をかいた人

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