私は、terraformがリソースに対して「file」、「remote-exec」、または「local-exec」を一度だけ実行することに気づきました。 「remote-exec」のコマンドが変更された場合、またはプロビジョナー「file」からのファイルが変更された場合、リソースがプロビジョニングされると、terraformはインスタンスに変更を加えません。では、terraform applyを実行するたびにterraformにプロビジョナー「file」、「remote-exec」、または「local-exec」を実行させるにはどうすればよいですか?
詳細:
「remote-exec」からのエラーが原因でリソースが部分的にプロビジョニングされていることがよくあります(ほとんどの場合、スクリプトの作成中に間違ったコマンドを入力したことが原因です)。この後に再度terraformを実行すると、以前に作成されたリソースが破棄され、強制的にterraformが最初から新しいリソースを作成します。これは、リソースで "remote-exec"を2回実行できる唯一の方法でもあります...最初から作成することによって。
これは、完全にべき等であることを除いて、テラフォームとまったく同じ働きをすることができるansibleとは対照的に、テラフォームの欠点です。 「ec2」、「シェル」、「コピー」などのタスクでAnsibleを使用する場合、Teraformと同じタスクを実行できますが、これらのタスクのそれぞれがべき等です。 Ansibleは、変更を加える必要がない場合、それをどこで行うかを自動的に認識します。これにより、障害のあるansible-playbookがすべてを破壊してゼロから開始することなく、中断した箇所をピックアップできます。 Terraformにはこの機能がありません。
参考までに、「remote-exec」と「file」の両方のプロビジョナーを使用するec2インスタンスの単純なterraformリソースブロックを次に示します。
resource "aws_instance" "test" {
count = ${var.amt}
AMI = "AMI-2d39803a"
instance_type = "t2.micro"
key_name = "ansible_aws"
tags {
name = "test${count.index}"
}
#creates ssh connection to consul servers
connection {
user = "ubuntu"
private_key="${file("/home/ubuntu/.ssh/id_rsa")}"
agent = true
timeout = "3m"
}
provisioner "remote-exec" {
inline = [<<EOF
Sudo apt-get update
Sudo apt-get install curl unzip
echo hi
EOF
]
}
#copying a file over
provisioner "file" {
source = "scripts/test.txt"
destination = "/path/to/file/test.txt"
}
}
プロビジョニングに関するTerraformのドキュメント は、基本的なブートストラップのプロビジョナーの使用を1回だけのタスクと見なしており、Ansibleなどの適切な構成管理ツールの代わりとして使用しないでください:
プロビジョナーは、リソースが作成されたときにのみ実行されます。これらは、構成管理および既に実行中のサーバーのソフトウェアを変更する代わりではなく、単にbootstrapサーバーへの手段として提供されています。構成管理には、Terraformプロビジョニングを使用する必要があります。実際の構成管理ソリューションを呼び出します。
そして
リソースが正常に作成されたがプロビジョニング中に失敗した場合、Terraformはエラーになり、リソースを「汚染」としてマークします。汚染されたリソースは物理的に作成されていますが、プロビジョニングが失敗したため、安全に使用することはできません。
次の実行プランを生成すると、Terraformは汚染されたリソースを削除して新しいリソースを作成し、再度プロビジョニングを試みます。安全であることが保証されていないため、同じリソースでプロビジョニングを再開しようとしません。
Terraformは、失敗が発生したときに、適用中にリソースを自動的にロールバックおよび破棄しません。これは、実行計画に反するためです。実行計画では、リソースが作成されると言われていますが、削除されるとは言われていません。ただし、汚染されたリソースを使用して実行プランを作成すると、汚染されたリソースが破棄されることが明確に示されます。
プロビジョニングはbootstrapインスタンスを実行できるようにするために重要です。別の注意として、これは構成管理の代わりではありません。単にbootstrapマシンです。構成管理を使用する場合は、プロビジョニングをbootstrap構成管理ユーティリティの方法として使用する必要があります。
プロビジョニング時にEC2ユーザーデータスクリプトに似ていると考えてください。EC2ユーザーデータスクリプトは作成時に1回だけ実行され、失敗した場合はインスタンスを破棄して再試行する必要があります。
この利点は、Terraformがインスタンス自体よりも高いレベルで動作し、データセンター全体のプロビジョニングでより多くのレベルで動作するため、Terraformがオペレーティングシステムで変更をべき等にする方法に関する知識を必要としないことです。
これ以上の柔軟性が必要な場合は、Terraformを使用して構成管理システムを呼び出し、インスタンスを適切にプロビジョニングし(失敗した場合は、Terraformプロビジョニングステージから切り離して再試行を許可する)、またはJenkinsなどのオーケストレーションツールを使用することを検討してください。 TerraformとAnsibleなどの代替構成管理ツールの両方をラップします。
もう1つのオプションは、不変インフラストラクチャのルートに沿ってさらに進み、 Packer を使用して、Ansibleまたはその他のツールを使用してAMIを作成し、Terraformを使用して、AMIをそのままプロビジョニングすることで、追加のプロビジョニングを行う必要がないインスタンス。
私の検索でこのスレッドに出会い、最終的に解決策を見つけました:
resource "null_resource" "ansible" {
triggers {
key = "${uuid()}"
}
provisioner "local-exec" {
command = "ansible-playbook -i /usr/local/bin/terraform-inventory -u ubuntu playbook.yml --private-key=/home/user/.ssh/aws_user.pem -u ubuntu"
}
}
すべてのTerraform実行に固有のuuid()を使用して、nullリソースまたはプロビジョナーをトリガーできます。
taint
コマンドを使用してリソースに汚染のマークを付け、リソースを強制的に破棄して、次回の適用時に再作成することができます。