arrow_back

Terraform の状態の管理

参加 ログイン
Test and share your knowledge with our community!
done
Get access to over 700 hands-on labs, skill badges, and courses

Terraform の状態の管理

Lab 1時間 universal_currency_alt クレジット: 5 show_chart 中級
Test and share your knowledge with our community!
done
Get access to over 700 hands-on labs, skill badges, and courses

このラボは Google のパートナーである Hashicorp と共同開発されました。アカウント プロフィールでサービスの最新情報、お知らせ、特典の受け取りをご希望になった場合、お客様の個人情報が本ラボのスポンサーである Hashicorp と共有される場合があります。

GSP752

Google Cloud セルフペース ラボ

概要

Terraform では、マネージド インフラストラクチャと構成に関する「状態」を保存する必要があります。Terraform はこの状態を使用して、実際のリソースを構成にマッピングしたり、メタデータをトラッキングしたり、大規模インフラストラクチャのパフォーマンスを改善したりします。

この状態は、デフォルトでは terraform.tfstate というローカル ファイルに保存されます。チーム環境にとって便利なリモートで保存することもできます。

Terraform は、このローカルの状態を使用してプランを作成し、インフラストラクチャに変更を加えます。オペレーションを実行する前に、Terraform は更新を行い、実際のインフラストラクチャによって状態をアップデートします。

Terraform の状態の主な用途は、リモート システム内のオブジェクトと構成で宣言されているリソース インスタンスとの間のバインディングを保存することです。Terraform は構成の変更に応じてリモート オブジェクトを作成する際に、そのリモート オブジェクトを特定のリソース インスタンスに対して同定する情報を記録します。その後、構成の変更に応じて適宜オブジェクトの更新や削除を行います。

目標

このラボでは、次のタスクを行う方法を学びます。

  • ローカル バックエンドを作成する。
  • Cloud Storage バックエンドを作成する。
  • Terraform の状態を更新する。
  • Terraform 構成をインポートする。
  • Terraform でインポートした構成を管理する。

設定と要件

[ラボを開始] ボタンをクリックする前に

こちらの手順をお読みください。ラボの時間は記録されており、一時停止することはできません。[ラボを開始] をクリックするとスタートするタイマーは、Google Cloud のリソースを利用できる時間を示しています。

このハンズオンラボでは、シミュレーションやデモ環境ではなく、実際のクラウド環境を使ってご自身でラボのアクティビティを行うことができます。そのため、ラボの受講中に Google Cloud にログインおよびアクセスするための、新しい一時的な認証情報が提供されます。

このラボを完了するためには、下記が必要です。

  • 標準的なインターネット ブラウザ(Chrome を推奨)
注: このラボの実行には、シークレット モードまたはシークレット ブラウジング ウィンドウを使用してください。これにより、個人アカウントと受講者アカウント間の競合を防ぎ、個人アカウントに追加料金が発生することを防ぎます。
  • ラボを完了するために十分な時間を確保してください。ラボをいったん開始すると一時停止することはできません。
注: すでに個人の Google Cloud アカウントやプロジェクトをお持ちの場合でも、このラボでは使用しないでください。アカウントへの追加料金が発生する可能性があります。

ラボを開始して Google Cloud コンソールにログインする方法

  1. [ラボを開始] ボタンをクリックします。ラボの料金をお支払いいただく必要がある場合は、表示されるポップアップでお支払い方法を選択してください。 左側の [ラボの詳細] パネルには、以下が表示されます。

    • [Google コンソールを開く] ボタン
    • 残り時間
    • このラボで使用する必要がある一時的な認証情報
    • このラボを行うために必要なその他の情報(ある場合)
  2. [Google コンソールを開く] をクリックします。 ラボでリソースが起動し、別のタブで [ログイン] ページが表示されます。

    ヒント: タブをそれぞれ別のウィンドウで開き、並べて表示しておきましょう。

    注: [アカウントの選択] ダイアログが表示されたら、[別のアカウントを使用] をクリックします。
  3. 必要に応じて、[ラボの詳細] パネルから [ユーザー名] をコピーして [ログイン] ダイアログに貼り付けます。[次へ] をクリックします。

  4. [ラボの詳細] パネルから [パスワード] をコピーして [ようこそ] ダイアログに貼り付けます。[次へ] をクリックします。

    重要: 認証情報は左側のパネルに表示されたものを使用してください。Google Cloud Skills Boost の認証情報は使用しないでください。 注: このラボでご自身の Google Cloud アカウントを使用すると、追加料金が発生する場合があります。
  5. その後次のように進みます。

    • 利用規約に同意してください。
    • 一時的なアカウントなので、復元オプションや 2 要素認証プロセスは設定しないでください。
    • 無料トライアルには登録しないでください。

その後このタブで Cloud Console が開きます。

注: 左上にある [ナビゲーション メニュー] をクリックすると、Google Cloud のプロダクトやサービスのリストが含まれるメニューが表示されます。 ナビゲーション メニュー アイコン

