LoginSignup
20
17

More than 5 years have passed since last update.

Terraformで環境別の状態を管理する

Posted at

やりたいこと

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は操作をミスったりリモートだけ手動で構成を変更したりすると割りとすぐ整合性が崩れて事故の元になるので運用方法には注意が必要

20
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
17