Terraform プロジェクトでコードを重複させずに複数の環境をデプロイする方法

著者は、自由でオープンソースの基金を選定し、Write for DOnationsプログラムの一部として寄付を受け取ることにしました。

紹介

Terraformは、プロジェクトの規模と複雑性が増すにつれてますます有用になる高度な機能を提供しています。複数の環境に対する複雑なインフラ定義の維持コストを軽減するために、コードを構造化して反復を最小限に抑え、テストやデプロイを容易にするツール支援のワークフローを導入することができます。

Terraformは、バックエンドとステートを関連付け、ステートの保存および取得の方法と場所を決定します。すべてのステートは1つのバックエンドにのみ関連付けられ、インフラ構成と結びつけられています。いくつかのバックエンド、例えばlocals3は、複数のステートを含むことがあります。その場合、ステートとインフラをバックエンドに対してペアリングすることで、ワークスペースを記述しています。ワークスペースを使用することで、異なるバックエンドに保存しないで、同じインフラ構成の複数の異なるインスタンスをデプロイすることができます。

このチュートリアルでは、まず異なるワークスペースを使用して複数のインフラインスタンスをデプロイします。次に、このチュートリアルでは、デジタルオーシャンボリュームとして stateful resource をデプロイします。最後に、Terraform Registryから既に作成されたモジュールを参照します。これらのモジュールを使用することで、自分のものを補完することができます。

前提条件

このチュートリアルを完了するためには、以下が必要です。

  • デジタルオーシャンの控制在面板上に作成できる個人的なアクセストークン。デジタルオーシャンのプロダクト文書にある個人的なアクセストークンを作成する方法に基づいて、指示を探してください。
  • 本地マシンにTerraformをインストールし、DOプロバイダーを使用したプロジェクトを設定します。ステップ1ステップ2Terraformをデジタルオーシャンで使用する方法チュートリアルを完了し、プロジェクトフォルダーをterraform-advancedに名前を付けて、loadbalanceを使用しないでください。ステップ2の間、pvt_key変数とSSHキーリソースを含めないでください。

注意:このチュートリアルは、Terraform 1.0.2で特定にテストされています。

ワークスペースを使用して複数のインフラステークスのインスタンスをデプロイする

複数のワークスペースは、メインインフラステークスの変更されたバージョンをデプロイまたはテストするために便利であること、別のプロジェクトを作成して再度認証キーを設定する必要がないことをいくつか示します。独自の状態で開発およびテストを行った後、新しいコードをメインワークスペースに取り込むことができ、追加の状態を可能に削除することができます。Terraformプロジェクトをinitする際に、後端に関係なく、Terraformはdefaultという名前のワークスペースを作成します。これは常に存在し、削除することはできません。

しかし、複数のワークスペースは、ステージングやプロデューションなどの複数の環境を作成するための適切な解決策ではないこと、また、状態を追跡するだけであるため、コードやその変更を保存しません。

ワークスペースは実際のコードを追跡しないため、複数のワークスペース間でのコード分離をバージョンコントロール(VCS)レベルで管理する必要があります。これは、それぞれのインフラ変体に一致させて行うべきです。これを達成する方法は、VCSツール自体に依存します。例えば、Gitブランチは適切な抽象化となります。複数の環境向けのコード管理を容易にするために、それらを再利用可能なモジュールに分けることができ、各環境に同じコードを繰り返すのを避けることができます。

ワークスペースにリソースをデプロイする

今から、複数のワークスペースから適用するDropletをデプロイするプロジェクトを作成します。

Dropletの定義をdroplets.tfというファイルに保存します。

terraform-advancedディレクトリにいることを前提に、編集するために作成し開くには以下を実行します:

  1. nano droplets.tf

以下の行を追加します:

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-18-04-x64"
  name   = "web-${terraform.workspace}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

この定義は、fra1リージョンで1つのCPUコアと1GBのRAMを持つUbuntu 18.04で動作するDropletを作成します。その名前には、デプロイされた現在のワークスペースの名前が含まれます。完了したら、ファイルを保存して閉じます。

Terraformのプロジェクトを適用して、アクションを実行するために:

  1. terraform apply -var "do_token=${DO_PAT}"

出力はこのようになります:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.web を作成します + resource "digitalocean_droplet" "web" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "web-default" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = (known after apply) + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) + vpc_uuid = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. ...

質問にyesを入力して、defaultワークスペースにDropletをデプロイしてください。

Dropletの名前はweb-defaultになります、なぜなら開始したワークスペースの名前がdefaultからなるからです。ワークスペースを一覧表示して、唯一利用可能なものであることを確認することができます:

  1. terraform workspace list