Cloud Shell をアクティブにする

Cloud Shell は、開発ツールと一緒に読み込まれる仮想マシンです。5 GB の永続ホーム ディレクトリが用意されており、Google Cloud で稼働します。Cloud Shell を使用すると、コマンドラインで Google Cloud リソースにアクセスできます。

  1. Google Cloud コンソールの上部にある「Cloud Shell をアクティブにする」アイコン 「Cloud Shell をアクティブにする」アイコン をクリックします。

接続した時点で認証が完了しており、プロジェクトに各自の PROJECT_ID が設定されます。出力には、このセッションの PROJECT_ID を宣言する次の行が含まれています。

Your Cloud Platform project in this session is set to YOUR_PROJECT_ID

gcloud は Google Cloud のコマンドライン ツールです。このツールは、Cloud Shell にプリインストールされており、タブ補完がサポートされています。

  1. (省略可)次のコマンドを使用すると、有効なアカウント名を一覧表示できます。
gcloud auth list
  1. [承認] をクリックします。

  2. 出力は次のようになります。

出力:

ACTIVE: * ACCOUNT: student-01-xxxxxxxxxxxx@qwiklabs.net To set the active account, run: $ gcloud config set account `ACCOUNT`
  1. (省略可)次のコマンドを使用すると、プロジェクト ID を一覧表示できます。
gcloud config list project

出力:

[core] project = <project_ID>

出力例:

[core] project = qwiklabs-gcp-44776a13dea667a6 注: Google Cloud における gcloud ドキュメントの全文については、gcloud CLI の概要ガイドをご覧ください。

Terraform の状態の用途

状態は Terraform が機能するための必須要件です。ユーザーからは「Terraform は状態なしでも機能するのか」といった質問や、「状態を使用せずに実行のたびにクラウド リソースを検査する形でも機能するのか」といった質問を受けることがあります。状態を使用しなくても Terraform が機能するシナリオはありますが、状態を使用しないと、ある場所(状態)から別の場所(代替の概念)に複雑な内容を大量に移行しなければならなくなります。このセクションでは、Terraform の状態が必要な理由を説明します。

実世界へのマッピング

Terraform では、Terraform の構成を実世界にマッピングするためになんらかのデータベースが必要です。構成に resource "google_compute_instance" "foo" が含まれている場合は、そのリソースによって i-abcd1234 インスタンスが表現されていることを認識するためにマッピングが使用されます。

Terraform は、各リモート オブジェクトが 1 つのリソース インスタンスのみにバインドされると想定します。Terraform はオブジェクトを作成し、それらのオブジェクトを同定する情報を状態に記録するようになっているので、この想定は通常保証されます。Terraform 外で作成されたオブジェクトをインポートする場合は、それぞれのオブジェクトが 1 つのリソース インスタンスに対してのみインポートされていることを確認する必要があります。

1 つのリモート オブジェクトが 2 つ以上のリソース インスタンスにバインドされていると、そういったオブジェクトに対して Terraform が想定外の振る舞いをする場合があります。これは、構成からリモート オブジェクトの状態へのマッピングが不明瞭になるためです。

メタデータ

Terraform は、リソースとリモート オブジェクト間のマッピングをトラッキングするだけでなく、リソースの依存関係などのメタデータもトラッキングする必要があります。

Terraform では通常、構成を基に依存順序を判断します。ただし、Terraform 構成からリソースを削除する際は、そのリソースの削除方法を Terraform が認識している必要があります。構成ファイル内に存在しないリソースのマッピングがあると、Terraform が識別し、破棄を計画します。ただし、リソースはすでに存在しないため、構成だけから順序を判断することはできません。

オペレーションを適切に実行するため、Terraform は最新の依存関係セットのコピーを状態内に保持しておきます。これにより、Terraform は構成から 1 つ以上の項目を削除する際に、状態から破棄の正しい順序を判断できます。

上記のプロセスは、Terraform がリソースタイプ間の必須の順序を認識している場合には回避できます。たとえば Terraform は、サブネットを削除する前に、それらのサブネットに属するサーバーを削除しなければならないことを認識できます。しかし、この手法では複雑さが増してすぐに管理できなくなります。Terraform は各クラウドの各リソースの順序セマンティクスだけでなく、複数のプロバイダ全体の順序も把握する必要があります。

同様の理由で Terraform では他のメタデータも保存します。たとえば、エイリアス化されたプロバイダが複数存在する場合に、リソースによって最後に使用されたプロバイダ構成へのポインタなどです。

パフォーマンス

Terraform は基本的なマッピングのほかに、全リソースの属性値のキャッシュを状態に保存します。これは Terraform の状態のオプション機能であり、パフォーマンスの改善のみを目的としています。

Terraform は terraform plan を実行する際、目的の構成を実現するうえで必要な変更を上手く判断するために、リソースの現在の状態を把握する必要があります。

