こんにちは!はじめまして。
ドリコムSRE部のsasaです。新社会人です。 ドリコムでは、AWSのリソース管理にTerraformというツールを使っています。
Terraformはコードによってインフラの構成を記述できるツールで、DevOpsによる開発を進める上で効率を良くしてくれます。
この記事では、新米SREの方向けにTerraformを使ったAWSでのインフラ設計のポイントや、具体的な利用方法をサンプルコードを加えて説明します。

目次

対象読者&記事の目的

  • AWSを感覚で触ったことがある人
  • Terraformを試しに触ったことがあるけど、まだちゃんとは使ってない人
  • Terraformと聞いて「火星・ゴキブリ」のキーワードしか思い浮かばない人
関係ないですが、Terraform使う人のことをTerraformerって呼びたいです。
この記事を読んだ後は、あなたはこのようになっています。
  • Workspaceの使い方が分かる
  • Terraformでworkspaceを使ったAWSリソースの管理ができる
  • IaC(Infrastructure as Code)による効率的なインフラ運用が実践できる

Terraformとは?

改めて、TerraformはHashiCorpによって開発されたインフラ構築の自動化ツールです。リソースの変更をコード上で行うことで管理画面での人力操作を減らし、操作ミスや画面ポチポチの面倒さから解放してくれます。
AWS・GCP・Azureはもちろん、有名なクラウドサービスにはほとんど対応しています。
利用できるサービス一覧
また、2021年6月8日にTerraformのv1.0がリリースされました。今後はより安定した運用ができそうです。

Terraformの機能: Workspaceとは?

複数のインフラ環境を workspace という単位で分けて管理することができます。
Workspaceの特徴として、複数の workspace で一つのソースコードを共有します。
詳しくは後述の設計のポイントにて説明しますが、
Workspaceを使うことで新たな環境を簡単に構築できます。

環境を分ける意義

本番環境・ステージング環境などのように環境を分けることで、本番環境以外の環境でリソースを変更しても本番環境には影響はありません(大事)。よって私たちエンジニアは安心して作業を行うことができるし、ビジネス側の人への説得材料にもなります。

Workspaceの活用方法

ドリコムでは、基本的に最低3つのworkspaceを使っています。
common 、system 、$envです。必要があれば$envはproduction、staging、dev1など増やしていくことができます。
新たな環境を構築するときは、workspaceを作れば良いだけなので簡単にできます。
$ terraform workspace new dev1      # workspace「dev1」を作成 
$ terraform workspace select dev1 # 現在のworkspaceを「dev1」に切り替え
全体像としては下図のような感じになっています。なんだか色々あるので、ここでは眺めるだけで大丈夫です。
リソースは土台となるcommonから作っていきます。

common

commonは主にRegion = Globalとなるリソースが集約されたworkspaceで、最初に実行するものとなります。
例: ACM、IAM、S3(lambda bucket)

system

systemはリージョン別リソースかつ $env にて共通で利用するリソースが集約されたworkspaceです。
common の次に実行するものになります。
例: S3(Log)、 ECR、CloudWatch、Lambda(監視用)

$env

$envはアプリケーション用に利用するリソースが集約されたworkspaceです。
例: VPC、ALB、ECS、AutoScaling、RDS、ElastiCache

そのほかの環境を分ける方法

workspaceの他に環境を分ける方法としては、 module(リソースをテンプレート化する機能)を用意して、各環境のディレクトリごとにmoduleを呼び出すコードを複製して調整する といった方法があります。

ドリコム式Workspaceのメリット

workspaceを分けることでコードを共有したまま環境(tfstateファイル)が別々に生成されます。

workspaceを使うことにより、アプリケーション用のAWS環境をproduction staging に続き、dev1やdev2なども簡単なコマンドと設定ファイルを編集するだけで作れるようになります。

また、common、system、productionと環境を分けることで、一回当たりのapplyの実行時間が短くなり、影響リスクも分割されます。

さらに、環境を分けることでリソースの作成に間が生まれ、IAMリソース作成直後のリソース作成に失敗しないというメリットもあります。 ドリコムでは本番環境・ステージング環境・負荷テスト環境・開発環境1・開発環境2など、環境を複数作成して開発したいというニーズがあります。
そのため、環境ごとにファイルを複製せずにコードの共有ができるこの方法を採用しています。

デメリット

メリットがあればもちろんデメリットもあります。
今回のWorkspaceを使う方法はリソースを環境ごとに分けるためにcountを使っていて、全体の見通しが悪くなってしまいます。
また、workspace間での関連リソースの値を渡すためにoutputの記述も必要になるので、乱雑になる場合もあります。

設計のポイント

基本的な設定は、variables.tfファイルの中を編集するだけでいいようになっています。
また、基本から外れるシステムなどは*_variables.tfファイルを編集することでリソースの有効化・無効化を切り替えられるようになっています。
環境ごとによるリソース作成の制御には、countパラメータを使っています。
例を見てみましょう。

