本文へスキップ

プロビジョナー

プロビジョナーを使用して、ローカルマシンまたはリモートマシンでの特定のアクションをモデル化し、サーバーやその他のインフラストラクチャオブジェクトをサービスの準備をすることができます。

プロビジョナーは最後の手段です

OpenTofuは、OpenTofuの宣言型モデルでは直接表現できない動作が常に存在することを認識し、現実的な対応策としてプロビジョナーの概念を取り入れています。

しかし、これらはOpenTofuの使用にかなりの複雑さと不確実性も加えます。第一に、OpenTofuは原則としてどのようなアクションでも実行できるため、プロビジョナーのアクションを計画の一部としてモデル化できません。第二に、プロビジョナーの成功した使用には、OpenTofuの使用が通常必要とするよりも多くの詳細を調整する必要があります。サーバーへの直接ネットワークアクセス、ログインするためのOpenTofu資格情報の発行、必要なすべての外部ソフトウェアがインストールされていることの確認などです。

次のセクションでは、原則としてプロビジョナーで解決できる状況について説明しますが、より良い解決策も存在します。次のセクションで説明されているユースケースには、プロビジョナーの使用はお勧めしません。

特定のユースケースが次のセクションで説明されていない場合でも、最初に他の手法を使用して解決を試み、他に選択肢がない場合にのみプロビジョナーを使用することをお勧めします。

仮想マシンやその他のコンピューティングリソースへのデータの渡

仮想マシンや同様のコンピューティングリソースをデプロイする場合、サーバー上のソフトウェアがそのジョブを実行するために必要な他の関連インフラストラクチャに関するデータを渡す必要があることがよくあります。

SSHまたはWinRM経由でリモートサーバーとやり取りするさまざまなプロビジョナーを使用して、サーバーにログインし、直接データを渡すことができますが、ほとんどのクラウドコンピューティングプラットフォームは、インスタンスの作成時にデータを渡すメカニズムを提供しており、データはシステム起動時にすぐに利用できます。例として

多くの公式Linuxディストリビューションのディスクイメージには、cloud-initと呼ばれるソフトウェアが含まれています。これは、上記の方法で渡されたデータを様々な方法で自動的に処理できるため、起動プロセス中にSSHでマシンにアクセスすることなく、任意のスクリプトを実行したり、基本的なシステム設定を実行したりできます。

カスタムマシンイメージを作成する場合は、上記の方法で渡された「ユーザーデータ」または「メタデータ」を、アプリケーションにとって意味のある方法で活用できます。データへのランタイムアクセス方法については、ベンダーのドキュメントを参照してください。

この方法は、クラウドプロバイダーの自動的なサーバー起動・破棄メカニズムを使用する場合は必須です。なぜなら、その場合、個々のサーバーはOpenTofuがプロビジョニングする前に、無人状態で起動されるからです。

OpenTofuで個々のサーバーを直接デプロイする場合でも、この方法でデータを渡すと、OpenTofuから新しいサーバーへの直接ネットワークアクセスや、リモートアクセス資格情報の提供が不要になるため、起動時間を短縮し、デプロイを簡素化できます。

cloud-configを使用したファイルのプロビジョニング

OpenTofuの設定にcloudinit_configデータソースを追加し、プロビジョニングするファイルをtext/cloud-configコンテンツとして指定できます。cloudinit_configデータソースは、cloud-initで使用するためのマルチパートMIME構成をレンダリングします。contentフィールドに、write_filesブロックを使用してYAMLエンコードされた構成としてファイルをパスします。

次の例では、my_cloud_configデータソースは、cloud.confという名前のtext/cloud-config MIMEパートを指定しています。part.contentフィールドはyamlencodeに設定されており、これはwrite_files JSONオブジェクトをYAMLにエンコードして、システムが参照されたファイルをプロビジョニングできるようにします。