小規模なインフラストラクチャの場合は、プロバイダに対するクエリを実行し、すべてのリソースの最新の属性を同期できます。それが Terraform のデフォルトの動作です。すべての planapply で、Terraform は状態内のすべてのリソースを同期します。

大規模なインフラストラクチャの場合は、すべてのリソースに対するクエリを実行すると時間がかかりすぎてしまいます。多くのクラウド プロバイダは、複数のリソースに対するクエリを一括実行するための API を提供しておらず、リソースあたりのラウンドトリップ時間は数百ミリ秒になります。また、クラウド プロバイダはたいてい API のレート制限を設けています。そのため、Terraform が一定期間内にリクエストできるリソースの数は限られます。この問題を回避するために、Terraform を大規模に使用するユーザーは多くの場合、-refresh=false フラグと -target フラグの両方を使用します。こうしたシナリオでは、キャッシュに保存された状態が信頼できる記録として扱われます。

同期

デフォルトの構成では、状態は Terraform が実行された現在の作業ディレクトリにファイルとして保存されます。最初はこの方法で問題ないでしょう。しかし、Terraform をチームで使用する場合は、オペレーションが同一のリモート オブジェクトに適用されるように、チームメンバー全員が同じ状態を使用できることが重要です。

この問題への対応策としてリモート状態をおすすめします。多機能の状態バックエンドを利用すると、複数のユーザーが誤って Terraform を同時実行するのを防ぐ手段として、Terraform でリモートロックを使用できます。これにより、Terraform の実行が毎回、更新済みの最新の状態で開始されるようになります。

状態のロック

バックエンドがロックに対応している場合、Terraform は状態を書き込む可能性があるすべてのオペレーションに対して状態をロックします。これにより、他のユーザーがロックを取得し、状態に不適切な変更を加えることを防止できます。

状態のロックは、状態を書き込む可能性があるすべてのオペレーションを対象に自動的に行われます。ロックが行われる際に特にメッセージは表示されません。状態のロックに失敗すると、Terraform は続行できなくなります。-lock フラグを使用すると、ほとんどのコマンドで状態のロックを無効化できますが、推奨されません。

ロックの取得に想定されているよりも時間がかかると、Terraform からステータス メッセージが出力されます。Terraform からメッセージが出力されていない場合は、状態のロックが引き続き有効です。

一部のバックエンドはロックに対応していません。バックエンドがロックに対応しているかどうかの詳細については、バックエンドのタイプのリストをご覧ください。

ワークスペース

それぞれの Terraform 構成には、オペレーションの実行方法や永続データ(Terraform の状態など)の保存場所を定義するバックエンドが関連付けられています。

バックエンドに保存される永続データは、ワークスペースに属します。最初はバックエンドに default というワークスペースしかないため、構成に関連付けられる Terraform の状態は 1 つのみです。

一部のバックエンドは複数の名前付きワークスペースに対応しており、複数の状態を単一の構成に関連付けることができます。この構成のバックエンドは 1 つのみですが、新しいバックエンドを構成したり、認証情報を変更したりしなくても、この構成を使った別個のインスタンスを複数デプロイできます。

タスク 1. バックエンドの操作

状態を読み込む方法と apply などのオペレーションを実行する方法は、Terraform のバックエンドによって決まります。この抽象化によって、ローカル ファイルを使用しない状態の保存やリモート実行などが可能になります。

デフォルトでは、Terraform は「ローカル」のバックエンドを使用します。これは、ここまで使われていた Terraform の標準の動作です。これまでのラボでは、このローカルのバックエンドを呼び出していました。

バックエンドには次のようなメリットがあります。

  • チームでの作業: バックエンドを使用すると、状態をリモートに保存できることに加え、その状態をロックによって保護し、不適切な変更を防止できます。Terraform Cloud など一部のバックエンドでは、すべての状態の変更履歴を自動的に保存することもできます。
  • 機密情報をディスク外に保管: 状態はバックエンドからオンデマンドで取得され、メモリにのみ保存されます。
  • リモート オペレーション: 大規模なインフラストラクチャや一部の変更では、terraform apply に長時間かかる場合があります。一部のバックエンドはリモート オペレーションに対応しており、リモートでオペレーションを実行できます。その場合は PC の電源を切ってもオペレーションが完了します。前述のとおり、リモート オペレーションを状態のリモート保存およびロックと組み合わせることで、チーム環境も維持できます。

バックエンドは任意: バックエンドの学習や使用をしなくても、Terraform は問題なく使うことができます。しかし、バックエンドを使用することで、ある程度の規模のチームで悩みとなる問題を解消できます。個人で作業を進める場合は、おそらくバックエンドを使用しなくても問題ないでしょう。

ローカル バックエンドの動作は変更することもできるので、ローカル バックエンドのみを使用する場合でも、バックエンドについて学んでおくと便利です。

ローカル バックエンドの追加

