やりたいこと
Terraformを環境別にdevelopment
, production
用というように分けてそれぞれリソースを管理したい
やったこと
それぞれの環境ごとのtfstateを作成してディレクトリで環境を分けた
ディレクトリ構成としては大体このような感じ
├── .terraform
│ ├── terraform.tfstate
│ └── terraform.tfstate.backup
├── development
│ ├── .terraform
│ │ ├── terraform.tfstate
│ │ └── terraform.tfstate.backup
│ ├── config.tf
│ ├── ec2.tf
│ ├── elasticache.tf
│ ├── elb.tf
│ ├── iam.tf
│ ├── rds.tf
│ ├── route53.tf
│ ├── s3.tf
│ ├── security_group.tf
│ ├── variables.tf
│ └── vpc.tf
├── production
│ ├── .terraform
│ │ ├── terraform.tfstate
│ │ └── terraform.tfstate.backup
│ ├── config.tf
│ ├── ec2.tf
│ ├── elasticache.tf
│ ├── elb.tf
│ ├── iam.tf
│ ├── rds.tf
│ ├── route53.tf
│ ├── s3.tf
│ ├── security_group.tf
│ ├── variables.tf
│ └── vpc.tf
├── route53.tf
├── s3.tf
├── config.tf
└── variables.tf
ポイントとしては
- ルートディレクトリにそれぞれの環境で共通のリソースを作る
- 一部IAM Role、IAM User、Route53のZone、それぞれの環境で共通で使うS3バケット、共通のVPCなど
- 環境別にディレクトリを切る
- それぞれの環境固有のリソースはそのディレクトリ内で作成。(環境ごとに固有のドメイン、環境固有のS3のオブジェクト、VPC、EC2インスタンスなど)
- 上位のリソースのIDやARNなどは
outputs
経由で委譲してもらう
なぜこのような構成になったかというと、環境別にVarファイル(Terraformでの変数)を用意してapply
実行時に切り替える方法も考えたのだけど、
- オプションの切り替えで事故りそう(
-state
,-var
での指定で毎回正確に指定出来る自信がない) - 事故を防ぐため複数人で作業する場合でもオプション指定無しでも実行出来るようにしたい(
terraform plan
,terraform apply
のみで実行出来るようにしたい)
というのがあり、変数ファイルでの切り替えにはならないので書き方としては多少冗長になるものの、インフラの事故は1ミスすなわち死なので、下手に再利用性を高めるよりは明示性に寄って安全重視で行きたい、ということでこんな構成になった。
構築方法
- ルートディレクトリでS3をremote stateに設定をする
terraform remote config \
-backend=S3 \
-backend-config="bucket=your.terraform.bucket" \
-backend-config="key=super.terraform.tfstate" \
-backend-config="region=ap-northeast-1"
- 共通のリソースを作る
route53.tf
resource "aws_route53_zone" "foobar" {
name = "foobar.com"
comment = "foo!"
tags {
name = "foobar"
}
}
-
output
を定義する
ここで定義したoutput
リソースは各環境に委譲され利用出来る
$ vim outputs.tf
outputs.tf
output "zone_id" {
value = "${aws_route53_zone.foobar.id}"
}
plan
で確認してapply
で適用
terraform plan
terraform apply
- リモートにtfstateファイルをpush
apply後はstateファイルをリモートのS3にpushする
terraform remote push
- 各環境別のリソースを作成
ここから各環境用のリソースを作って行きます
$ mkdir development
$ cd development
環境別のremote stateをコマンドラインから設定
terraform remote config \
-backend=S3 \
-backend-config="bucket=your.terraform.bucket" \
-backend-config="key=development.terraform.tfstate" \
-backend-config="region=ap-northeast-1"
remote stateをリソース定義から利用するためterraform_remote_state
の定義をする
vim config.tf
config.tf
resource "terraform_remote_state" "super_state" {
backend = "s3"
config {
bucket = "your.terraform.bucket"
region = "ap-northeast-1"
key = "super.terraform.tfstate"
}
}
resource "terraform_remote_state" "development_state" {
backend = "s3"
config {
bucket = "your.terraform.bucket"
region = "ap-northeast-1"
key = "development.terraform.tfstate"
}
}
例えば開発環境用のドメインをroute53で設定したいとすると
$ vim route53.tf
route53.tf
resource "aws_route53_record" "dev_api" {
zone_id = "${terraform_remote_state.super_state.output.zone_id}"
name = "dev.api.foobar.com"
type = "A"
}
このようになる。
${terraform_remote_state.super_state.output.zone_id}
でルートディレクトリでのoutputを委譲している
これによって複数人で作業するときもremote stateを参照してリソースの定義が出来るのでチームでの作業やリソースのコンポーネント化がやりやすくなります
リソースの定義が終わったらそれぞれの環境別のディレクトリ内でも同じくplan
, apply
で適用します
terraform plan
terraform apply
まとめ
terraformのstateを環境別にディレクトリで分けることで管理した
tfstateは操作をミスったりリモートだけ手動で構成を変更したりすると割りとすぐ整合性が崩れて事故の元になるので運用方法には注意が必要