続きをかきました→ https://qiita.com/uraura/items/e13d883827443f27bf98
概要
TerraformでAWSのリソース管理をしていますが,(少人数でやるには1)まぁまぁ良い感じに落ちついたのでご紹介します.
以下,話を簡単にするためにTerraformでAWSのリソースを管理しているという前提で話をすすめます.
問題
Terraformは便利で,使いはじめると何でもかんでもコード化してやろう!!などと思ってしまいますが,すぐに以下のような問題にぶち当たります.
- コード化をすすめると
plan/apply
にかかる時間が増大していく -
plan
が通ってもapply
でコケる場合がままある
コード化をすすめるとplan/apply
にかかる時間が増大していく
コード化されてるリソースが少ないうちはあまり問題にならないのですが,時がたちコード量が増えてくると,plan/apply
にかかる時間がどんどん伸びていきます.
巨大なmodule
があると,コード量の増加は数行だったとしても所要時間は一気に増えたりするので要注意です.
plan
が通ってもapply
でコケる場合がままある
プルリクエスト作ったらplan
して,マージされたapply
する,というフローをよく(?)みかけます.
一見すると分かりやすいフローではありますが,planが成功していようが結局applyしないとどうなるかわかりません.一度この状態に陥ると,
- applyを通すために微修正したプルリクエストを何度も作ることになってつらい
- applyが通っても意図した通りの結果になっていなくてつらい
みたいなことになり,加えてコード量がそれなりに多い場合は(1)の問題がクリーンヒットしてきます.
どうしたか
大きくわけて2つです.
- AWSアカウントを開発(dev)/ステージング(stg)/本番(prd)で分ける
- Terraform Providerを使う
AWSアカウントを開発(dev)/ステージング(stg)/本番(prd)で分ける
よくある話だと思います.(IAMを完全にマスターすれば1アカウントで頑張れるのかもしれませんが,ちょっと自分には無理です...)
各アカウントの用途は以下のような感じになります.
- devはローカルマシンから
plan/apply
できるようにしてしまう - CIからapplyする確認はstgで取る
- stgで確認できたらprdにもapplyする
devを,対象プロジェクト専用のsandboxとみなしてしまうのがポイントです.
そもそもdevは壊れる前提で作ってるわけですし,ぶっ壊れたら作りなおせばいいよね?(それをしないなら何のためにコード化を...?)
新規で何かリソースを追加するにしても,既存のリソースがある前提で考えられますし,
何よりdevでapply
までやってしまうことにより,無駄なプルリクエストを作りまくらなくても良くなりCI待ちなども無くサクサク開発できるようになります.
※冒頭で少人数でと書いたのはこのあたりの事情にもよります.複数人で1つの環境に同時にapply
すると多分よくわからない状態になります.
Terraform検証用AWSアカウントについて
以前は,Terraformの検証は調査/学習用の(共通の)AWSアカウントでやる,という感じでした.その場合はローカルマシンからapply
できるようになっていると思いますが,以下のような問題もあります.
- 関係ない他のリソースが作られていたりする
- 検証したいリソースに必要な依存先があればそれも含めて作る必要がある
- 検証終わったらちゃんと消さないと無駄に金がかかる
また,通常は必要最低限のリソースしか作らないので,そのコードを加えた際に増加するapply時間がまったく見えなくなります.
というわけで,一切プロジェクトと関係ないリソース(個人の趣味とか将来的には使うかもとか...)の確認には良いですが,現在のプロジェクトで使う前提のリソースを確認する目的なのであればそのプロジェクトのdevでやるのが良いのでは,という感じです.
Terraform Providerを使う
Terraform ProviderというProviderがあります.一言でいうと,他で実行されたTerraformのtfstateを参照できるProviderです.イメージは下記の通りです.
resource "aws_s3_bucket" "foo" {
:
}
output "s3_bucket_foo" {
value = "${aws_s3_bucket.foo.id}"
}
data "terraform_remote_state" "tf_a" {
backend = "s3"
config {
:
}
}
data "aws_s3_bucket" "foo" {
bucket = "${data.terraform_remote_state.tf_a.s3_bucket_foo}"
}
これで,terraform_A
をapply
した結果できたS3バケットfooを,別のterraform_B
が参照できるようになります.
terraform_B
内ではS3バケットfooは存在することを前提として動けるため,plan/apply
が爆速になります.
基本はmodule
で完結させ,module
外で必要なリソースはoutput
を定義する,という感じにする2と,どこに何があるのか把握しやすくて良い感じです.
terraform output
コマンドでoutput
されている値を一覧できる3ので,必要なときにぱっと探しやすいという利点もあります.
まとめ
- Terraformはapplyしやすい環境を整えると捗る
- Terraform Providerをつかってtfstateを分割すると時短になる4
-
自分自身がそんなに大勢の人がTerraformを同時にいじくるという環境にいたこと無いというのと,現実的にはインフラ構成いじるの少人数じゃない?という憶測があるためです. ↩
-
具体的な構成はまた別の記事に書くかも... ↩
-
terraform_remote_state
で参照するためにはroot
レベルでoutput
されてなければいけない(仕様)せいで若干めんどくさかったりもする. ↩ -
TerraformのBest Practice的にも推奨っぽい ↩