このセクションでは、ローカル バックエンドを構成します。

Terraform では、バックエンドを初めて構成するときに(バックエンドが定義されていない状態から明示的に構成を行うとき)、状態を新しいバックエンドに移行するオプションが提示されます。これにより、既存の状態を失わずにバックエンドを導入できます。

細心の注意を払い、必ず手動で状態をバックアップしておくことをおすすめします。手動バックアップは、terraform.tfstate ファイルを別の場所にコピーするだけで完了します。初期化プロセスでもバックアップが作成されますが、念のため手動でも保存しておきましょう。

初めてバックエンドを構成するときも後から構成を変更するときも方法は同じです。新しい構成を作成し、terraform init を実行します。後は Terraform が示すガイドに沿って手順を進めます。

  1. 新しく開いた Cloud Shell のウィンドウで、main.tf 構成ファイルを作成します。
touch main.tf
  1. 次のコマンドを実行して、プロジェクト ID を取得します。
gcloud config list --format 'value(core.project)'
  1. Cloud Shell ツールバーで [エディタを開く] をクリックします。Cloud Shell とコードエディタを切り替えるには、必要に応じて [エディタを開く] または [ターミナルを開く] をクリックするか、[新しいウィンドウで開く] をクリックして別のタブでエディタを開いたままにします。
  1. Cloud Storage バケットのリソースコードを main.tf 構成ファイルにコピーし、projectname の変数を実際のプロジェクト ID に置き換えます。
provider "google" { project = "# 実際のプロジェクト ID に置き換え" region = "{{{project_0.default_region | REGION}}}" } resource "google_storage_bucket" "test-bucket-for-state" { name = "# 実際のプロジェクト ID に置き換え" location = "US" uniform_bucket_level_access = true }

Cloud Storage リソースについて詳しくは、Terraform のドキュメントをご覧ください。

  1. ローカル バックエンドを main.tf ファイルに追加します。
terraform { backend "local" { path = "terraform/state/terraform.tfstate" } }

これにより、terraform/state ディレクトリの terraform.tfstate ファイルが参照されます。別のファイルパスを指定するには、path 変数を変更します。

ローカル バックエンドでは、ローカルのファイルシステムに状態を保存して、その状態をシステム API によってロックし、ローカルでオペレーションを実行します。

Terraform では、構成したバックエンドを使用前に初期化する必要があります。そのためには、terraform init を実行します。terraform init コマンドは、いずれかのチームメンバーが Terraform 構成に対して、最初のステップとして実行する必要があります。複数回実行して、バックエンドの初期化など、Terraform 環境に必要な設定操作をすべて行うと安全です。

init コマンドは次の場合に呼び出す必要があります。

  • バックエンドを構成する環境を新しく用意する
  • バックエンド構成を変更する(バックエンドの種類の変更も含む)
  • バックエンド構成を完全に削除する

これらを厳密に覚える必要はありません。初期化が必要な状況になったら、Terraform からエラー メッセージが表示されます。Terraform が初期化を自動で行うことはありません。ユーザーからの追加情報が必要な場合や、状態の移行を実行する場合などがあるからです。

  1. Cloud Shell ツールバーで、[ターミナルを開く]、[Terraform を初期化する] の順にクリックします。
terraform init
  1. 変更を適用します。確認プロンプトで「yes」と入力します。
terraform apply

Cloud Shell エディタで terraform/state ディレクトリに terraform.tfstate という状態ファイルが表示されるはずです。

  1. 状態ファイルを確認します。
terraform show

google_storage_bucket.test-bucket-for-state リソースが表示されます。

Cloud Storage バックエンドの追加

Cloud Storage バックエンドでは、構成可能なプレフィックスで状態をオブジェクトとして Cloud Storage 上の特定のバケットに保存します。Cloud Storage バックエンドは状態のロックにも対応していて、状態を書き込む可能性があるすべてのオペレーションに対して状態をロックします。これにより、他のユーザーがロックを取得し、状態に不適切な変更を加えることを防止できます。

状態のロックは、状態を書き込む可能性があるすべてのオペレーションを対象に自動的に行われます。ロックが行われる際に特にメッセージは表示されません。状態のロックに失敗すると、Terraform は続行できなくなります。-lock フラグを使用して、ほとんどのコマンドで状態のロックを無効化できますが、推奨されません。

  1. エディタで main.tf ファイルに戻ります。ここで、現在のローカル バックエンドを gcs バックエンドに置き換えます。

  2. 既存のローカル バックエンドの構成を変更するには、次の構成をファイルにコピーし、local バックエンドを置き換えます。

terraform { backend "gcs" { bucket = "# 実際のバケット名に置き換え" prefix = "terraform/state" } } 注: 必ず bucket の変数定義を更新してください。構成を変更しなかった場合は、google_storage_bucket リソースの name が使用されます。このバケットが状態ファイルをホストするために使用されます。
  1. バックエンドを再度初期化します。今回は状態を自動的に移行することが目的です。
