web-dev-qa-db-ja.com

Terraform(Hashicorp)のさまざまな環境

私はTerraformを使用してAWSスタックを構築し、楽しんでいます。商用設定で使用する場合は、構成をさまざまな環境(QA、STAGING、PRODなど)で再利用する必要があります。

どうすればこれを達成できますか?以下のように環境ごとに異なる状態ファイルを渡しながらterraformのcliを呼び出すラッパースクリプトを作成する必要がありますか? Terraformによって提供されるよりネイティブなソリューションがあるかどうか疑問に思っています。

terraform apply -state=qa.tfstate
42
n00b

hashicorp best-practices repo をご覧になることをお勧めします。これは、(James Woolfendenが提案したものと同様に)さまざまな環境に対処するための非常に優れた設定です。

私たちは同様の設定を使用しており、それは非常にうまく機能します。ただし、このベストプラクティスリポジトリでは、Atlasを使用していることを前提としていますが、これは使用していません。非常に手の込んだRakefileを作成しました。これは、基本的に(ベストプラクティスのリポジトリを再び参照して)/terraform/providers/awsのすべてのサブフォルダーを取得し、名前空間を使用して異なるビルドとして公開します。したがって、rake -T出力には次のタスクがリストされます。

us_east_1_prod:init
us_east_1_prod:plan
us_east_1_prod:apply

us_east_1_staging:init
us_east_1_staging:plan
us_east_1_staging:apply

この分離により、devが独占的に変更を行って、prod内の何かに誤って影響を与える(さらには、破壊する)可能性があります。これは、状態ファイルが異なるためです。また、実際に製品に適用する前に、開発/ステージングの変更をテストすることもできます。

また、私は最近、この小さな記事に偶然遭遇しました。基本的に、すべてをまとめるとどうなるかを示しています。 https://charity.wtf/2016/03/30/terraform-vpc-and-why-you -want-a-tfstate-file-per-env /

20
Erik van Brakel

モジュールによるPaulのソリューションは正しい考えです。ただし、すべての環境(QA、ステージング、本番など)を同じTerraformファイルで定義する反対を強くお勧めします。そうした場合、ステージングに変更を加えるたびに、誤って本番環境を壊してしまうリスクがあり、これらの環境を最初から隔離しておくという点が部分的に無効になります。 Terraform、VPC、および環境ごとにtfstateファイルが必要な理由 を参照して、何が問題になるかについてのカラフルな説明をご覧ください。

各環境のTerraformコードを別のフォルダーに保存することを常にお勧めします。実際、各「コンポーネント」(データベース、VPC、単一のアプリなど)のTerraformコードを別々のフォルダーに保存することもできます。繰り返しになりますが、理由は分離です。1つのアプリに変更を加える場合(1日に10回行う可能性があります)、VPC全体を危険にさらしたくない(おそらく決して変更しない)ことです。

したがって、私の典型的なファイルレイアウトは次のようになります。

stage
  └ vpc
     └ main.tf
     └ vars.tf
     └ outputs.tf
  └ app
  └ db
prod
  └ vpc
  └ app
  └ db
global
  └ s3
  └ iam

ステージング環境のすべてのTerraformコードはstageフォルダーに入れられ、prod環境のすべてのコードはprodフォルダーに入れられ、環境の外部にあるすべてのコード(たとえばIAMユーザー、S3バケット)はglobalフォルダーに移動します。

詳細については、チェックアウト Terraform状態の管理方法 を参照してください。 Terraformのベストプラクティスの詳細については、本Terraform:Up&Runningをご覧ください。

15

バージョン0.10.0以降、Terraformはワークスペースの概念(0.9.xの環境)をサポートすることに注意してください。

ワークスペースは、Terraform状態の名前付きコンテナーです。複数のワークスペースがある場合、Terraform構成の1つのディレクトリを使用して、インフラストラクチャリソースの複数の異なるセットを管理できます。

詳細はこちら: https://www.terraform.io/docs/state/workspaces.html

14
Ronny López

Terraformの使用を拡大するとき、状態(開発者、ビルドプロセス、異なるプロジェクト間)を共有し、複数の環境とリージョンをサポートする必要があります。これには、リモート状態を使用する必要があります。テラフォームを実行する前に、状態を設定する必要があります。 (私はpowershellを使用しています)

$environment="devtestexample"
$region     ="eu-west-1"
$remote_state_bucket = "${environment}-terraform-state"
$bucket_key = "yoursharedobject.$region.tfstate"

aws s3 ls "s3://$remote_state_bucket"|out-null
if ($lastexitcode)
{
   aws s3 mb "s3://$remote_state_bucket"
}

terraform remote config -backend S3 -backend-config="bucket=$remote_state_bucket"  -backend-config="key=$bucket_key" -backend-config="region=$region"
#(see here: https://www.terraform.io/docs/commands/remote-config.html)

terraform apply -var='environment=$environment' -var='region=$region'

これで、状態がS3に地域ごと、環境ごとに保存され、他のtfプロジェクトでこの状態にアクセスできるようになります。

6

ラッパースクリプトを作成する必要はありません。環境変数をモジュールに分割し、最上位のterraformファイルを作成して、環境ごとにそのモジュールをインポートするだけです。十分な変数(通常はenv_nameとその他いくつか)を取得するようにモジュールを設定している限り、問題はありません。例として

# project/main.tf
module "dev" {
    source "./env"

