🌵
【terraform】GoogleStyleGuide咀嚼
概要
GoogleStyleGuide(terraform)
terrafomrを使用する為のベストプラクティス(Google公式)への自己解釈
特に留意するべきことを抜粋(意訳アリ・詳細はそれぞれリンク参照)
🪨スタイルと構造に関する一般的なガイドライン
🌵標準のモジュール構造に従う
- terraform実行ディレクトリには
main.tfを起因として、モジュールを呼び出す - モジュール配備ディレクトリには
README.mdを必ず配置 - terraform実行ディレクトリには
examples/ディレクトリを作成し、
サンプルコードをとREADME.mdを配置 - モジュールの
*.tfは目的別に分け、長大化を避ける - モジュールディレクトリには
CHANGELOG.mdを配置し履歴を手書きで残す
🌵命名規則を採用する
- リソース名には
_を使用する。-を使用しない - 参照されるリソースについては名前を簡略化する
- リソースタイプに含まれる文言をリソース名に含まない
-
aws_s3_bucketというリソース名に s3、bucket というワードは避ける
-
🌵変数を慎重に使用する
- すべての変数を
variables.tfで宣言する - 単位(MB・GB等)が影響する変数は、単位を変数名に組み込むとメンテナンス性が上がる
- 必須でないオプショナルな変数は、接頭語に
optionalなどを付与-
requiredの場合は特に明記しないことで差別化を計る
-
- ON・OFFの条件を判定する場合は、正(enable・true)の値を変数名に組み込む
- 変数名のdescriptionは必須明記
- 変数の型定義は必ず行う
- 環境に依存しない変数についてはデフォルト値を設ける
- 非公開のvalueについては、
.gitignoreに含まれるファイルで管理する
🌵出力を公開する
-
output.tfを使用する際は、仕様についてREADME.mdに明記する -
output.tfにて渡す変数は、descriptionを併せて記載する - variablesから、outputには直接変数を渡さないこと(依存関係が崩れる為)
🌵データソースを使用する
- データソースにて外部値を参照する場合は、引用するリソースと一緒の箇所に記載する
- 但し、データソースを多く参照する場合については専用の
data.tfを検討する
- 但し、データソースを多く参照する場合については専用の
🌵カスタム スクリプトの使用を制限する
- カスタムスクリプトは極力使用しないこと
- terraformの挙動が対応していない場合のみ使用
- カスタムスクリプトは
scripts/ディレクトリを作成して配備する - README.mdに詳細を記載し、メンテナンス性を担保すること
🌵静的ファイルを別のディレクトリに配置する
- terraformにて参照する静的ファイルは
files/ディレクトリ配下に配備する - template関数を使用して参照するファイルは
templates/ディレクトリ配下に配備する- templateファイルは拡張子
.tftplを使用する
- templateファイルは拡張子
🌵ステートフル リソースを保護する
- データベース・ディスクなどのステートフルリソースは削除保護を有効にする
🌵組み込みの書式設定を使用する
-
terraform fmtに準拠したコーディングをする(要はterraform fmtを実行しろ)
🌵式の複雑さを制限する
- 1行のコードに関数を多用しない
- local関数などを使用し、分割をこころがけ可読性をあげる
- 1行のコードに3項演算子を複数用いない
🌵条件値に count を使用する
- 条件付きでリソースをインスタンス化するには、count メタ引数を使用する
variable "readers" { description = "..." type = list default = [] } resource "resource_type" "reference_name" { // Do not create this resource if the list of readers is empty. count = length(var.readers) == 0 ? 0 : 1 ... }
🌵反復されるリソースに対して for_each を使用する
- 複数リソースを一括で作成する際は、
for_each関数を使用する
🪨再利用可能なモジュール
🌵モジュールで必要な API を有効にする
- GCPでterraformを使用する際は、
project_servicesリソースを使用してAPIを有効化する
🌵オーナー ファイルを含める
- すべての共有モジュールにOWNERS ファイルを含める
- GitHub では CODEOWNERSが相当
🌵タグ付きバージョンをリリースする
- バージョニングによって互換性を失うリソースについては、メジャーバージョンを固定する
🌵プロバイダやバックエンドを構成しない
- 共有モジュールでbackendやproviderは指定せず、terraformコマンド実行ディレクトリにて指定する
- providerバージョンを共有モジュールで記載する場合は、
required_providersブロックに最低限のバージョンを記載する
🌵複雑なロジックにインライン サブモジュールを使用する
- インラインサブモジュールとはモジュール内で更に呼び出す為のモジュールである
- モジュール内は完結に記載できるようサブモジュールを使用するケースがある
- インラインサブモジュールはモジュールからしか呼ばれなく、外部からは呼ばれない作りにする
🪨Terraform のルート モジュール
- ルートモジュールとはterraform CLIを実行するディレクトリを指す
🌵各ルート モジュールのリソース数を最小限に抑える
- ルートモジュールから呼び出されるリソースは100個未満に抑える
🌵環境固有のサブディレクトリにアプリケーションを分割する
- サービスのディレクトリ配下には下記の2つのディレクトリを設ける
- サービスモジュール
modules/- 再利用し、複数構築されるリソースはサービスモジュールと呼ぶ(EC2など)
- 再利用し、環境を跨ぐ(Stage・Prod)リソースは参照モジュールと呼ぶ(ACMなど)
- 環境ディレクトリ
environments/-
environments/ディレクトリ配下は環境ディレクトリを掘る
-
- サービスモジュール
🌵環境ディレクトリを使用する
- サービスモジュールは共通入力をハードコーディングする
- 環境毎の固有値は変数化して、ルートモジュールからの値を参照する構成にする
- 環境ディレクトリ配下に下記ファイルを必須とする
- tfstateを管理する
backend.tf - サービスモジュールをインスタンス化する
main.tf
- tfstateを管理する
- terraformの機能である、workspaceは非推奨
🌵リモート状態から出力を公開する
-
terraform_remote_stateとは、別のルートモジュールに存在するtfstateファイルの情報を読み込むことが可能である- e.g.)別ディレクトリの参照モジュールにある、VPCのtfstate情報を読み込む
参考サイト
- e.g.)別ディレクトリの参照モジュールにある、VPCのtfstate情報を読み込む
🌵マイナー プロバイダのバージョンに固定する
-
versions.tfというファイルを設け、terraformブロックにrequired_providersを記載する
🌵変数を tfvars ファイルに格納する
-
terraform.tfvarsに変数の値を入力する -
-var-fileはイレギュラーな為、使用しないこと
🪨バージョン管理
🌵デフォルトのブランチ戦略を使用する
- 機能ブランチ名は
feature/$feature_name - バグ修正ブランチ
fix/$bugfix_name
🌵ルート構成に環境ブランチを使用する
- 環境名・ブランチ名・ディレクトリ名は構成を考慮して設計する
e.g.)dev環境構築
devという名前の入ったブランチ名を使用し、環境ディレクトリ名はdevという名前で作成
🌵シークレットを commit しない
- secret情報はSecretManagerや環境変数を利用する
- terraformCLIを実行する際に、標準出力にアウトプットされるかも懸念すること
🪨運用
🌵常に計画してから始める
-
terraform plan事前に実行し、反映されるリソースについて計画通りであることを確認する
🌵既存のリソースのインポートを回避する
-
terraform importによる既存リソースのインポートは極力避ける- 手動で作成したリソースやリソースの来歴を完璧に把握するのが困難な為
🌵Terraform の状態を手動で変更しない
-
terraform.tfstateは手動で変更せず、terraform stateで更新する
🌵バージョンの固定状態を定期的に確認する
-
dependbotを使いバージョンの固定状態の問題性を定期的に確認する
🌵Terraform にエイリアスを設定する
- ローカル開発環境用にエイリアスを用意し、 コマンド短縮・タイポのフェイルセーフに万全を期す
alias tf="terraform"alias terrafrom="terraform"
🪨セキュリティ
🌵リモート状態を使用する
- 状態ファイル(tfstate)についてはリモートにて管理する
- チームにての共同作業が制限されるので、チーム内での構築ルールを設ける
- tfstateファイルについてはgitignoreに記載し、git管理外とする
🌵状態を暗号化する
- 状態ファイル(tfstate)の保存の際に必ず暗号化を行う(AWS・GCP)
- GOOGLE_ENCRYPTION_KEY やAWSのKMS
🌵シークレットを状態に保持しない
- シークレット情報についてはterraformのコード管理からは外す
- シークレットの箱はterraformで管理し、valueは手動で設定を行う
🌵機密出力をマークする
- 標準出力に出したくない機密情報については
sensitive = trueをリソースに組み込む- planやapplyに出力されないので、README.mdなどに明記すること
🌵職掌分散を確保する
- terraform実行の際に使用するプロファイルについては、権限を制限し必要最低限にする
🌵適用前のチェックを実行する
-
terraform vet planコマンドを事前に実行する- セキュリティ・コンプライアンスに準拠しているかを構築前にチェックし、
出力が無い状態をキープする
- セキュリティ・コンプライアンスに準拠しているかを構築前にチェックし、
🌵継続的な監査を実施する
- terraformで構築したリソースに対して、
terraform外部の自動セキュリティチェックを導入し安全性を担保する
🪨テスト
terraformCLIを実行する際の留意点して下記を挙げる
- Terraform テストを実行すると、実際のインフラストラクチャが作成、変更、破棄されるため、テストに時間と費用がかかる可能性がある
- エンドツーエンドの単体テストはterraformで完結しないが、ストランタイムの高速化・モジュール毎に反復開発が迅速に行えることを有効活用する
- tfstateファイルについてテスト中は極力弄らない。テスト中にtfstateファイルを弄ると、予期せぬリソース変更が検出される為
🌵最初は低コストのテスト方法を使用する
- 静的分析
コンパイラ・リンター・ドライランを使用しリソースを構築せず、構文・構造をテストする - モジュール統合テスト
サービス単位でモジュールを構築し、想定されるリソース群が作成されることを確認する - エンドツーエンドのテスト
テスト環境にて全てのリソースを構築し、本番と同等の環境が構築されることを確認する
🌵小規模で始める
- 小規模のテストを繰り返し実施した後に、複雑なテストを行いフェイルファストアプローチを実行する
🌵プロジェクト ID とリソース名をランダム化する
-
resource "random_id"を使用しリソース名の競合を避ける
🌵テストに別の環境を使用する
- テスト用の環境は個別で用意すること
- 構築・削除を前提とした環境とし、サービスアカウントやフォルダなどもテスト用を設ける
🌵すべてのリソースをクリーンアップする
- リソースはクリーンアップするまでがフローである(構築しっぱなしだと課金される為)
🌵テスト ランタイムを最適化する
- テストを並行して実行する
- フレームワーク(terratest)などを使用することで、並行してリソース構築が可能である
構築依存関係などを確認し、構築順が発生していないかを確認可能
- フレームワーク(terratest)などを使用することで、並行してリソース構築が可能である
- 段階的にテストする
- 別個にテストできるような構成に分離しておき、個別で反復開発できるよう独立させる
Discussion