出力はこのようになります:

Output
* default

星号(*)は、現在選択されているワークスペースを意味します。

新しいワークスペースtestingを作成して、defaultから異なるDropletをデプロイするためにworkspace newを実行します。

  1. terraform workspace new testing

出力はこのようになります:

Output
Created and switched to workspace "testing"! You're now on a new, empty workspace. Workspaces isolate their state, so if you run "terraform plan" Terraform will not see any existing state for this configuration.

Dropletのデプロイを再度計画し、以下のように実行します:

  1. terraform plan -var "do_token=${DO_PAT}"

出力は前回の実行と似ています:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.web を作成します + resource "digitalocean_droplet" "web" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "web-testing" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = (known after apply) + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) + vpc_uuid = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. ...

注意してください、Terraformはweb-testingという名前のDropletをデプロイする計画しており、web-defaultとは異なる名前を付けています。これはdefaulttestingのワークスペースが分離された状態であり、それぞれのリソースについて他のワークスペースに認識されていません。

workspace showを実行して、現在のtestingワークスペースを確認します:

  1. terraform workspace show

出力は現在のワークスペースの名前です。

Output
testing

ワークスペースを削除するには、まずそれに紐付くすべてのデプロイされたリソースを破棄する必要があります。その後、活性状態の場合は、workspace selectを使用して別のワークスペースに切り替える必要があります。ここでのtestingワークスペースは空であるため、すぐにdefaultに切り替えることができます。

  1. terraform workspace select default

Terraformのworkspace selectコマンドの出力が表示されます。

Output
Switched to workspace "default".

次に、workspace deleteを実行することで削除することができます。

  1. terraform workspace delete testing

Terraformはその後削除を行います。

Output
Deleted workspace "testing"!

また、defaultワークスペースでデプロイしたDropletを削除するには、以下のようにします。

  1. terraform destroy -var "do_token=${DO_PAT}"

質問に答えて、プロセスを完了させます。

ここで、いくつかのTerraformワークスペースで作業しました。次のセクションで、状態を持つリソースをデプロイします。

状態を持つリソースのデプロイ

状態を持たないリソースはデータを保持しないため、それらは独特ではないため、素早く作成や置き換えが可能です。しかし、状態を持つリソースは、再作成できないか独自のデータを含んでいるため、持続的なデータストORAGEが必要です。

これらのリソースを破棄するか、複数のリソースがそれぞれのデータを必要とする場合、別のエンティティにデータを格納することが最善です。例えば、DigitalOcean Volumesなど。

ボリュームは追加のストレージスペースを提供します。ボリュームはドロップレット(サーバ)に添付できますが、それらとは独立しています。この手順で、droplets.tfにボリュームを定義し、ドロップレットに接続します。

編集用に開いてください:

  1. nano droplets.tf

以下の行を追加してください:

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-18-04-x64"
  name   = "web-${terraform.workspace}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

resource "digitalocean_volume" "volume" {
  region                  = "fra1"
  name                    = "new-volume"
  size                    = 10
  initial_filesystem_type = "ext4"
  description             = "New Volume for Droplet"
}

resource "digitalocean_volume_attachment" "volume_attachment" {
  droplet_id = digitalocean_droplet.web.id
  volume_id  = digitalocean_volume.volume.id
}

ここで、自分自身のボリュームと、ボリュームのアタッチメントを2つ新しいリソースとして定義します。ボリュームは10GBで、ext4としてフォーマットされ、new-volumeと名付け、ドロップレットと同じリージョンに配置されます。ボリュームとドロップレットは独立した实体であるため、彼らを接続するためにボリュームのアタッチメントオブジェクトを定義する必要があります。volume_attachmentはドロップレットとボリュームのIDを取り、デジタルオーシャンクラウドに対して、ボリュームをドロップレットのディスク装置として利用可能にするよう指示します。

終わったら、ファイルを保存して閉じてください。

以下のように構成を計画する:

  1. terraform plan -var "do_token=${DO_PAT}"

