Terraformの基本的扱い方(AWS編)

terraformAWS

Terraformを使って環境構築を行ったときによく使ったコマンドや設定などをまとめておきます。

Terraformをまともに触ったことがない状態でしたが、環境構築をするとなってから事前にある程度どういったものか調べて取り組みました。

その中でもよく使った設定やコマンドを取り上げます。

書いてあること

・Terraform基本的な設定方法
・Terraformの基本コマンド
・詰まったポイント

今回はAWSを前提に書いています。

基本的な設定方法

ざっくりTerraformについて説明すると、
HashiCorp社が提供するマルチクラウド上のコンピュータやネットワークの構築を自動化するツールです。

Infrastructure as Code(IaC)と呼ばれるものですね。
リソースをコード管理できるのがメリットの1つになります。

AWSのCloudFormationも同じくIaCですが、TerraformはAWS以外にもGCPやAzureにも対応しています。
Terraform

では早速設定方法を見ていきます。

provider

どのクラウド環境を使用するかを設定します。

provider "aws" {
    region = "ap-northeast-1"
}

variable

変数を定義します。
型やデフォルト値を指定することが可能です。
typeの種類は下記になります。

• string
• number
• bool
• list()
• set()
• map()
• object({ = , … })
• tuple([, …])

variable "hogehoge" {}
variable "env" {
    type    = string
    default = "development"
}

呼び出すときはvar.{変数名}でその変数の値を取得でき、文字列の中で展開するときは${}で囲ってあげることで展開もできます。

resource "aws_iam_user" "admin" {
  name = var.hogehoge
  tags = {
    Name = "${var.env}-admin"
  }
}

その他値の注入の仕方は後述するterraform planなどを実行したときに指定したり、コマンドの引数によって指定したり、環境変数による指定などが存在します。

resource

作成するリソースについて記述します。
構文としてはresource "リソースの種類" "リソース名" {}のような形です。

リソースの種類についてはTerraformの公式ドキュメントに記載されているので作成したいリソースを検索すればすぐに見つけることができます。

ブロックの中にリソース毎に必要な設定項目を記述していきます。

注意点として、Terraformは頻繁にバージョンが変わるためバージョンによっては書き方が非推奨になっていたりするので自分の設定したバージョンでドキュメントを見ることが必要です。

リソース名は任意の値で問題ないです。

resource "aws_vpc" "main" {
    cidr_block = "10.1.0.0/16"
    instance_tenancy = "default"
    enable_dns_support = "true"
    enable_dns_hostnames = "false"
    tags {
      Name = "${var.env}-main"
    }
}

data

Terraform内で参照したいリソースの情報を参照します。

構文としては、data "要求するリソース名" "terraform内の名前" {}のような形です。

resourceと同じくドキュメントにリソース名は記載されています。

data.要求するリソース名.terraform内の名前.取得したキー名でリソースの値を取得することができます。

data "aws_vpc" "main" {
  id = "vpc-01b2caf4c15eaab98"
}
data "aws_subnet_ids" "hoge_subnet" {
  vpc_id = data.aws_vpc.main.id
  name   = "${var.env}-main
}

基本コマンド

terraform fmt

ソースコードのフォーマットを整えてくれるコマンドです。

例えば下記のようにイコール(=)の位置が項目ごとにずれているときにすべてを同じ位置に整えてくれます。

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support  = true
  instance_tenancy = "default"
  assign_generated_ipv6_cidr_block = false
}

↓こんな感じ

resource "aws_vpc" "main" {
  cidr_block                       = "10.0.0.0/16"
  enable_dns_hostnames             = true
  enable_dns_support               = true
  instance_tenancy                 = "default"
  assign_generated_ipv6_cidr_block = false
}

例えば、/developmentというディレクトリ配下にvpc.tfが存在する場合は/developmentでterraform fmtを実行する必要があります。

/developmentにあるファイルはすべてフォーマットの対象になります。

しかし、/development/moduleのように更に階層が深くなる場合は/module配下のファイルには適応されません。

オプションのterraform fmt -recursiveを使用することで解決することができます。

このオプションをつけることでコマンドを実行した階層の配下すべてのファイルに適応されます。