terraform init -migrate-state

確認プロンプトで「yes」と入力します。

  1. Cloud コンソールのナビゲーション メニューで、[Cloud Storage] > [バケット] をクリックします。

  2. バケットをクリックし、terraform/state/default.tfstate ファイルにアクセスします。状態ファイルは Cloud Storage バケット内にあります。

注: バックエンドを使用する必要がなくなった場合は、ファイルから構成を削除するだけで処理できます。他の変更と同様に構成の削除が Terraform によって検出され、再初期化を促すメッセージが表示されます。

再初期化の一環として、状態を標準であるローカルに戻すかどうかを Terraform に問われます。それが完了すると、Terraform はデフォルトの動作に戻ります。

状態の更新

terraform refresh コマンドは、Terraform が状態ファイルを通じて認識している状態と実際のインフラストラクチャとを整合させるために使用します。これにより、最後に認識された状態からのずれを検出し、状態ファイルを更新できます。

インフラストラクチャではなく、状態ファイルを修正するコマンドです。状態が変更されると、次の plan や apply の最中に変更が行われる場合があります。

  1. Cloud コンソールで Storage バケットに戻ります。名前の横にあるチェックボックスをオンにします。

  2. [ラベル] タブをクリックします。

  3. [ラベルを追加] をクリックします。[鍵 1] を [key]、[値 1] を [value] に設定します。

  4. [保存] をクリックします。

  5. Cloud Shell に戻り、次のコマンドを使用して状態ファイルを更新します。

terraform refresh
  1. 更新を確認します。
terraform show

構成のラベル属性に Key-Value ペア "key" = "value" が表示されます。

