こんにちは。河内です。 これは FLINTERS advent calendar 2022 2日目の記事です。 2022年にやってよかったこととして、今日は tfmigrate の導入について書きます。
terraform でインフラを管理していて、しばらく経つと state を変更したくなる場面があります。例えば、一度手動で作ったリソースを import したいときとか、 .tf ファイルをリファクタリングしたいときとか、provider を更新するときとか。
terraform では terraform import や terraform state といったコマンドで state ファイルの編集ができます。 しかしこれらのコマンドは、手で実行するしかなく、レビューを受けることが難しく、履歴があとに残りません。
tfmigrate を使うと terraform import や terraform state コマンドをファイルとして記録し、Git で管理できるようになります。Git で管理できるということは、他のコードでやっているようにレビューを受けたり、CIで実行することが簡単にできるようになることを意味します。
導入したプロジェクトでは GitLab CI を用いているので、ここではそれ前提で話をします。
tfmigrate でどこまで適用したかは、ファイルに記録されます。ローカルファイルの他にS3とGCS上に記録するオプションがあります。
CIで実行する際には、S3やGCSを使うのが楽でしょう。
我々は terraform の state を S3 においていることを踏まえて S3 を選択しました。
このあたりの設定は .tfmigrate.hcl
に書きます。書き方は tfmigrate の README をご参照ください。
我々は tfmigrate/
というディレクトリに tfmigrate 用の migration ファイルを置くと決め、MR *1 で tfmigrate/
以下に変更があれば、CI で tfmigrate 用のパイプラインを実行するようにしました。
tfmigrate の設定 .tfmigrate.hcl
は例えば次のようになります。
tfmigrate { migration_dir = "./tfmigrate" history { storage "s3" { bucket = "my-bucket" key = "tfmigrate-history.json" region = "ap-northeast-1" } } }
GitLab CI の設定 .gitlab-ci.yml
から該当部の雰囲気を抜き出すと次のようになります。
# tfmigrate plan を実行する CI job tfmigrate-plan: # tfmigrate の入った image を指定 image: my-tfmigrate-image rules: # default branch に対する MR でのみ実行 - if: "$CI_PIPELINE_SOURCE != 'merge_request_event' && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH" when: never # tfmigrate/ 以下に変更があるときのみ実行 - changes: - tfmigrate/* when: on_success script: - tfmigrate plan # tfmigrate apply を実行する CI job tfmigrate-apply: image: my-tfmigrate-image needs: # tfmigrate-plan job が成功していたら実行できる - tfmigrate-plan rules: - if: "$CI_PIPELINE_SOURCE != 'merge_request_event' && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH" when: never - changes: - tfmigrate/* # plan 結果を確認した後に job 実行は手動キック when: manual script: - tfmigrate apply
上記では記載していませんが、通常時に実行される terraform plan → terraform apply の job は、 tfmigrate/
以下に変更がある場合には実行されないように rules
を追加してあります。
以上で導入が完了です。以後 tfmigrate/
以下にファイルを追加して、terraform state の変更がレビュー、CIから実行できるようになりました。
プロジェクトでは実際に AWS provider を version 4 に上げる 際に活用されたりしています。
導入した感想
tfmigrate plan は、内部で terraform plan を実行し、差分が出ないことを要求します。 これが tfmigrate の migration を書く際に大きな安心感をもたらすことを実感しました。 terraform plan で差分が出ないなら、state の書き換えは間違っていないと確信できます。
しかし現実ではうまくいくことばかりではなく、 terraform apply しても terraform plan で差分が出続けてしまうことがあるため、tfmigrate plan が通らずに困ってしまいました。
現状は、 lifecycle { ignore_changes = ... }
で差分を一時的に無効化しておき、tfmigrate apply 後に無効化を取り消すという回避策を取っています。
terraform plan で差分が出続けるのはおそらく provider の問題の場合が多いように思うので、そのうち出なくなるといいなあ。
まとめ
terraform を使っているプロジェクトで tfmigrate を導入すると、state を自信をもって書き換えられるようになるよ。オススメ!
*1:MR: Merge Request。PR: Pull Request の GitLab 用語。merge を要求するので MR のほうが意味が通っているように思えるが、GitLab を使っていない人には PRと言ったほうが通じやすい。