この記事は Terraform Advent Calendar 2021 18日目の記事です。

Terraform を昨年末ぐらいから使い始め、仕事・プライベート問わずとにかく色々なところでコードを書きました。
今回は、この1年でどういうことをやったかを簡単にまとめます。
IaC って何?という方、興味はあるけどあまり使ってこなかった方、よくわからないまま使っている方などの参考になれば幸いです。

そもそも Terraform って?

昨今何かと話題の IaC (Infrastructure as Code) ツールで、HashiCorp 社によって開発されました。
以前書いた記事でも少し触れましたが、サーバなどのインフラリソースについて構築手順をコードに落とし込むことができます。
コード化することによって何が嬉しいかというと、

  • GUI のように操作感がコロコロ変わらず
  • 手順書のように実態と乖離しないよう追従する手間がかからず
  • 同じ構成を何度でも再現できる(冪等性の担保)

などがあげられます。
加えて、Terraform では宣言的にコードを書くことができます。
「あるべき姿」をコードに書くだけで良いので、利用者は細かい構築手順について把握する必要がありません。

簡単なセットアップならシェルスクリプトでなんとかなりますが、複雑になってくるにつれメンテナンスするのも大変になりがちです(会社だと作った人が退職している…みたいなことも起きます)。
設定ファイルは HCL (HashiCorp Configuration Language) という言語で書くことになるため、それを覚える必要はありますが、そこまで難しいものではないので比較的容易に習得できるのではと思います。

やったこと

大きく3つでした。

  • パブリッククラウドのリソースを作成する
  • GitHub の設定をコード化する
  • 作成した Terraform 設定ファイルを CI でチェックする

パブリッククラウドのリソースを作成する

一番多かったのはやはりこれですね。
かつて管理コンソールから作成されたリソースたちを terraform import を使ってコードへ落とし込むという作業がとにかく多かったです。

私は以下のような構成で作ることが多かったですが、ディレクトリ構成についてはベストプラクティスがまだ無さそうで先人たちも色々試行錯誤されているようです。

  • main.tf: エントリポイント

  • variables.tf: 変数宣言をするファイル

  • outputs.tf: 出力対象を記載するファイル

  • modules

    • variables.tf: 変数宣言をするファイル(モジュール内部用)
    • outputs.tf: 出力対象を記載するファイル(モジュール内部用)
    • alb.tf: alb / ecs / rds のように AWS のサービス単位で作成
    • ...

環境ごと(テスト環境・本番環境など)にインフラリソースが完全に分かれている場合は、環境ごとにディレクトリを作成してその中に tf ファイルを配置することもできます。
ただ、少なくとも私が見てきたプロダクトは環境間でリソースを共有していることが多かったので、この方法は使えませんでした。

ちなみに、「インフラリソースをコードで管理する」というだけなら CloudFormation でもできるんじゃね?というツッコミもあるかと思います。
しかしながら、CloudFormation は AWS リソースしか管理できません。
GCP や Azure など他のパブリッククラウドのリソースも管理したいとなった場合に都度ツールを変えるのは大変なのと、まあつぶしが効くだろうということで Terraform を選択しました。

もともとは VPS で個人用のサーバを運用していたのですが、今年からは AWS の Lightsail を使うようにしました。
それに伴い、リソースの作成は Terraform、サーバ内の各種セットアップは Ansible で行うようにしました。

GitHub の設定をコード化する

これは実運用というより、試しにやってみたものになります。
GitHub Actions を使うことが多かったので、そこで利用する環境変数を設定する記事を以前書きました。

それに加えて、最近はブランチのプロテクションルールを設定したりするようなコードも書きました。
気になる方は以下をご覧ください。

作成した Terraform 設定ファイルを CI でチェックする

以前の記事で GitHub Actions の便利な action についてご紹介しました。
そこで触れた terraform-pr-commenter を利用して、PR 作成時にいくつかのチェックを自動で実行しています。

on: [pull_request] # PR 作成時に実行する

jobs:
  terraform:
    step:
      # Terraform のセットアップ
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v1
        with:
          terraform_version: 1.0
          cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
      # terraform validate でエラーが起きた場合、結果を PR にコメントする
      - name: Post Validate
        if: ${{ always() && github.ref != 'refs/heads/main' && (steps.validate.outcome == 'failure') }}
        uses: robburger/terraform-pr-commenter@v1
        with:
          commenter_type: validate
          commenter_input: ${{ format('{0}{1}', steps.validate.outputs.stdout, steps.validate.outputs.stderr) }}
          commenter_exitcode: ${{ steps.validate.outputs.exitcode }}
      # terraform plan の結果を PR にコメントする
      - name: Post Plan
        if: ${{ always() && github.ref != 'refs/heads/main' && (steps.plan.outcome == 'success' || steps.plan.outcome == 'failure') }}
        uses: robburger/terraform-pr-commenter@v1
        with:
          commenter_type: plan
          commenter_input: ${{ format('{0}{1}', steps.plan.outputs.stdout, steps.plan.outputs.stderr) }}
          commenter_exitcode: ${{ steps.plan.outputs.exitcode }}

修正して Push する度、そのソースを利用して terraform plan した結果をコメントしてくれます。

まとめ

いかがだったでしょうか。
この記事を読んだ方が少しでも Terraform や IaC に興味を持っていただけると幸いです。