読者です 読者をやめる 読者になる 読者になる

scramble cadenza

技術ネタのガラクタ置き場

terraform quick start 的なメモ

イントロ

terraform の初期化を行うのはプライベートでは二回目。
以前まとめていた自分用メモを、少し整形して公開してみる。

terraform はなんぞや、というところはすっ飛ばし、もう一度手元で terraform を使う環境を構築する人向けです。
内容は今更感がありまくりで、目新しいことは何もなし。

(なお、個人的な趣味により、provider は aws で、backend は s3 にしていますし、その前提で記事を書いています。)

terraform を始める

まず terraform init コマンドを実行する。

実行するとカレントディレクトリに .terraform というディレクトリが掘られていて、ここに terraform.tfstate というファイルが作成される。

この terraform.tfstateterraform が管理するリソースを json 形式で書いたもの。
commit するのは注意が必要。
Command: init - Terraform by HashiCorp

terraform init -backend=s3 \
-backend-config="bucket=terraform-bucket" \
-backend-config="region=ap-northeast-1" \
-backend-config="key=terraform.tfstate" \
-backend-config="profile=profile_name" .

terraform init コマンドの補足

backend とは

tfstate 置き場の事。
-backend=s3terraform.tfstate の置き場所を s3 にする、という設定。

tfstate の管理について

terraform はローカルにある terraform.tfstate を元にコマンドが実行される。 したがって、複数人で開発する時、各個人のローカルで持っている terraform.tfstate の状態に差があると、terraform の実行結果に差が出てしまう。

ファイルの状態によっては、A さんは EC2 が作られていて、B さんは EC2 が作られていない、という矛盾した状況にもなり得る。こうなると、どちらが正しいかわからなくて困ってしまう。

現在実際に構成されている AWS のリソースが常に正であり、その状態は常に tfstate は反映されてなければならない。

なので、複数人で開発する場合は、全員が最新の terraform.tfstate を参照する必要がある。

State - Terraform by HashiCorp

tfstate を s3 で管理する意味

全員が最新の tfstate を参照する方法の一つとして、s3 に terraform.tfstate を置く、というやり方がある。

A さんが AWS の状態が更新したら terraform.tfstate をローカルで上書きして、s3 に保存する。
B さんは s3 の terraform.tfstate をローカルに反映させて、terraform.terraform を実行する、というみたいな仕組み。(多分)

なお、terraform init 以外でも、terraform remote config コマンドを実行することで terraform.tfstate を s3 で管理する指定ができる。

Remote State Backend: s3 - Terraform by HashiCorp

terraform remote config \
    -backend=s3 \
    -backend-config="bucket=terraform-bucket" \
    -backend-config="key=terraform.tfstate" \
    -backend-config="region=ap-northeast-1"

provider の設定

Provider: AWS - Terraform by HashiCorp

どちらかを選択する

  • access_key, secret_key セットする。
  • profile をセットする

access_key をセットする

provider "aws" {
   access_key = "${var.aws_access_key}"
   secret_key = "${var.aws_secret_key}"
   region = "us-east-1"
}
  • access_key or 環境変数 AWS_ACCESS_KEY_ID をセットする
  • secret_key or AWS_SECRET_ACCESS_KEY をセットする
  • region or AWS_DEFAULT_REGION をセットする

profile をセットする

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

最小限の構成

環境変数を適切にセットしている前提であれば

provider "aws" {}

に落ち着く。

これからどうするの?

後は普通にドキュメント見ながら resource を定義していくだけで OK。
aws の resource はこちらにまとめられている。

Provider: AWS - Terraform by HashiCorp

terraform import 手順

terraform には、現在 AWS に構築されている環境を terraform.tfstate に落とし込む機能がある。
それを terraform import と呼ぶらしい。

Import: Usage - Terraform by HashiCorp

terraform import resource名.名前 {id}

というコマンドを叩く。
resource 名は import 対象の resource。名前は terraform で管理したい名前。{id} は resource によって異なる。
{id} は勘でなんとかなる気がします。

例えば aws_route53_zone という resource の場合は、以下のコマンドで import できた。

terraform import -backup=backup aws_route53_zone.mgi166 {zone_id}

このコマンドで何が起こるかというと、ローカルの terraform.tfstate に、aws_route53 の設定内容が反映される。

後は、自前で resource を定義しながら、terraform plan との差分が無くなるまで、 tf ファイルを試行錯誤すれば良い。
というのも、差分が無くなるということは、import コマンドを叩いた後の terraform.tfstate と、tf ファイルに書いたコードの内容が同じであることを意味するからです。

しかし、terraform import は完全ではないようで、差分をなくすのは難しい場合がある。
具体的には一部の属性が変わったりしてしまう。
私はどうしようもないと諦めてしまったけど、このあたりの良い解決方法があれば教えていただきたいです。

$ 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_route53_zone.mgi166: Refreshing state... (ID: xxxx)
aws_route53_record.www: Refreshing state... (ID: xxxxx CNAME)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.


# force_destroy が `""` だったのが、"false" になっている
~ aws_route53_zone.mgi166
    comment:       "HostedZone created by Route53 Registrar" => "Managed by Terraform"
    force_destroy: "" => "false"

まとめ

  • terraform init or terraform remote config で backend の設定を作る
  • 必要に応じて terraform import で既存のリソースを import する
  • 後は document を読んで頑張る

参考