terrform plan

実装した内容が実際にどのようなリソースを作成するのかを確認することができます。

何か間違いがあればエラーが出るので実行前にテストできるイメージですね。

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc.hogehoge will be created
  + resource "aws_vpc" "main" {
      + arn                                  = (known after apply)
      + assign_generated_ipv6_cidr_block     = false
      + cidr_block                           = "10.0.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags_all                             = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

known after applyはAWSリソースが作成された後に決定する値です。

下記はリソースが1つ追加され、変更や削除はないという意味になります。

Plan: 1 to add, 0 to change, 0 to destroy.

terraform apply

実際にリソース作成を実行します。
コマンドを実行するとterraform planのときと同じように作成されるリソースが確認できます。

その後本当に実行するか聞かれるので「yes」と入力すると作成が開始されます。
リソースによっては少し時間がかかることもあります。

作成時になにか問題があるとこのタイミングでエラーが吐かれます。
僕の場合は、実行は失敗したがリソースは作れられているということがおきました。
Terraform上のリソースの状態とAWS上の状態が一致している必要ががあるため後述するterraform importで既存のリソースを取り込んで差分を無くす必要がありました。

terraform import ADDRESS ID

既存のリソースをインポートします。

ADDRESSはリソースの種類+リソース名です。
本章で取り上げていたVPCの場合だとaws_vpc.mainの部分になります。

IDはAWSのリソースの種類によって異なります。
ARNだったり、インスタンスの場合はインスタンスIDだったりします。
ID形式の詳細はドキュメントに記載されています。

terraform import aws_vpc.main [VPCのID]

moduleの場合

terraform import module.foo.aws_instance.bar i-abcd1234

ここで指定したtfファイルのリソースに対して既存リソースの情報がインポートされることになります。
そのため、予め対応するリソースをtfファイルに記述しておく必要があります。

Terraformは実行したときに自動で判断してリソースを作成してくれますが、これは実行時に読み込んだtfファイルとtfstateに書かれている内容の差分を元に行われます。
つまり、指定した既存リソースをTerraform上で管理するためにはtfstateの内容を変更する必要があり、指定した既存リソースの情報を読み込みtfstateに追加してくれるコマンドになります。

terraform state show ADDRESS

指定したリソースがtfstate上でどのような属性や値を持っているかを見ることができます。

ADDRESSはリソースの種類+リソース名です。

resource "aws_vpc" "main" {
    arn                              = "arn:aws:vpc:ap-northeast-1:AWSアカウントID:vpc/main"
    assign_generated_ipv6_cidr_block = false
    cidr_block                       = "10.0.0.0/16"
    default_network_acl_id           = "acl-0294d93390a5fb366"
    default_route_table_id           = "rtb-0070871d11d9ef714"
    default_security_group_id        = "sg-00fb88354cb9fa47e"
    dhcp_options_id                  = "dopt-0b1a7ce9ce8741ab2"
    enable_classiclink               = false
    enable_classiclink_dns_support   = false
    enable_dns_hostnames             = true
    enable_dns_support               = true
    id                               = "vpc-0ab175d8404e47af3"
    instance_tenancy                 = "default"
    ipv6_netmask_length              = 0
    main_route_table_id              = "rtb-0070871d11d9ef714"
    owner_id                         = "123456789098"
}

このメソッドはARNを取得したいときなどに使用しました。
環境変数にARNを設定したいときにコンソール画面にARNが表示されていないサービスがあったため、このコマンドを実行することでARNを取得しました。
例)SSMのパラメータストアなど

まとめ

初めてTerraformを触って環境構築を行いましたが、何度もエラーにぶつかりかなり手こずりました。

ただ1コマンドで環境が出来上がり、コード管理できるという点は魅力的でした!

AWSの話になってしまいますが、個人的にはARNが取得できないサービスがあったときは優しくないなあと思ってしまいました笑

terraform state showコマンドを使って取得する方法を先輩エンジニアの方に教えてもらったことでなんとか解決できました。

今回はあまりmoduleとかを使わなかったのでそういったところも使えるようになりたいですね。

コメント

タイトルとURLをコピーしました