    env = "dev"
    aws_ssh_keyname = "dev_ssh"
}

module "stage" {
    source "./env"

    env = "stage"
    aws_ssh_keyname = "stage_ssh"
}

# Then in project/env/main.tf
# All the resources would be defined in here
# along with variables for env and aws_ssh_keyname, etc.

2020/03/01を編集

この回答は現時点ではかなり古いですが、更新する価値があります。開発者とステージが同じ状態ファイルを共有することは悪いという批判は、見方の問題です。上記の正確なコードの場合、開発者とステージも同じコードを共有しているため、完全に有効です。したがって、「開発者を壊すことはあなたの段階を台無しにするでしょう」と正しいです。この回答を書いているときに私が注意しなかった重要なことは、source "./env"source "git::https://example.com/network.git//modules/vpc?ref=v1.2.0"と書くこともできました

そうすることで、リポジトリ全体がTFスクリプトのサブモジュールのようなものになり、1つのブランチをQAブランチとして分割して、参照をプロダクション環境としてタグ付けできます。これにより、開発環境を変更してステージング環境を破壊する問題が回避されます。

次の状態のファイル共有。 1回の実行ですべての環境を更新できるため、これは見通しの問題だと私は言います。変更をプロモートする際の時間の節約が役立つ小さな会社では、--targetを使用すると、通常、本当に必要な場合でも、慎重に処理を高速化できます。複数の異なる構成を環境全体にわずかに異なる方法で適用するよりも、1つの場所と1つのTerraformランからすべてを管理する方がエラーが発生しにくいことがわかりました。それらすべてを1つの状態ファイルに収めることで、変数v.sになるために本当に必要なことについてより厳しくする必要がありました。私たちの目的のために何がちょうどやり過ぎでしたか。それはまた、私たちの環境が互いから離れすぎてドリフトすることを可能にすることを非常に強く妨げました。 terraform planの出力に2k行が表示される場合、違いは主に、devとstageがprodのように見えないためです。フラストレーション要因だけで、私たちのチームはそれを正気に戻すよう促しました。

これに対する非常に強力な反論は、さまざまなコンプライアンスルールによってdev/stage/prodに同時に触れることができない大企業にいる場合です。そのシナリオでは、状態ファイルを分割することをお勧めしますhow実行しているterraform applyがスクリプト化されていることを確認してください。そうしないと、誰かが「ステージングで--target必要なのはこれ1つだけです。次のスプリントは修正するつもりです」と言ったときに、これらの状態ファイルがばらつくという非常に現実的なリスクがあります。このスパイラルが今すぐ何度も見られ、環境間のあらゆる種類の比較がせいぜい疑わしいものになっています。

2
Paul

このスレッドには良い答えがたくさんあります。私や他のいくつかのチームに役立つアイデアを提供します。

アイデアは、インフラストラクチャコード全体を含む単一の「傘」プロジェクトを持つことです。

各環境のterraformファイルには、「メイン」という単一のモジュールのみが含まれています。

次に、「メイン」にはリソースと他のモジュールが含まれます

- terraform_project
- env
  - dev01        <-- Terraform home, run from here 
    - .terraform    <-- git ignored of course
    - dev01.tf  <-- backend, env config, includes always _only_ the main module
  - dev02
    - .terraform
    - dev02.tf 
  - stg01
    - .terraform
    - stg01.tf
  - prd01
    - .terraform
    - prd01.tf 
- main        <-- main umbrella module
   - main.tf
   - variables.tf         
- modules         <-- submodules of the main module
  - module_a
  - module_b
  - module_c

また、サンプルの環境ホームファイル(例:dev01.tf)は次のようになります。

provider "azurerm" {
  version = "~>1.42.0"
}

terraform {
  backend "azurerm" {
    resource_group_name  = "tradelens-Host-rg"
    storage_account_name = "stterraformstate001"
    container_name       = "terraformstate"
    key                  = "dev.terraform.terraformstate"
  }
}

module "main" {
  source               = "../../main"
  subscription_id      = "000000000-0000-0000-0000-00000000000"
  project_name         = "tlens"
  environment_name     = "dev"
  resource_group_name  = "tradelens-main-dev"
  tenant_id            = "790fd69f-41a3-4b51-8a42-685767c7d8zz"
  location             = "West Europe"
  developers_object_id = "58968a05-dc52-4b69-a7df-ff99f01e12zz"
  terraform_sp_app_id  = "8afb2166-9168-4919-ba27-6f3f9dfad3ff"

  kubernetes_version      = "1.14.8"
  kuberenetes_vm_size     = "Standard_B2ms"
  kuberenetes_nodes_count = 4

  enable_ddos_protection = false
  enable_waf             = false
}

ありがとうございます。

  • 環境ごとにTerraformリモート状態ファイルの個別のバックエンドを持つことができます
  • 異なる環境に個別のシステムアカウントを使用できる
  • 環境ごとに異なるバージョンのプロバイダーとTerraform自体を使用できる(そして1つずつアップグレードできる)
  • 必要なすべてのプロパティが環境ごとに提供されていることを確認します(環境プロパティがない場合、Terraform検証は合格しません)
  • すべてのリソース/モジュールが常にすべての環境に追加されるようにします。モジュールが1つしかないため、モジュール全体を「忘れる」ことはできません。

ソースのブログ投稿を確認

0
Piotr Gwiazda