こんにちは!PR TIMESの開発本部でインターンをさせていただいている西です。
とあるプロジェクトのインフラ構築にIaCの技術であるTerraformを用いたので、前半にはTerraformの基礎知識や導入メリット、開発効率を上げるために使ったツールについて、後半に実際にどのようなものを構築したかについて書きたいと思います。
Terraformとは?
HCLと呼ばれる専用の言語を用いてクラウドサービスを管理するオープンソースのIaCツールです。数百のクラウドサービスを一貫したワークフローで管理できます。例えばAWSやGCP、AzureなどをTerraformで管理できます。
HCLとは?
HashiCorp Configuration languageの略で、Terraformの開発元であるHashiCorp社が提供している設定言語のことです。TerraformはHCLで書かれた定義を元に実際のクラウドサービス上にインフラを構築します。
以下はHCL構文で書かれたコードの例です。
resource "aws_s3_bucket" "example_bucket" {
bucket = "example"
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
Terraformを導入するメリット
Terraformを使ってインフラを構築することで得られるメリットは以下の3つです。
- コードの適用だけでインフラを操作でき、構築の時短やミスの減少に繋がる
- コードを用いるためGitなどのバージョン管理システムで変更を管理できる
- 同じ構成のインフラが複数必要となったときに構築コストが下がる
Terraformを使えば以下の図のインフラをコマンド一発で構築できます。
しかし、コマンド一発で構築ができるようにするためにはTerraformにとって必要な定義をHCLで全て記述する必要があります。次は効率よくHCLを記述するために使ったTerraformの機能をいくつか紹介します。
terraform import
既存のインフラをTerraformの管理下に置くためのコマンドです。このコマンドを実行するとtfstateファイルにimport対象のインフラが追記されます。
https://www.terraform.io/cli/import
tfstateファイルとはTerraformが管理しているインフラの状態を保持しておくファイルのことです。このファイルがあるおかげでHCLで定義したものが実際に構築されているのかをTerraformが把握することができます。
tfstateファイルにはHCLで記述する設定のプロパティを見ることができます。この情報をヒントにできるのでHCLを容易に書き出していくことができます。
Terraform Workspace
Terraform WorkspaceはTerraformの標準機能でstateを分けて管理する機能です。
https://www.terraform.io/language/state/workspaces
先ほど話した通りTerraformは管理しているインフラの状態をtfstateファイルに保持します。
しかし、複数の環境(例えば本番環境やテスト環境)を1つのtfstateファイルでは管理できません。
Terraform Workspaceを使うと環境ごとにtfstateファイルを生成し、複数環境のインフラ構築を簡単に行うことができます。
tfcmt
これはTerraformの機能ではないですが、関連するOSSとして1つ紹介します。
tfcmtは元々、メルカリ社が公開しているtfnotifyをフォークして作られたもので、TerraformのCI体験をより良いものにするために作られたCLIツールです。
今回CI/CD実行環境としてGitHub Actionsを選択しました。
https://github.co.jp/features/actions
GitHubにTerraformの変更をプルリクエストとして送ることでGitHub ActionsがTerraformやtfcmtのコマンドを実行するように設定しています。
tfcmtを活用するとTerraformのコマンドを実行した際の結果をGitHubのコメントとして分かりやすくまとめてくれます。
実際に構築したもの
PR TIMESではサムネイル画像のアップロード先として従来のオンプレミスのファイルサーバーに加えて、Amazon S3も利用したいという要件がありました。今回は画像保存用のS3やアップロード用のAmazon API Gateway、各AWSサービスに権限を与えるためにAWS Identity and Access Management (IAM)のIAM RoleやIAM PolicyをTerraformで構築しました。要約すると下記図の通りです。
一部、HTTPのヘッダー情報(Cache-Control等)をS3オブジェクトのメタ情報として保存する必要があったため、API Gateway側で特定のヘッダーが通過することを許可する設定もしています。
先に手動でテスト環境を構築
Terraformで構築するためにまずはコンソール上から手動でテスト環境を構築しました。理由は主に以下の2つです。
- アプリケーション開発をしているメンバーへ早く動くインフラを提供するため
- 要件に合うものを先に作って主要な設定について把握するため
どちらも開発効率を上げるために必要でした。
Terraformを書くためには構築対象のインフラについて先に理解しておくことが必要だと感じます。なぜなら、対象のインフラについて全く知らない状態でTerraformのドキュメントと白紙のテキストエディタを眺めても何も書けないからです。完成イメージを知らされないまま、パズルのピースだけを渡されてそのパズルを今すぐ完成させてくださいと言われているような感じです。完成品を知ることによって効率よくパズルが組み上げられるようになるように、実際のインフラをよく触って必要な設定について理解することによってTerraformを書くことができるようになると感じます。
先にテスト環境を構築することで構築対象のインフラについて理解しました。
Terraformでテスト環境と同等のものを構築する際にterraform import
コマンドを多用しました。すでに説明した通りこのコマンドを用いると容易にHCLを書き出していけます。
用法についてはとても長くなりそうなので省略しますが、既存のインフラリソースをTerraform化する際はこのコマンドを使った方が圧倒的に早くHCLを生産できるのでオススメします。
Terraform Workspaceとlocalsを組み合わせた環境依存の値の注入
S3のバケット名やAmazon CloudWatchのロググループ名は環境ごとに変える必要があります。そこで今回はTerraform Workspaceとlocalsの機能を組み合わせて、それら環境依存の値を一括で管理する方法を考えました。
例えば以下のようなHCLコードを用意します。
# locals.tf
locals {
env = {
prod = {
example_bucket = "example-bucket"
}
dev = {
example_bucket = "example-bucket-dev"
}
}
}
# s3.tf
resource "aws_s3_bucket" "example_bucket" {
bucket = local.env[terraform.workspace]["example_bucket"]
}
このようにすることで、Terraform Workspaceで選択している環境の設定値を読むことができ、環境ごとに切り替える必要がある値をlocals.tfのように1枚のファイルで管理できるようになります。
以下のサイトが参考になりました。
まとめ
Terraformの導入メリットや便利な機能、それからPR TIMESで実際に構築したものについて書いていきました。Terraformでインフラをコード化することによって、開発者が慣れた形でインフラを管理できたり、コードを再利用することで同じ環境を複数用意する時間的コストを減らせたりできます。IaCの技術を活用した際に得られる開発体験は今後も生かせるといいなと感じます。