Terraform 内のリソースにおいて depends_on
という順序制御の仕組みがあります。しかし同じ module を複数呼び出す際に、シーケンシャルに実行したいケースがあるともいます。(私はありました)
もちろん呼び出す module
ごとに depends_on
を書けば解決するのですが、新しくmodule
を呼び出す処理を書く時に絶対 depends_on
を忘れそうです。
できれば「呼び出された module
側で対処して欲しい」ですね。
方法
方法は単純で作成したいリソースの前後にnull_resource
を作成し、ロックの作成、削除を行ないます。
イメージとしては以下のとおりです。
null_resource
でロックファイルを作成- リソースを作成
null_resource
でロックファイルを削除
このようにすることで上記のプロセスを複数箇所から呼び出しても、ロックファイルの有無によって並列実行を防ぐことが出来ます。
サンプルコード
今回は GCPでIPアドレスを作成するmoduleを3つ呼び出し、ロックファイルでこれらの実行をシーケンシャルにできるか試しました。(module名が node-pool
になっているのは無視してください)
コードはこちら。
module.node-pool-111111.null_resource.get_lock: Creating... module.node-pool-222222.null_resource.get_lock: Creating... module.node-pool-333333.null_resource.get_lock: Creating... module.node-pool-111111.null_resource.get_lock: Provisioning with 'local-exec'... module.node-pool-222222.null_resource.get_lock: Provisioning with 'local-exec'... module.node-pool-333333.null_resource.get_lock: Provisioning with 'local-exec'... module.node-pool-111111.null_resource.get_lock (local-exec): Executing: ["/bin/sh" "-c" "modules/test/get-lock.sh lockfile1"] module.node-pool-333333.null_resource.get_lock (local-exec): Executing: ["/bin/sh" "-c" "modules/test/get-lock.sh lockfile1"] module.node-pool-222222.null_resource.get_lock (local-exec): Executing: ["/bin/sh" "-c" "modules/test/get-lock.sh lockfile1"] module.node-pool-222222.null_resource.get_lock: Creation complete after 0s [id=6049866523593116765] module.node-pool-111111.null_resource.get_lock (local-exec): waiting: /tmp/lockfile1 module.node-pool-333333.null_resource.get_lock (local-exec): waiting: /tmp/lockfile1 ★ここで node-pool-222222 はロックが取れたので先に進んでいる module.node-pool-222222.google_compute_address.this: Creating... module.node-pool-111111.null_resource.get_lock: Still creating... [10s elapsed] module.node-pool-333333.null_resource.get_lock: Still creating... [10s elapsed] module.node-pool-222222.google_compute_address.this: Still creating... [10s elapsed] module.node-pool-222222.google_compute_address.this: Creation complete after 12s [id=projects/sre-training-267108/regions/asia-northeast1/addresses/test-2-address] ★ここで node-pool-222222 はリソースができたのでロックを削除している module.node-pool-222222.null_resource.release_lock: Creating... module.node-pool-222222.null_resource.release_lock: Provisioning with 'local-exec'... module.node-pool-222222.null_resource.release_lock (local-exec): Executing: ["/bin/sh" "-c" "modules/test/release-lock.sh lockfile1"] module.node-pool-222222.null_resource.release_lock (local-exec): delete: /tmp/lockfile1 module.node-pool-222222.null_resource.release_lock: Creation complete after 0s [id=8917614109989523954] module.node-pool-111111.null_resource.get_lock: Still creating... [20s elapsed] module.node-pool-333333.null_resource.get_lock: Still creating... [20s elapsed] module.node-pool-111111.null_resource.get_lock: Creation complete after 20s [id=7923255662165431221] module.node-pool-333333.null_resource.get_lock (local-exec): waiting: /tmp/lockfile1 ★ここで node-pool-111111 はロックが取れたので先に進んでいる module.node-pool-111111.google_compute_address.this: Creating... module.node-pool-333333.null_resource.get_lock: Still creating... [30s elapsed] module.node-pool-111111.google_compute_address.this: Still creating... [10s elapsed] module.node-pool-111111.google_compute_address.this: Creation complete after 12s [id=projects/sre-training-267108/regions/asia-northeast1/addresses/test-1-address] ★ここで node-pool-111111 はリソースができたのでロックを削除している module.node-pool-111111.null_resource.release_lock: Creating... module.node-pool-111111.null_resource.release_lock: Provisioning with 'local-exec'... module.node-pool-111111.null_resource.release_lock (local-exec): Executing: ["/bin/sh" "-c" "modules/test/release-lock.sh lockfile1"] module.node-pool-111111.null_resource.release_lock (local-exec): delete: /tmp/lockfile1 module.node-pool-111111.null_resource.release_lock: Creation complete after 0s [id=6082285058616397965] module.node-pool-333333.null_resource.get_lock: Still creating... [40s elapsed] module.node-pool-333333.null_resource.get_lock: Creation complete after 40s [id=8955755976657092243] ★ここで node-pool-333333 はロックが取れたので先に進んでいる module.node-pool-333333.google_compute_address.this: Creating... module.node-pool-333333.google_compute_address.this: Still creating... [10s elapsed] module.node-pool-333333.google_compute_address.this: Creation complete after 12s [id=projects/sre-training-267108/regions/asia-northeast1/addresses/test-3-address] ★ここで node-pool-333333 はリソースができたのでロックを削除している module.node-pool-333333.null_resource.release_lock: Creating... module.node-pool-333333.null_resource.release_lock: Provisioning with 'local-exec'... module.node-pool-333333.null_resource.release_lock (local-exec): Executing: ["/bin/sh" "-c" "modules/test/release-lock.sh lockfile1"] module.node-pool-333333.null_resource.release_lock (local-exec): delete: /tmp/lockfile1 module.node-pool-333333.null_resource.release_lock: Creation complete after 0s [id=2383163452978889987]
以下コード
main.tf
module "node-pool-111111" { source = "./modules/test" name = "test-1" } module "node-pool-222222" { source = "./modules/test" name = "test-2" } module "node-pool-333333" { source = "./modules/test" name = "test-3" }
modules/test/main.tf
resource "null_resource" "get_lock" { triggers = { name = var.name } provisioner "local-exec" { command = "${path.module}/get-lock.sh lockfile1" } } resource "google_compute_address" "this" { name = "${var.name}-address" address_type = "EXTERNAL" region = "asia-northeast1" depends_on = [ null_resource.get_lock ] } resource "null_resource" "release_lock" { triggers = { name = var.name } provisioner "local-exec" { command = "${path.module}/release-lock.sh lockfile1" } depends_on = [ google_compute_address.this ] }
modules/test/get-lock.sh
#!/bin/bash set -o nounset LOCK_FILE="/tmp/$1" LOCK_TIMEOUT_SECONDS=${2:-1800} SECONDS=0 # lock 用のディレクトリが作成できるか、タイムアウトを迎えるまでループする # mkdir は atomic(同時に実行されても片方しか成功しない)なのでこれを利用してロックを取得する # see: http://mywiki.wooledge.org/BashFAQ/045 until mkdir $LOCK_FILE 2> /dev/null do [[ $SECONDS -gt $LOCK_TIMEOUT_SECONDS ]] \ && echo "timeout: $LOCK_FILE" \ && exit 1 echo "waiting: $LOCK_FILE" sleep 20 done exit 0
release-lock.sh
#!/bin/bash set -o pipefail set -o nounset set -o errexit LOCK_FILE="/tmp/$1" rm -rf "$LOCK_FILE" echo "delete: $LOCK_FILE"