私は、インフラストラクチャーをテラフォームに切り替えるプロセスを進めています。 Terraformファイルと状態を実際に管理するためのベストプラクティスは何ですか?コードとしてのインフラストラクチャであることに気付き、.tfファイルをgitにコミットしますが、tfstateもコミットしますか?それはS3のような場所にあるべきですか?最終的にはCIでこのすべてを管理したいと思いますが、それは非常に広範であり、ファイルの動く部分を把握する必要があります。
私は実際に、実際に人々が実際にこの種の製品を生産でどのように利用しているかを見たいと思っています
また、既存のAWSインフラストラクチャをTerraformに移行している状態なので、開発中に回答を更新することを目指します。
私は、公式のTerraform examples と何度も試行錯誤に大きく依存して、不確実な領域を具体化してきました。
.tfstate
files
Terraform configを使用して、さまざまなインフラストラクチャに多くのボックスをプロビジョニングできます。各ボックスは異なる状態を持つことができます。複数の人が実行することもできるため、この状態は中央の場所(S3など)にある必要がありますが、notgitです。
これはTerraform .gitignore
を見ると確認できます。
開発者コントロール
私たちの目的は、完全な監査(gitログ)および健全性チェックの変更(プル要求)を維持しながら、開発者にインフラストラクチャの制御を強化することです。それを念頭に置いて、私が目指している新しいインフラストラクチャワークフローは次のとおりです。
編集1-現在の状態で更新
この回答を始めて以来、私はたくさんのTFコードを書いており、私たちの状況をより快適に感じています。私たちは途中でバグや制限にぶつかりましたが、これは新しい、急速に変化するソフトウェアを使用することの特徴だと思います。
レイアウト
それぞれに複数のサブネットを持つ複数のVPCを持つ複雑なAWSインフラストラクチャがあります。これを簡単に管理するための鍵は、インフラストラクチャコード(テラフォームとパペットの両方)を整理するために使用できる地域、環境、サービス、所有者を含む柔軟な分類法を定義することでした。
モジュール
次のステップは、テラフォームモジュールを格納する単一のgitリポジトリを作成することでした。モジュールの最上位ディレクトリ構造は次のようになります。
tree -L 1 .
結果:
├── README.md
├── aws-asg
├── aws-ec2
├── aws-elb
├── aws-rds
├── aws-sg
├── aws-vpc
└── templates
それぞれがいくつかの健全なデフォルトを設定しますが、「接着剤」によって上書きできる変数としてそれらを公開します。
接着剤
上記のモジュールを使用するglue
を備えた2番目のリポジトリがあります。これは、分類ドキュメントに沿ってレイアウトされています。
.
├── README.md
├── clientA
│ ├── eu-west-1
│ │ └── dev
│ └── us-east-1
│ └── dev
├── clientB
│ ├── eu-west-1
│ │ ├── dev
│ │ ├── ec2-keys.tf
│ │ ├── prod
│ │ └── terraform.tfstate
│ ├── iam.tf
│ ├── terraform.tfstate
│ └── terraform.tfstate.backup
└── clientC
├── eu-west-1
│ ├── aws.tf
│ ├── dev
│ ├── iam-roles.tf
│ ├── ec2-keys.tf
│ ├── prod
│ ├── stg
│ └── terraform.tfstate
└── iam.tf
クライアントレベル内には、グローバルリソース(IAMロールなど)をプロビジョニングするAWSアカウント固有の.tf
ファイルがあります。次はEC2 SSH公開キーを使用した地域レベルです。最後に、環境(dev
、stg
、prod
など)にVPCセットアップ、インスタンス作成、ピアリング接続などが保存されます。
サイドノート:ご覧のとおり、terraform.tfstate
をgitに保持するという上記の独自のアドバイスに反しています。これは、S3に移行するまでの一時的な措置ですが、現在私が唯一の開発者であるため、私には適しています。
次のステップ
これはまだ手動のプロセスであり、Jenkinsではまだ行われていませんが、かなり大規模で複雑なインフラストラクチャを移植しています。私が言ったように、バグはほとんどありませんが、うまくいきます!
編集2-変更
この最初の回答を書いてからほぼ1年が経ち、Terraformと私自身の状態は大きく変わりました。 Terraformを使用してAzureクラスターを管理する新しい立場になり、Terraformはv0.10.7
になりました。
状態
人々は繰り返しGitにnotするべきだと言ってきました-そして彼らは正しいです。開発者のコミュニケーションと規律に依存する2人のチームとの暫定的な手段としてこれを使用しました。大規模な分散チームでは、DynamoDBが提供する locking でS3のリモート状態を完全に活用しています。理想的には、これはconsulに移行され、クロスクラウドプロバイダーを削減するv1.0です。
モジュール
以前は、内部モジュールを作成して使用しました。これは今でも当てはまりますが、 Terraformレジストリ の出現と成長により、これらを少なくともベースとして使用しようとしています。
ファイル構造
新しい位置には、dev
とprod
の2つのinfx環境のみが含まれる、はるかに単純な分類法があります。それぞれに独自の変数と出力があり、上記で作成したモジュールを再利用します。 remote_state
プロバイダーは、作成されたリソースの出力を環境間で共有するのにも役立ちます。私たちのシナリオは、グローバルに管理されたTLDに対するさまざまなAzureリソースグループのサブドメインです。
├── main.tf
├── dev
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
└── prod
├── main.tf
├── output.tf
└── variables.tf
計画
この場合も、分散したチームの追加の課題により、常にterraform plan
コマンドの出力を保存します。 plan
ステージとapply
ステージの間で何らかの変更のリスクなしに実行されるものを検査して知ることができます(ロックはこれに役立ちますが)。このプランファイルには、プレーンテキストの「秘密」変数が含まれている可能性があるため、必ず削除してください。
全体的に、Terraformに非常に満足しており、追加された新しい機能を使用して学習と改善を続けています。
Terraformを頻繁に使用し、推奨されるセットアップは次のとおりです。
各環境(たとえば、stage、prod、qa)のTerraformコードを別々のテンプレートセット(したがって、個別の.tfstate
ファイル)に保存することを強くお勧めします。これは、変更を行っている間、実際には別々の環境が互いに隔離されるようにするために重要です。そうでなければ、ステージングでいくつかのコードをいじりながら、prodで何かを爆破するのは簡単すぎます。 Terraform、VPC、およびenvごとにtfstateファイルが必要な理由 を参照してください。理由のカラフルな議論について。
したがって、一般的なファイルレイアウトは次のようになります。
stage
└ main.tf
└ vars.tf
└ outputs.tf
prod
└ main.tf
└ vars.tf
└ outputs.tf
global
└ main.tf
└ vars.tf
└ outputs.tf
ステージVPCのすべてのTerraformコードはstage
フォルダーに格納され、prod VPCのすべてのコードはprod
フォルダーに格納され、VPCの外部に存在するすべてのコード(IAMユーザー、 SNSトピック、S3バケット)はglobal
フォルダーに移動します。
慣例により、Terraformコードは通常3つのファイルに分割されることに注意してください。
vars.tf
:入力変数。outputs.tf
:出力変数。main.tf
:実際のリソース。通常、インフラストラクチャは次の2つのフォルダーで定義します。
infrastructure-modules
:このフォルダーには、小さく再利用可能なバージョン付きモジュールが含まれています。各モジュールを、VPCやデータベースなどの単一のインフラストラクチャを作成する方法の青写真と考えてください。infrastructure-live
:このフォルダーには、infrastructure-modules
のモジュールを組み合わせて作成した実際の稼働中のインフラストラクチャが含まれます。このフォルダ内のコードは、設計図から構築した実際の家と考えてください。Terraformモジュール は、フォルダー内のTerraformテンプレートのセットです。たとえば、単一のVPCのすべてのルートテーブル、サブネット、ゲートウェイ、ACLなどを定義するinfrastructure-modules
のvpc
というフォルダーがあるとします。
infrastructure-modules
└ vpc
└ main.tf
└ vars.tf
└ outputs.tf
infrastructure-live/stage
およびinfrastructure-live/prod
でそのモジュールを使用して、ステージおよびprod VPCを作成できます。たとえば、infrastructure-live/stage/main.tf
は次のようになります。
module "stage_vpc" {
source = "git::[email protected]:gruntwork-io/module-vpc.git//modules/vpc-app?ref=v0.0.4"
vpc_name = "stage"
aws_region = "us-east-1"
num_nat_gateways = 3
cidr_block = "10.2.0.0/18"
}
モジュールを使用するには、module
リソースを使用して、そのsource
フィールドをハードドライブのローカルパス(たとえばsource = "../infrastructure-modules/vpc"
)にポイントするか、上記の例のようにGit URL( モジュールソース を参照)。 Git URLの利点は、特定のgit sha1またはタグ(ref=v0.0.4
)を指定できることです。これで、インフラストラクチャを小さなモジュールの束として定義するだけでなく、それらのモジュールをバージョン管理し、必要に応じて慎重に更新またはロールバックできます。
VPC、Dockerクラスター、データベースなどを作成するために、再利用可能、テスト済み、およびドキュメント化された多数の Infrastructure Packages を作成しましたが、そのほとんどはバージョン管理されたTerraformモジュールです。
Terraformを使用してリソース(EC2インスタンス、データベース、VPCなど)を作成すると、.tfstate
ファイルに作成内容に関する情報が記録されます。これらのリソースを変更するには、チームの全員が同じ.tfstate
ファイルにアクセスする必要がありますが、Gitにチェックインしないでください( ここで理由の説明 を参照)。
代わりに、Terraformを実行するたびに最新のファイルを自動的にプッシュ/プルする Terraform Remote State を有効にして、.tfstate
ファイルをS3に保存することをお勧めします。 S3バケットで バージョン管理を有効化 にして、何らかの理由で最新バージョンが破損した場合に古い.tfstate
ファイルにロールバックできるようにしてください。ただし、重要な注意事項:Terraformはロックを提供しません。そのため、2人のチームメンバーが同じterraform apply
ファイルに対して.tfstate
を同時に実行すると、互いの変更が上書きされる可能性があります。
この問題を解決するために、 Terragrunt と呼ばれるオープンソースツールを作成しました。これは、Amazon DynamoDBを使用してロックを提供するTerraformの薄いラッパーです(ほとんどのチームでは完全に無料です)。 Terragruntを使用してTerraformに自動リモート状態ロックと構成を追加する をご覧ください。
Terraformの総合ガイド と呼ばれる一連のブログ投稿を開始しました。これは、Terraformを実際の世界で使用するために学んだすべてのベストプラクティスを詳細に説明しています。
更新:Terraformブログポストシリーズの総合ガイドは非常に人気があったため、 Terraform:Up&Runningという本に拡張しました!
以前はremote config
でこれが許可されていましたが、現在は " backends "に置き換えられているため、Terraform Remoteは使用できなくなりました。
terraform remote config -backend-config="bucket=<s3_bucket_to_store_tfstate>" -backend-config="key=terraform.tfstate" -backend=s3
terraform remote pull
terraform apply
terraform remote Push
詳細については、 docs を参照してください。
@Yevgeny Brikmanにより詳細に説明されていますが、OPの質問に具体的に答えています。
Terraformファイルと状態を実際に管理するためのベストプラクティスは何ですか?
TFファイルにはgitを使用します。ただし、状態ファイル(tfstateなど)はチェックしないでください。代わりにTerragrunt
を使用して、S3への状態ファイルの同期/ロックを行います。
しかし、tfstateもコミットしますか?
番号。
それはS3のような場所にあるべきですか?
はい
ここには多くの答えがありますが、私のアプローチはかなり異なります。
⁃ Modules
⁃ Environment management
⁃ Separation of duties
モジュール
環境管理
IaCは、SDLCプロセスをインフラストラクチャ管理に関連させており、開発インフラストラクチャと開発アプリケーション環境があることを期待することは通常ありません。
職務の分離
小規模な組織にいる場合、または個人インフラストラクチャを実行している場合、これは実際には適用されませんが、運用の管理に役立ちます。
また、一部のリソースはめったに変更されず、他のリソースは常に変更されるため、リリースの問題にも役立ちます。分離はリスクと複雑さを取り除きます。
この戦略は、AWSのマルチアカウント戦略と類似しています。詳細をお読みください。
CI/CD
これは独自のトピックですが、Terraformは優れたパイプライン内で非常にうまく機能します。ここで最も一般的なエラーは、CIを特効薬として扱うことです。技術的にTerraformは、アセンブリパイプラインの段階でのみインフラストラクチャをプロビジョニングする必要があります。これは、通常、テンプレートを検証およびテストするCIステージで行われることとは別のものです。
N.B.モバイルで書かれているので、エラーを許してください。
それでもより良いソリューションを探している場合は、ワークスペース固有の変数を持つことができるさまざまな環境フォルダー構造の維持を置き換えることができるワークスペースを見てください。
Yevgeniy Brikman言及 のように、モジュール構造を持つ方が良いでしょう。
回答が非常に堅実で有益なものになる前に、ここに2セントを追加しようとします。
少ないリソースで作業する方が簡単で高速です。
terraform plan
とterraform
の両方を適用すると、リソースのステータスを確認するためにクラウドAPI呼び出しが行われます。爆発半径は、リソースが少ないほど小さくなります。
リモート状態を使用してプロジェクトを開始します。
tfstate
ファイルを管理するのは悪夢です。一貫した構造と命名規則を実践してみてください。
リソースモジュールはできるだけ単純にします。
ハードコード値を変数として渡すことも、データソースを使用して検出することもできません。
コンポジション内のインフラストラクチャモジュール間の接着剤として、特にdata
ソースとterraform_remote_state
を使用します。
(参照記事:https://www.terraform-best-practices.com/code-structure )
例:
より少ない数のリソースで作業する方が簡単で高速なので、以下に推奨されるコードレイアウトを示します。
注:各プロジェクトには固有の特性があるため、厳密には従わない参照と同じように
.
├── 1_tf-backend #remote AWS S3 + Dynamo Lock tfstate
│ ├── main.tf
│ ├── ...
├── 2_secrets
│ ├── main.tf
│ ├── ...
├── 3_identities
│ ├── account.tf
│ ├── roles.tf
│ ├── group.tf
│ ├── users.tf
│ ├── ...
├── 4_security
│ ├── awscloudtrail.tf
│ ├── awsconfig.tf
│ ├── awsinspector.tf
│ ├── awsguarduty.tf
│ ├── awswaf.tf
│ └── ...
├── 5_network
│ ├── account.tf
│ ├── dns_remote_zone_auth.tf
│ ├── dns.tf
│ ├── network.tf
│ ├── network_vpc_peering_dev.tf
│ ├── ...
├── 6_notifications
│ ├── ...
├── 7_containers
│ ├── account.tf
│ ├── container_registry.tf
│ ├── ...
├── config
│ ├── backend.config
│ └── main.config
└── readme.md