Terraformが計画するアクションは以下のようになります:

Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # digitalocean_droplet.web を作成します + resource "digitalocean_droplet" "web" { + backups = false + created_at = (known after apply) + disk = (known after apply) + id = (known after apply) + image = "ubuntu-18-04-x64" + ipv4_address = (known after apply) + ipv4_address_private = (known after apply) + ipv6 = false + ipv6_address = (known after apply) + ipv6_address_private = (known after apply) + locked = (known after apply) + memory = (known after apply) + monitoring = false + name = "web-default" + price_hourly = (known after apply) + price_monthly = (known after apply) + private_networking = (known after apply) + region = "fra1" + resize_disk = true + size = "s-1vcpu-1gb" + status = (known after apply) + urn = (known after apply) + vcpus = (known after apply) + volume_ids = (known after apply) + vpc_uuid = (known after apply) } # digitalocean_volume.volume を作成します + resource "digitalocean_volume" "volume" { + description = "New Volume for Droplet" + droplet_ids = (known after apply) + filesystem_label = (known after apply) + filesystem_type = (known after apply) + id = (known after apply) + initial_filesystem_type = "ext4" + name = "new-volume" + region = "fra1" + size = 10 + urn = (known after apply) } # digitalocean_volume_attachment.volume_attachment を作成します + resource "digitalocean_volume_attachment" "volume_attachment" { + droplet_id = (known after apply) + id = (known after apply) + volume_id = (known after apply) } Plan: 3 to add, 0 to change, 0 to destroy. ...

Terraformは、ドロップレット、ボリューム、およびボリュームのアタッチメントを作成する詳細を出力します。これは、ボリュームをドロップレットに接続するためのアクションです。

これで、ステートフルリソースとしてボリュームをドロップレットに定義して接続しました。次のセクションで、プロジェクトに取り込むことができる既存のTerraformモジュールを確認します。

既存のモジュールを参照する

プロジェクトに独自のモジュールを作成する以外に、他の開発者によって作成され、Terraform Registryで公開されている既存のモジュールやプロバイダーを使用することもできます。

モジュールセクションで、利用可能なモジュールのデータベースをsearchし、プロバイダーごとに並べ替えて、必要な機能を持っているモジュールを探すことができます。見つけた後、モジュールの説明を読むことができ、これにはモジュールが提供する入力と出力、外部モジュールやプロバイダーの依存性がリストされています。

ここで、DigitalOcean SSH鍵moduleをプロジェクトに追加します。既存の定義とは別に、ssh-key.tfというファイルにコードを保存します。次のコマンドを実行して、編集用に作成して開きます。

  1. nano ssh-key.tf

以下の行を追加します。

module "ssh-key" {
  source         = "clouddrove/ssh-key/digitalocean"
  key_path       = "~/.ssh/id_rsa.pub"
  key_name       = "new-ssh-key"
  enable_ssh_key = true
}

このコードは、レジストリからclouddrove/droplet/digitaloceanモジュールのインスタンスを定義し、提供されているパラメータのいくつかを設定します。これは、~/.ssh/id_rsa.pubから読み取って、アカウントに公開SSH鍵を追加する必要があります。

終わったら、ファイルを保存して閉じてください。

このコードをplanする前に、参照されているモジュールをダウンロードする必要があります。これは以下のような出力を受け取ります。

  1. terraform init

次に、コードの変更を計画します。

Output
Initializing modules... Downloading clouddrove/ssh-key/digitalocean 0.13.0 for ssh-key... - ssh-key in .terraform/modules/ssh-key Initializing the backend... Initializing provider plugins... - Reusing previous version of digitalocean/digitalocean from the dependency lock file - Using previously-installed digitalocean/digitalocean v2.10.1 Terraform has been successfully initialized! ...

以下のような出力を受け取ります。

  1. terraform plan -var "do_token=${DO_PAT}"
Output
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: ... # module.ssh-key.digitalocean_ssh_key.default[0] will be created + resource "digitalocean_ssh_key" "default" { + fingerprint = (known after apply) + id = (known after apply) + name = "devops" + public_key = "ssh-rsa ... demo@clouddrove" } Plan: 4 to add, 0 to change, 0 to destroy. ...

出力は、SSH鍵リソースを作成することを示しています。これは、コードからモジュールをダウンロードして実行したことを意味します。

結論

大きなプロジェクトでは、Terraformが提供する高度な機能を使用することができます。これにより Complexityを減少させ、メンテナンスを容易にすることができます。ワークスペースを使用することで、コードに新しい追加をテストすることができます。また、ワークスペースを版本管理システムと組み合わせることで、コード変更を追跡することもできます。既存のモジュールを使用することで、開発時間を短縮できますが、モジュールが時代遅れすると、追加の费用や時間を発生させる可能性があります。

このチュートリアルは、Terraformを使用してインフラの管理シリーズの一部です。このシリーズでは、Terraformの様々なトピックについて説明しています。これには、Terraformを初めてインストールするから、複雑なプロジェクトを管理するまでのものが含まれています。

Source:
https://www.digitalocean.com/community/tutorials/how-to-deploy-multiple-environments-with-workspaces-in-your-terraform-project