[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。 バックエンドの操作

ワークスペースのクリーンアップ

次のタスクに移る前に、プロビジョニング済みのインフラストラクチャを破棄します。

  1. まず、バックエンドを local に戻し、Storage バケットを削除できるようにします。gcs 構成をコピーし、次に置き換えます。
terraform { backend "local" { path = "terraform/state/terraform.tfstate" } }
  1. local バックエンドを再初期化します。
terraform init -migrate-state

確認プロンプトで「yes」と入力します。

  1. main.tf ファイルで、force_destroy = true 引数を google_storage_bucket リソースに追加します。このブール値のオプションを使用することで、バケットを削除するときに含まれているすべてのオブジェクトが削除されます。オブジェクトが含まれているバケットを削除しようとすると、Terraform による実行が失敗します。リソースの構成は次のようになります。
resource "google_storage_bucket" "test-bucket-for-state" { name = "qwiklabs-gcp-03-c26136e27648" location = "US" uniform_bucket_level_access = true force_destroy = true }
  1. 変更を適用します。
terraform apply

確認プロンプトで「yes」と入力します。

  1. これでインフラストラクチャを正常に破棄できるようになりました。
terraform destroy

確認プロンプトで「yes」と入力します。

タスク 2. Terraform 構成のインポート

このセクションでは、既存の Docker コンテナとイメージを空の Terraform ワークスペースにインポートします。これにより、実際のインフラストラクチャを Terraform にインポートする際の戦略や考慮事項を学ぶことができます。

Terraform のデフォルトのワークフローでは、インフラストラクチャの作成と管理はすべて Terraform によって行われます。

  • 作成するインフラストラクチャを定義する Terraform 構成を記述します。

  • Terraform プランを確認し、構成から想定どおりの状態とインフラストラクチャが実現することを確かめます。

  • 構成を適用し、Terraform の状態とインフラストラクチャを作成します。

Terraform のワークフローの図

Terraform でインフラストラクチャを作成した後は、構成を更新して、変更に対し plan と apply を実行できます。その後、インフラストラクチャが不要になったら、Terraform を使用してインフラストラクチャを破棄します。このワークフローは、Terraform が完全に新しいインフラストラクチャを作成することを前提としています。

しかし場合によっては、Terraform 以外で作成されたインフラストラクチャを管理する必要があります。この問題は、terraform import コマンドを使用して、サポート対象のリソースを自分の Terraform ワークスペースの状態に読み込むことで対処できます。

ただし、import コマンドでは、インフラストラクチャを管理するための構成が自動的に生成されません。そのため、既存のインフラストラクチャを Terraform にインポートするプロセスは、複数のステップで構成されます。

既存のインフラストラクチャを Terraform の管理下に置く作業には、次の 5 つの主要なステップがあります。

  • インポートする既存のインフラストラクチャを特定する。
  • インフラストラクチャを Terraform の状態にインポートする。
  • そのインフラストラクチャに一致する Terraform 構成を記述する。
  • Terraform プランを確認し、構成が想定どおりの状態とインフラストラクチャに一致していることを確かめる。
  • 構成を適用し、Terraform の状態を更新する。

Terraform のインポート ワークフローの図

このセクションでは、まず Docker CLI を使用して Docker コンテナを作成します。次に、そのコンテナを新しい Terraform ワークスペースにインポートします。続いて、Terraform を使用してコンテナの構成を更新します。作業完了後、このコンテナは最終的に破棄します。

警告: インフラストラクチャをインポートすると、Terraform の状態に変更が生じ、既存の Terraform プロジェクトが無効な状態になる可能性があります。実際の Terraform プロジェクトで terraform import を使用する前に、terraform.tfstate ファイルと .terraform ディレクトリのバックアップを作成して、安全に保存しておいてください。

Docker コンテナの作成

  1. Docker Hub の最新の NGINX イメージを使用して hashicorp-learn という名前のコンテナを作成し、Cloud Shell の仮想マシン上で、ポート 80(HTTP)経由でコンテナをプレビューします。
docker run --name hashicorp-learn --detach --publish 8080:80 nginx:latest
  1. コンテナが実行されていることを確認します。
docker ps
  1. Cloud Shell のペインで、[ウェブでプレビュー]、[ポート 8080 でプレビュー] の順にクリックします。

 [ウェブでプレビュー] のオプション

プロキシ サービスのプレビュー用 URL が新しいブラウザ ウィンドウで開き、NGINX のデフォルトのインデックス ページが表示されます。これで、ワークスペースにインポートして Terraform で管理する Docker イメージとコンテナを準備できました。

Terraform へのコンテナのインポート

  1. サンプル リポジトリのクローンを作成します。
git clone https://github.com/hashicorp/learn-terraform-import.git
  1. そのディレクトリに移動します。
cd learn-terraform-import

このディレクトリには、本ガイドの構成を実現する 2 つの Terraform 構成ファイルが含まれています。

  • main.tf ファイルでは Docker プロバイダを構成します。
  • docker.tf ファイルには、前のステップで作成した Docker コンテナを管理するために必要な構成が含まれます。
  1. Terraform ワークスペースを初期化します。
terraform init 注:Error: Failed to query available provider packages」のようなエラーが表示された場合は、コマンド terraform init -upgrade を実行してください。
  1. Cloud Shell エディタで learn-terraform-import/main.tf にアクセスします。

  2. provider: docker リソースを見つけて、host 引数をコメントアウトまたは削除します。

provider "docker" { # host = "npipe:////.//pipe//docker_engine" } 注: 現時点では、このようにして Docker の初期化エラーに関する既知の問題を回避します。
  1. 次に、learn-terraform-import/docker.tf にアクセスします。

  2. コメントアウトされたコードの下で、docker.tf ファイルの空の docker_container リソースを定義します。このリソースは、Terraform リソース ID docker_container.web で Docker コンテナを表します。

resource "docker_container" "web" {}
  1. インポートするコンテナの名前を見つけます。この例では、前のステップで作成したコンテナになります。
docker ps
  1. 次の terraform import コマンドを実行して、作成したばかりの docker_container.web リソースに既存の Docker コンテナを関連付けます。terraform import では、この Terraform リソース ID と完全な Docker コンテナ ID が必要です。docker inspect -f {{.ID}} hashicorp-learn コマンドを実行すると、完全な SHA256 コンテナ ID が返されます。
terraform import docker_container.web $(docker inspect -f {{.ID}} hashicorp-learn) 注: terraform import で受け入れられる ID はリソースのタイプによって異なり、Terraform にインポートできるリソースごとにプロバイダのドキュメントに記載されています。この例では、Docker プロバイダのドキュメントを参照します。
  1. Terraform の状態にコンテナがインポートされていることを確認します。
terraform show

この状態には、インポートした Docker コンテナについて Terraform が認識している情報がすべて含まれています。ただし、terraform import ではリソースの構成は作成されません

構成の作成

Terraform を使用してこのコンテナを管理するには、Terraform 構成を作成しておく必要があります。

  1. 次のコードを実行します。
terraform plan 注: 必須の引数 imagename が抜けていることを示すエラーが Terraform によって表示されます。Terraform は必須の引数が抜けているリソースのプランを生成できません。

インポートした状態に合わせて docker.tf の構成を更新する方法は 2 つあります。リソースの現在の状態全体をそのまま構成にインポートする方法か、必要な属性を個別に選択して構成にインポートする方法です。これらの方法は有効な状況がそれぞれ異なります。

  • 多くの場合、現在の状態を使用する方が手早く済みますが、構成が過度に細かくなる可能性があります。構成に含める必要があるかどうかにかかわらず、すべての属性が状態に含まれるためです。

  • 必要な属性を個別に選択する方法では、構成を管理しやすくなりますが、構成でどの属性を設定する必要があるのかを把握する必要が生じます。

このラボでは、現在の状態をリソースとして使用します。

  1. Terraform の状態を docker.tf ファイルにコピーします。
terraform show -no-color > docker.tf 注: > 記号は、docker.tf のすべての内容を terraform show コマンドの出力に置き換えます。この例では問題ありませんが、すでにリソースを管理している構成にリソースをインポートするためには、terraform show の出力を編集し、構成の完全な置き換えが望ましくない既存のリソースを削除して、新しいリソースを既存の構成に統合する必要があります。
  1. docker.tf ファイルを検査して、実行した terraform show コマンドの出力によって内容が置き換えられていることを確認します。

  2. 次のコードを実行します。

terraform plan

Terraform に、非推奨の引数(「links」)と一部の読み取り専用の引数(ip_addressnetwork_datagatewayip_prefix_lengthid)に関する警告やエラーが表示されます。

これらの読み取り専用の引数は、Terraform が Docker コンテナの状態に保存する値ですが、Docker によって内部で管理されるため、構成で設定することはできません。Terraform では、構成を使用して links 引数を設定できますが、その場合でも警告は表示されます。links 引数は非推奨であり、Docker プロバイダの今後のバージョンではサポートされない可能性があるためです。

ここで説明する方法では、Terraform の状態で表現されている属性をすべて読み込むため、値がデフォルトと同一であるオプションの属性も構成に含まれます。オプションの属性とそのデフォルト値はプロバイダによって異なり、プロバイダのドキュメントにまとめられています。

  1. こうしたオプションの属性を選択して削除できます。オプションの属性をすべて削除し、必須属性(imagenameports)のみを残します。これらのオプションの属性を削除すると、構成は次のようになります。
resource "docker_container" "web" { image = "sha256:87a94228f133e2da99cb16d653cd1373c5b4e8689956386c1c12b60a20421a02" name = "hashicorp-learn" ports { external = 8080 internal = 80 ip = "0.0.0.0" protocol = "tcp" } }

実際のインフラストラクチャをインポートする際は、プロバイダのドキュメントで各引数の役割を確認してください。そうすることで、plan 実行時のエラーや警告に対処する方法を見極められます。たとえば、links 引数に関するドキュメントは、Docker プロバイダのドキュメントにあります。

  1. エラーが解決されていることを確認します。
terraform plan

plan は正常に実行されるはずです。Terraform によってコンテナが更新され、attachlogsmust_runstart の各属性が追加されることを plan は示しています。

Terraform はこれらの属性を使用して Docker コンテナを作成しますが、Docker はこれらの属性を保存しません。そのため、terraform import では値が状態に読み込まれていません。構成に対し plan と apply を実行するとき、Docker プロバイダがこれらの属性のデフォルト値を割り当てて状態に保存しますが、実行されるコンテナに影響はありません。

  1. 変更を適用して、更新された Terraform の構成と状態を、それを反映させる Docker コンテナと同期させるプロセスを完了します。確認プロンプトで「yes」と入力します。
terraform apply

以上で、構成ファイル、Terraform の状態、コンテナがすべて同期され、Terraform を使用して通常どおり Terraform コンテナを管理できるようになりました。

イメージ リソースの作成

場合によっては、terraform import コマンドを使用しなくてもリソースを Terraform の管理下に置くことができます。Docker イメージなど、1 つの一意の ID やタグで定義されるリソースは、これに該当する場合が多くあります。

docker.tf ファイルの docker_container.web リソースは、コンテナの作成に使用されるイメージの SHA256 ハッシュ ID を指定します。Docker はこの方法でイメージ ID を内部で保存するため、terraform import を実行するとイメージ ID が状態に直接読み込まれます。ただし、イメージ ID はイメージのタグや名前ほど人間が読みやすい形式にはなっておらず、意図に合っていない場合もあります。たとえば、「nginx」イメージの最新バージョンを使用したいとします。

  1. イメージのタグ名を取得するには、<IMAGE-ID>docker.tf のイメージ ID に置き換えて次のコマンドを実行します。
docker image inspect -f {{.RepoTags}}
  1. 次の構成を docker.tf ファイルに追加し、このイメージをリソースとして表現します。
resource "docker_image" "nginx" { name = "nginx:latest" } 注: docker_container.web リソースのイメージの値はまだ置き換えないでください。この値を置き換えると、コンテナが破棄、再作成されます。Terraform は docker_image.nginx リソースをまだ状態に読み込んでいないため、ハードコードされた ID と照合するイメージ ID がありません。このため、Terraform はコンテナを置き換える必要があると判断します。この状況に対処するには、今回のラボの説明どおりに先にイメージを作成したうえで、そのイメージを使用するようコンテナを更新します。
  1. 状態にイメージ リソースを作成します。
terraform apply

イメージのリソースが作成されたら、コンテナの構成内で参照できます。

  1. docker_container.web のイメージの値を変更し、新しいイメージ リソースを参照します。
resource "docker_container" "web" { image = docker_image.nginx.image_id name = "hashicorp-learn" ports { external = 8080 internal = 80 ip = "0.0.0.0" protocol = "tcp" } }
  1. 変更内容を確認します。
terraform apply

docker_image.nginx.latest は置き換えたハードコード済みのイメージ ID に一致するため、この時点で terraform apply を実行しても変更内容は表示されません。

注: 最初に Docker コンテナを作成してから terraform apply コマンドを実行するまでの間に「nginx:latest」タグのイメージ ID が変更されている場合、コンテナは破棄され、新しいイメージを使用して再作成されます。

Terraform によるコンテナの管理

Terraform で Docker コンテナを管理するように構成したら、Terraform を使用して構成を変更します。

  1. docker.tf ファイルで、コンテナの外部ポートを 8080 から 8081 に変更します。
resource "docker_container" "web" { name = "hashicorp-learn" image = docker_image.nginx.image_id ports { external = 8081 internal = 80 ip = "0.0.0.0" protocol = "tcp" } }
  1. 変更を適用します。
terraform apply

確認プロンプトで「yes」と入力します。

これにより、コンテナが破棄され、新しいポート構成で再作成されます。

  1. コンテナが新しい構成のものに置き換えられていることを確認します。
docker ps

コンテナ ID が変わっていることに注目してください。ポート構成を変更するには、いったん破棄して再作成する必要があるので、これは完全に新しいコンテナになります。

インフラストラクチャの破棄

Docker コンテナと、それを作成するためのイメージを Terraform にインポートしました。

  1. コンテナとイメージを破棄します。
terraform destroy

確認プロンプトで「yes」と入力します。

  1. コンテナが破棄されたことを確認します。
docker ps --filter "name=hashicorp-learn" 注: Terraform の構成とコンテナの両方にイメージを追加したため、Docker とコンテナの両方からイメージが削除されます。別のコンテナで同じイメージが使用されている場合は、破棄のステップが失敗します。リソースを Terraform にインポートすると、破棄を含め、リソースのライフサイクル全体が Terraform で管理されることになります。

制限事項とその他の考慮事項

リソースを Terraform にインポートする際は、いくつか重要なポイントがあります。

terraform import で認識できるのは、Terraform プロバイダから報告されるインフラストラクチャの現在の状態のみです。次の点は認識されません。

  • インフラストラクチャが適切に動作しているかどうか
  • インフラストラクチャの意図
  • インフラストラクチャに対して適用された変更のうち、Terraform によって管理されていないもの(Docker コンテナのファイルシステムの状態など)

インポートにはエラーが起こりやすい手動作業が含まれます。特にリソースをインポートする担当者が、対象のリソースが作成された本来の経緯や理由を理解していないと、エラーが起こりやすくなります。

インポートでは Terraform の状態ファイルに操作を加えます。そのため、新しいインフラストラクチャをインポートする前にバックアップを作成しておくことをおすすめします。

terraform import では、インフラストラクチャ間の関係性は検出、生成されません。

Terraform は、構成で設定する必要がないデフォルトの属性は検出しません。

一部のプロバイダやリソースは terraform import に対応していません。

インフラストラクチャを Terraform にインポートしても、Terraform で破棄、再作成できることにはなりません。たとえば、インポートされたインフラストラクチャが、他の非マネージドのインフラストラクチャや構成に依存している場合があります。

Immutable Infrastructure(不変のインフラストラクチャ)など、Infrastructure as Code(IaC)のベスト プラクティスに従うと、こうした問題の多くは防止できますが、手動で作成されたインフラストラクチャは、IaC のベスト プラクティスに即していない傾向があります。

Terraformer などのツールを利用すると、インフラストラクチャのインポートに伴う一部の手動作業を自動化できます。ただし、こうしたツールは、Terraform そのものに組み込まれているわけではなく、HashiCorp が推奨、支援しているものでもありません。

お疲れさまでした

このラボでは、Terraform を使用してバックエンドや状態を管理する方法を学びました。状態ファイルを管理するためのローカル バックエンドと Cloud Storage バックエンドを作成して、状態を更新し、Terraform に構成をインポートしました。その後、構成を更新し、手動で編集することで Terraform で Docker コンテナを完全に管理できるようにしました。

次のステップと詳細情報

次のリンクから、Terraform に関するその他の実践演習を受講できます。

Google Cloud トレーニングと認定資格

Google Cloud トレーニングと認定資格を通して、Google Cloud 技術を最大限に活用できるようになります。必要な技術スキルとベスト プラクティスについて取り扱うクラスでは、学習を継続的に進めることができます。トレーニングは基礎レベルから上級レベルまであり、オンデマンド、ライブ、バーチャル参加など、多忙なスケジュールにも対応できるオプションが用意されています。認定資格を取得することで、Google Cloud テクノロジーに関するスキルと知識を証明できます。

マニュアルの最終更新日: 2024 年 1 月 26 日

ラボの最終テスト日: 2023 年 12 月 11 日

Copyright 2024 Google LLC All rights reserved. Google および Google のロゴは Google LLC の商標です。その他すべての企業名および商品名はそれぞれ各社の商標または登録商標です。