web-dev-qa-db-ja.com

Terraformを使用する際のベストプラクティス

私は、インフラストラクチャーをテラフォームに切り替えるプロセスを進めています。 Terraformファイルと状態を実際に管理するためのベストプラクティスは何ですか?コードとしてのインフラストラクチャであることに気付き、.tfファイルをgitにコミットしますが、tfstateもコミットしますか?それはS3のような場所にあるべきですか?最終的にはCIでこのすべてを管理したいと思いますが、それは非常に広範であり、ファイルの動く部分を把握する必要があります。

私は実際に、実際に人々が実際にこの種の製品を生産でどのように利用しているかを見たいと思っています

87
Marc Young

また、既存のAWSインフラストラクチャをTerraformに移行している状態なので、開発中に回答を更新することを目指します。

私は、公式のTerraform examples と何度も試行錯誤に大きく依存して、不確実な領域を具体化してきました。

.tfstate files

Terraform configを使用して、さまざまなインフラストラクチャに多くのボックスをプロビジョニングできます。各ボックスは異なる状態を持つことができます。複数の人が実行することもできるため、この状態は中央の場所(S3など)にある必要がありますが、notgitです。

これはTerraform .gitignore を見ると確認できます。

開発者コントロール

私たちの目的は、完全な監査(gitログ)および健全性チェックの変更(プル要求)を維持しながら、開発者にインフラストラクチャの制御を強化することです。それを念頭に置いて、私が目指している新しいインフラストラクチャワークフローは次のとおりです。

  1. 再利用可能なモジュールを含む一般的なAMIの基本基盤。傀儡。
  2. Terraformを使用してDevOpsによってプロビジョニングされるコアインフラストラクチャ。
  3. 開発者は、必要に応じてGitのTerraform構成を変更します(インスタンスの数、新しいVPC、リージョン/アベイラビリティーゾーンの追加など)。
  4. Git構成がプッシュされ、プルリクエストが送信され、DevOpsチームのメンバーによって健全性チェックが行われます。
  5. 承認された場合、CIにwebhookを呼び出してビルドおよびデプロイします(現時点で複数の環境をパーティション分割する方法は不明です)

編集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公開キーを使用した地域レベルです。最後に、環境(devstgprodなど)に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レジストリ の出現と成長により、これらを少なくともベースとして使用しようとしています。

ファイル構造

新しい位置には、devprodの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に非常に満足しており、追加された新しい機能を使用して学習と改善を続けています。

71
Ewan

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つのフォルダーで定義します。

  1. infrastructure-modules:このフォルダーには、小さく再利用可能なバージョン付きモジュールが含まれています。各モジュールを、VPCやデータベースなどの単一のインフラストラクチャを作成する方法の青写真と考えてください。
  2. infrastructure-live:このフォルダーには、infrastructure-modulesのモジュールを組み合わせて作成した実際の稼働中のインフラストラクチャが含まれます。このフォルダ内のコードは、設計図から構築した実際の家と考えてください。

Terraformモジュール は、フォルダー内のTerraformテンプレートのセットです。たとえば、単一のVPCのすべてのルートテーブル、サブネット、ゲートウェイ、ACLなどを定義するinfrastructure-modulesvpcというフォルダーがあるとします。

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という本に拡張しました!

77

以前は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 を参照してください。

9
Shantanu

@Yevgeny Brikmanにより詳細に説明されていますが、OPの質問に具体的に答えています。

Terraformファイルと状態を実際に管理するためのベストプラクティスは何ですか?

TFファイルにはgitを使用します。ただし、状態ファイル(tfstateなど)はチェックしないでください。代わりにTerragruntを使用して、S3への状態ファイルの同期/ロックを行います。

しかし、tfstateもコミットしますか?

番号。

それはS3のような場所にあるべきですか?

はい

4
Snowcrash

ここには多くの答えがありますが、私のアプローチはかなり異なります。

⁃   Modules
⁃   Environment management 
⁃   Separation of duties

モジュール

  1. リソースの論理コレクションのモジュールを作成します。例:DB、HA VM、自動スケーリング、DNS、PubSub、およびオブジェクトストレージを必要とするAPIをデプロイすることが目標の場合、これらのリソースはすべて単一のモジュールにテンプレート化する必要があります。
  2. 単一のリソースを利用するモジュールの作成は避けてください。これは実行可能であり、実行されており、レジストリ内の多くのモジュールがこれを実行しますが、インフラストラクチャオーケストレーションではなくリソースのアクセシビリティに役立つプラクティスです。例:AWS EC2のモジュールは、複雑な構成をより簡単に呼び出すことでユーザーがEC2にアクセスするのを支援しますが、1。の例のようなモジュールは、アプリケーション、コンポーネント、またはサービス駆動型インフラストラクチャを調整するときにユーザーを支援します。
    1. ワークスペースでのリソース宣言は避けてください。これは、コードを整理して整理することについてです。モジュールは簡単にバージョン管理されるため、リリースをより詳細に制御できます。

