Terraform管理の取捨選択は運用で状態が変わるかどうかで決めると良い

今のプロジェクトではTerraformを使ってAWS上のインフラを構築しているのですが、1年程運用して向いてるケース、そうではないケース等が明確になってきました。

今一度Terraformとは

TerraformとはHashicorp社のプロダクトで、インフラを管理・構築・破棄をコードベースで行うことができ、まさにInfrastructure as Codeを地で行くようなOSSプロダクトです。 AWSだけではなく、その他多くのIaaS/PaaS/SaaSといったサービスの構成をコードで構築することが可能になります。最近はDockerの管理もサポートしていたり、GitHubのチームやリポジトリまでもが管理できたりします。

全てが運用に即したものではない

Terraformを利用する上で忘れていけない前提があると考えています。

「Terraformでの構成管理の全てが、必ずしも実運用に即したものではない」ということです。

様々なインフラやサービスをコードによって構築できるのは大きなメリットとしてありますが、Terraformはとにかく手広く多くのProviderをサポートしてはいるものも、そのそれぞれの操作が運用最適であるかとは限りません。そして運用最適も利用ケースによって変わってくるでしょう。

あくまでTerraformは構築までがスコープであって、運用は範疇ではありません。

運用上、mutable(可変)な特性を持つもの

例えばAWSのEC2では、CPUやメモリ利用率の閾値をトリガーにして自動でインスタンスの数を増やすAuto Scalingという仕組みがあります。Auto Scalingでは稼働させたいインスタンスの希望数(DesiredCount)を任意で設定することもできますし、負荷によってDesiredCountの値を収縮させたりというのもよくある手法です。

Auto ScalingグループはTerraformのコードでは以下のように表現します。公式ドキュメントから引用*1

resource "aws_autoscaling_group" "bar" {
  availability_zones = ["us-east-1a"]
  name = "foobar3-terraform-test"
  max_size = 5
  min_size = 2
  health_check_grace_period = 300
  health_check_type = "ELB"
  desired_capacity = 4
  force_delete = true
  placement_group = "${aws_placement_group.test.id}"
  launch_configuration = "${aws_launch_configuration.foobar.name}"

  tag {
    key = "foo"
    value = "bar"
    propagate_at_launch = true
  }
  tag {
    key = "lorem"
    value = "ipsum"
    propagate_at_launch = false
  }
}

desired_capacityがインスタンスの希望数です。Terraformの**.tf**ファイルはGitHubで管理するケースが多いと思いますがちょっと運用を想像してみてください。

指定したインスタンス数で十分なリクエストを捌けなかった場合、早急なスケールが求められますが、いくらInfrastructure as Codeとは言っても切迫した状況でPull Requestをやりとりしている暇はあるでしょうか? max_sizeの蓋を上げたいケースだってあるでしょう。なので、desired_capacity だけではなくmax_sizemin_sizeですらmutableな属性を持ったプロパティではないでしょうか。

また、Auto ScalingをTerraform管理する罠としては、運用で変動した値が次回 terraform apply するとTerraformで定義した値で更新されてしまうということにあります。これはTerraformが悪いのではなく、コードで定義した値で構成を作成するわけですから当然の動きです。

つまり、Auto Scalingのように運用に曝されることで状態が変化しうる性質を持つものに関しては、Terraformで管理するのはなかなか難しいということがわかります。そのため、今のプロジェクトにおいてはAuto Scaling Groupの起動構成だけをTerraform管理にし、Auto Scaling Groupの作成・破棄・操作に関しては別途Goでツールを書いて運用しています。

利用ケースによってどれがmutableになるかというのは多少違ってきますが、どれをTerraform管理にしてどれを管理外にするかという取捨選択は「運用によって状態が変わるかどうか?」という判断で決めるのが良い。というのが1年程Terraformを利用してきて掴んだ最大の知見かもしれません。

AWSでTerraform管理が向いていると思われるもの

とはいえインフラをポチポチ構築するのはナンセンスなのでTerraformを使っていけるものはどんどん使っていくと良いと思います。向いてない性質のものもありますが、向いている性質のものもたくさんあります。とりあえず一部ですがあげときます。

  • EC2
  • VPC
  • S3
  • SQS
  • IAM
  • Route53(動的にDNSを振るという要件が無ければ)
  • RDS(構築時間がかかるので、CIでTerraformする場合の時間を許容できるのであれば)

というわけで各々の運用ケースによって、Terraform管理をしていくかの取捨選択をしていけば良いという考えで、無理して全部コード化すると消耗するぞ!というのが結論です。