2019年12月11日水曜日

Terraformのバックエンドで同じワークスペースでも環境を分けよう!

皆さん、こんにちは。グルージェント開発部のジャレド・ウォレスです。今回は前回の記事と少し変わり、エンジニア向けになってしまうかもしれませんが、技術の話をしたいと思います。皆さん、Infrastructure as Code(IaC)をご存じでしょうか?簡単にいうとコンピューティング・インフラ(仮想マシン、ネットワーキング等)の構成管理をコーディングで行う、という言葉です。Chef、Ansible、Puppet等、様々な管理ツールが存在しますが、最近ではTerraformという、Hashicorp様が提供しているツールが注目されてきています。弊社も開発ツールの環境の構築と操作でTerraformを活かしております。

Terraformの基本とバックエンドの必要性
Terraformでは、AWSなどのIaaSクラウドサービスを管理するコードブロック「resource」があります。複数のリソースを一緒に管理する時にモジュールにまとめることも可能であり、よく使うものはTerraform Registryからパッケージのようにダウンロードして使うこともできます。JSONのように、HCL(Terraformリソースを書く言語)は宣言的で読みやすいです。

しかし、せっかく書いたインフラコードをどう管理すればいいのでしょうか?ステートを定義する、人が読まない大量のJSONのtfstateファイルまでソースコントロールにコミットをするのも気持ち悪いですし、開発者の実行ローカルだけで管理するにデータロスの危険性もあり、プロジェクトが増えれば管理が難しくなります。なお、現在のTerraformでは全く同じインフラを複数の環境に分けて明確に管理する方法はありません。しかし、少し賢く使えば、リモートバックエンドがシンプルに解決してくれるので、その方法を紹介していきたいと思います。なお、リモートバックエンドの種類複数存在しますが、AWSのリソースを管理することが多いため、本記事ではS3タイプのバックエンドに注目します。

バックエンド定義と初期化
まず、サンプルのmain.tfを作成しましょう。

main.tf


ここに通常のリソースとAWS設定に空のS3 Backendブロックを追加します。空であることは別のファイルで詳細を定義することを意味します。その詳細は環境ごとに分けてバックエンド.tfvarsファイルを作成します。

staging.backend.tfvars


production.backend.tfvars



御覧の通り、リモートステートを任意のS3バケットのkeyで示すパスに置いて、ローカルから実行する運用になります。同じバケットでも、tfstateのkeyが違うのであれば問題はないので、ディレクトリで分ける( /staging/ 配下など)をおすすめします。こうして「開発者ローカルからの簡単さ」と「安全で一貫性のある」運用のバランスが取れます。ワークスペース初期化の際は以下のコマンドでできます。

terraform init --backend-config=staging.backend.tfvars



変数の定義と実行方法
変数ファイル(variables.tf)も似たような運用になります。

vars.tf


staging.tfvars


production.tfvars


vars.tfではデフォルト値のみを定義し、各環境の.tfvarsファイルに適切な変数を定義します。実行は以下のように行います。

terraform apply --var-file=staging.tfvars



ステージング環境が初期化されていればプランが表示され、確認してから実行します。



S3のバケットを見ればtfstateファイルの存在を確認できます。


まとめ
いかがでしょうか。Terraformコマンドの実行の際にフラグを忘れないこと等、少しややこしいところもありますが、かなりシンプルに環境の操作もできるようになります。S3の他にも、Hashicorp様が提供しているTerraform Cloudのリモートステート・バックエンドとクラウドからのTerraformコマンド実行もありますので、興味のある方は是非ご覧ください。