コードブロック
data "cloudinit_config" "my_cloud_config" {
gzip = false
base64_encode = false

part {
content_type = "text/cloud-config"
filename = "cloud.conf"
content = yamlencode(
{
"write_files" : [
{
"path" : "/etc/foo.conf",
"content" : "foo contents",
},
{
"path" : "/etc/bar.conf",
"content" : file("bar.conf"),
},
{
"path" : "/etc/baz.conf",
"content" : templatefile("baz.tpl.conf", { SOME_VAR = "qux" }),
},
],
}
)
}
}

構成管理ソフトウェアの実行

汎用オペレーティングシステムディストリビューションイメージを使用せざるを得ないユーザーの利便性のために、OpenTofuには、特定の構成管理製品を起動するためのいくつかの特殊なプロビジョナーが含まれています。

これらを使用しないことを強くお勧めします。代わりに、カスタムイメージのビルドプロセス中にシステム構成手順を実行してください。たとえば、HashiCorp Packerは、同様の構成管理プロビジョナーを提供しており、システムディスクイメージを作成する前に、個別のビルドプロセス中にインストール手順を実行できます。このイメージは何度もデプロイできます。

中央サーバーコンポーネントを持つ構成管理ソフトウェアを使用している場合、最終的なシステムがカスタムイメージから起動されるまで、登録手順を遅らせる必要があります。そのためには、上記の方法のいずれかを使用して、必要な情報を各インスタンスに渡します。これにより、SSHまたはWinRM経由でOpenTofuからのコマンドを受け取る必要なく、起動時にすぐに構成管理サーバーに自身を登録できます。

ファーストクラスのプロバイダー機能が利用可能である可能性があります

local-execプロビジョナーを使用してターゲットシステムのCLIを実行し、そのシステムのリモートオブジェクトを作成、更新、またはその他の方法で操作することは技術的に可能です。

まだプロバイダーでサポートされていないリモートシステムの新しい機能を使用しようとしている場合、それが唯一のオプションかもしれません。ただし、使用する機能のプロバイダーサポートがある場合は、プロビジョナーではなくそのプロバイダー機能を使用することを優先してください。そうすることで、OpenTofuはオブジェクトを完全に認識し、その継続的な変更を適切に管理できます。

必要な機能が現在プロバイダーで利用できない場合でも、local-execの使用を一時的な回避策とみなし、関連するプロバイダーのリポジトリで問題を開いて、ファーストクラスのプロバイダーサポートの追加について議論することをお勧めします。プロバイダー開発チームは、関心に基づいて機能の優先順位を付けることが多いため、問題を開くことは、その機能への関心を記録する方法です。

プロビジョナーは、リソースの作成または破棄の一環として、ローカルまたはリモートマシンでスクリプトを実行するために使用されます。プロビジョナーは、リソースのブートストラップ、破棄前のクリーンアップ、構成管理の実行などに使用できます。

プロビジョナーの使用方法

上記セクションのアドバイスを考慮した上で、プロビジョナーが問題解決の最善の方法であると確信している場合は、コンピューティングインスタンスのリソースブロック内にprovisionerブロックを追加できます。

コードブロック
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
command = "echo The server's IP address is ${self.private_ip}"
}
}

local-execプロビジョナーは他の設定を必要としませんが、ほとんどの他のプロビジョナーはSSHまたはWinRMを使用してリモートシステムに接続する必要があります。OpenTofuがサーバーと通信する方法を理解できるように、connectionブロックを含める必要があります。

OpenTofuには、いくつかの組み込みプロビジョナーが含まれています。サードパーティのプロビジョナーをプラグインとして使用することもできます。それらを%APPDATA%\terraform.d\plugins~/.terraform.d/plugins$XDG_DATA_HOME/opentofu/plugins、またはOpenTofuバイナリがインストールされているのと同じディレクトリに配置します。ただし、組み込みのfilelocal-execremote-execプロビジョナーを除くプロビジョナーの使用はお勧めしません。