環境管理

IaCは、SDLCプロセスをインフラストラクチャ管理に関連させており、開発インフラストラクチャと開発アプリケーション環境があることを期待することは通常ありません。

  1. IaC環境の管理にフォルダーを使用しないでください。インフラストラクチャに共通のテンプレートがないため、これはドリフトにつながります。
  2. 単一のワークスペースと変数を使用して、環境仕様を制御してください。例:環境変数(var.stageが一般的)を変更すると、要件に合わせて計画が変更されるようにモジュールを作成します。通常、環境は可能な限り小さくする必要があり、量、露出、および容量は通常可変構成です。開発者はプライベートトポロジで1コアと1GB VMを1 RAM展開しますが、追加のパブリックトポロジを含む2コアと4GB RAMを備えた3 VMを運用できます。もちろん、バリエーションを増やすこともできます。devは、コストを節約するためにアプリケーションと同じサーバーでデータベースプロセスを実行できますが、プロダクションには専用のDBインスタンスがあります。これらはすべて、単一の変数、3項ステートメント、および補間を変更することで管理できます。

職務の分離

小規模な組織にいる場合、または個人インフラストラクチャを実行している場合、これは実際には適用されませんが、運用の管理に役立ちます。

  1. 職務、責任、またはチームごとにインフラストラクチャを分類します。例:基盤となる共有サービス(仮想ネットワーク、サブネット、パブリックIPアドレス、ロググループ、ガバナンスリソース、マルチテナントDB、共有キーなど)を中央ITが制御する一方で、APIチームはサービスに必要なリソース(VM、LB 、PubSubなど)、データソースおよびリモート状態のルックアップを通じて中央ITサービスを利用します。
    1. チームのアクセスを管理します。例:中央ITには管理者権限がありますが、APIチームはパブリッククラウドAPIの制限されたセットにのみアクセスできます。

また、一部のリソースはめったに変更されず、他のリソースは常に変更されるため、リリースの問題にも役立ちます。分離はリスクと複雑さを取り除きます。

この戦略は、AWSのマルチアカウント戦略と類似しています。詳細をお読みください。

CI/CD

これは独自のトピックですが、Terraformは優れたパイプライン内で非常にうまく機能します。ここで最も一般的なエラーは、CIを特効薬として扱うことです。技術的にTerraformは、アセンブリパイプラインの段階でのみインフラストラクチャをプロビジョニングする必要があります。これは、通常、テンプレートを検証およびテストするCIステージで行われることとは別のものです。

N.B.モバイルで書かれているので、エラーを許してください。

1
Henry Dobson

それでもより良いソリューションを探している場合は、ワークスペース固有の変数を持つことができるさまざまな環境フォルダー構造の維持を置き換えることができるワークスペースを見てください。

Yevgeniy Brikman言及 のように、モジュール構造を持つ方が良いでしょう。

0
Rajendra

回答が非常に堅実で有益なものになる前に、ここに2セントを追加しようとします。

コードを構造化するための一般的な推奨事項

  1. 少ないリソースで作業する方が簡単で高速です。

    • Cmdsterraform planterraformの両方を適用すると、リソースのステータスを確認するためにクラウドAPI呼び出しが行われます。
    • 単一のコンポジションにインフラストラクチャ全体がある場合、同じフォルダーに複数のファイルがある場合でも、これには数分かかることがあります。
  2. 爆発半径は、リソースが少ないほど小さくなります。

    • 無関係なリソースを別々のコンポジション(フォルダー)に配置することにより、互いに無関係なリソースを隔離することで、何か問題が発生した場合のリスクを軽減します。
  3. リモート状態を使用してプロジェクトを開始します。

  4. 一貫した構造と命名規則を実践してみてください。

    • 手続き型コードと同様に、最初に読むにはTerraformコードを記述する必要があります。一貫性は、6か月後に変更が発生したときに役立ちます。
    • Terraform state fileでリソースを移動することは可能ですが、構造と命名に一貫性がない場合は実行が難しくなる可能性があります。
  5. リソースモジュールはできるだけ単純にします。

  6. ハードコード値を変数として渡すことも、データソースを使用して検出することもできません。

  7. コンポジション内のインフラストラクチャモジュール間の接着剤として、特にdataソースとterraform_remote_stateを使用します。

参照記事:https://www.terraform-b​​est-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
0