下記はサンプルのapp runnerのIAMロールリソースのコードです。
count = local.on_common ? 1 : 0のように、三項演算子によってTrueであれば1(ON)、Falseであれば0(OFF)というように設定します。
なお、このlocal.on_commonはvariables.tf内に定義されています。
terraform-onboarding/variables.tf


resource "aws_iam_role" "apprunner" {
count = local.on_common ? 1 : 0 # リソースの作成制御
name = format("%s-%s", local.service_name, "apprunner")
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": [
"build.apprunner.amazonaws.com",
"tasks.apprunner.amazonaws.com"
]
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
variables.tfでは下記のように変数が書かれています。
terraform-onboarding/variables.tf


locals {
env = terraform.workspace
on_common = local.env == "common" ? true : false
on_system = local.env == "system" ? true : false
on_service = local.env != "common" && local.env != "system" ? true : false
}
特定の$envのみで特殊な対応をする場合、on_$envを追加します。
例: productionだけデプロイパイプラインを作成したいとき
terraform-onboarding/variables.tf


locals {
env = terraform.workspace
on_common = local.env == "common" ? true : false
on_system = local.env == "system" ? true : false
on_service = local.env != "common" && local.env != "system" ? true : false
on_production = local.env == "production" ? true : false # 必要に応じて追加していく
}

TerraformのCI

ドリコムでは、GitLabのmaster以外のブランチにpushするだけでGitLab Runner上で$ terraform plan を実行し、masterブランチ にmergeされると$ terraform applyを実行します。
applyによって変更されたtfstateファイルは、自動でmasterブランチに更新されます。

今回、サンプルコードでGitlab CIは扱っていないですが、下図のような構成になっています。
人が操作するのは図の青線の部分(①、③、⑤)だけで済むようになっています。すごいお手軽です。
  1. ローカルブランチで事前にcommonなどの名前でブランチを作成してcheckoutし、$ terraform planでエラーが出ないかチェックした後、git pushします
  2. gitlabにpushされたらgitlab runner上でDockerが起動し、$terraform init$terraform get$terraform planが実行され、その結果が社内のチャットアプリで通知されます
  3. gitlabのplan jobが成功したら、masterにマージリクエストを出します
  4. masterにmergeされたらgitlab runner上で$terraform init$terraform get$terraform applyが実行され、結果がチャットアプリに通知されます
    1. また、applyを実行するとtfstateファイルが更新されるため、master ブランチに変更内容を適用します
  5. 更新されたmasterブランチをローカルにpullして、また次のサイクルに進んでいきます
    1. 途中で失敗した場合は、pullした後コードを修正し、再びpush&マージリクエストを出していきます

Workspace実用サンプル

それでは、今回用意したWorkspaceの使用例のサンプルをみてみましょう。
Terraform_onboardingサンプルコード
このサンプルではLambdaとApp runnerというサービスを使って、hello worldなシステムを構築します。

AWSの構造は下図のようになります。新米SRE向けの内容のため極力シンプルに、そして最新のAWSの機能(App Runnerは2021年5月に発表されました)も使えるようになっています。AWSアカウントをお持ちの方は是非お手元の環境で遊んでみてください!
READMEに実行手順が書かれています。
詳細な手順はREADMEにあるので、ここでは体験してもらう流れだけ紹介します。
  1. 共通系(common)のリソース構築
  2. システム系(system)のリソース構築
  3. curlでLambdaの動作確認
  4. 本番環境(production)のリソース構築
  5. ブラウザでApp runnerの動作確認
  6. 各環境のお掃除
最後のお掃除は忘れずに!「後でやろっと」と思っていると痛い目に遭います。(自戒

最後に

ここまででドリコムでのTerraformの使い方について紹介していきました。
Terraformにおける環境の分け方はいくつかの方法があり、それぞれ長所・短所があります。環境の分け方については、こちらのフューチャー技術ブログ様の方で取り上げられています。
Terraformのベストなプラクティスってなんだろうか

どの方法にも一長一短ありますが、ドリコム式Workspaceのメリットで述べたように一回のapplyにかかる時間が短くなる点、環境がworkspace newと設定ファイルの編集だけで追加できる点の二つでworkspaceの恩恵が大きいです。

また、今回Terraformを使ったAWSの環境構築を体験できるサンプルコードを用意しましたが、もっとAWSのリソースを使って勉強したい方には「実践Terraform」という書籍がおすすめです。
「Pragmatic Terraform on AWS」あらため『実践Terraform』を商業出版します

新米SRE、Terraformを初めて導入する方、Terraformの運用に迷っている方、IaCに興味がある方達の参考になれば幸いです。

それではノシ

ドリコムでは一緒に働くメンバーを募集しています! 募集一覧はコチラを御覧ください!