すべてプロビジョナーは、whenon_failureのメタ引数をサポートしています。これらについては、以下で説明します(破棄時プロビジョナーエラー時の動作を参照)。

selfオブジェクト

provisionerブロック内の式は、名前で親リソースを参照できません。代わりに、特別なselfオブジェクトを使用できます。

selfオブジェクトは、プロビジョナーの親リソースを表し、そのリソースのすべての属性を持ちます。たとえば、aws_instancepublic_ip属性を参照するには、self.public_ipを使用します。

CLI出力でのプロビジョナーログの抑制

provisionerブロックの設定では、sensitive変数sensitive出力値など、機密性の高い値を使用する場合があります。この場合、機密値が表示されないように、プロビジョナーからのすべてのログ出力は自動的に抑制されます。

作成時プロビジョナー

デフォルトでは、プロビジョナーは、定義されているリソースが作成されたときに実行されます。作成時プロビジョナーは、作成時にのみ実行され、更新時やその他のライフサイクル時には実行されません。これらは、システムのブートストラップを実行するための手段として意図されています。

作成時プロビジョナーが失敗した場合、リソースは汚染された状態としてマークされます。汚染されたリソースは、次のtofu applyで破棄と再作成が計画されます。OpenTofuは、失敗したプロビジョナーによってリソースが半構成の状態になる可能性があるため、これを行います。OpenTofuはプロビジョナーが何をしているかを判断できないため、リソースの適切な作成を保証する唯一の方法は、リソースを再作成することです。これが汚染です。

on_failure属性を設定することで、この動作を変更できます。これについては、以下で詳しく説明します。

破棄時プロビジョナー

when = destroyが指定されている場合、プロビジョナーは、定義されているリソースが破棄されたときに実行されます。

コードブロック
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
when = destroy
command = "echo 'Destroy-time provisioner'"
}
}

破棄プロビジョナーは、リソースが破棄される前に実行されます。失敗した場合、OpenTofuはエラーになり、次のtofu applyでプロビジョナーを再度実行します。この動作のため、破棄プロビジョナーは複数回安全に実行できるよう注意する必要があります。

破棄時プロビジョナーは、リソースが破棄された時点で構成に残っている場合にのみ実行できます。破棄時プロビジョナーを持つリソースブロックが構成から完全に削除されると、そのプロビジョナー構成も一緒に削除され、そのため破棄プロビジョナーは実行されません。これを回避するには、破棄時プロビジョナーを持つリソースを安全に削除するために、複数ステップのプロセスを使用できます。

  • リソース構成を更新してcount = 0を含めます。
  • 構成を適用して、破棄プロビジョナーの実行を含め、リソースの既存のインスタンスをすべて破棄します。
  • 構成からリソースブロックとそのprovisionerブロックを完全に削除します。
  • 再度適用します。この時点で、リソースは既に破棄されているため、それ以上の操作は必要ありません。

この制限のため、破棄時プロビジョナーは慎重に使用する必要があります。

複数プロビジョナー

リソース内に複数のプロビジョナーを指定できます。複数のプロビジョナーは、構成ファイルで定義されている順序で実行されます。

作成と削除のプロビジョナーを組み合わせて使用することもできます。有効なプロビジョナーのみが実行されます。これらの有効なプロビジョナーは、設定ファイルで定義されている順序で実行されます。

複数プロビジョナーの例

コードブロック
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
command = "echo first"
}

provisioner "local-exec" {
command = "echo second"
}
}

エラー処理

デフォルトでは、失敗したプロビジョナーはOpenTofu apply自体も失敗させます。この動作はon_failure設定で変更できます。許容される値は以下のとおりです。

  • continue - エラーを無視して、作成または削除を続行します。

  • fail - エラーを発生させ、適用を停止します(デフォルトの動作)。これが作成プロビジョナーの場合、リソースを汚染します。

コードブロック
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
command = "echo The server's IP address is ${self.private_ip}"
on_failure = continue
}
}