suzuzusu日記

(´・ω・`)

TerraformでFizzBuzz

ネタです。

Terraformとは

f:id:suzuzusu:20200610061323p:plain

AWSGCP、Azureなどのクラウドやサービスのプロビジョニングと管理を行うInfrastructure as Code(IaC)ツールです。 今回はこのTerraformを使ってFizzBuzzを書いていきます。

Terraformの環境構築

0.13.0-beta10.12.1 の2つの環境を用意します。理由は後述します。

wget https://releases.hashicorp.com/terraform/0.13.0-beta1/terraform_0.13.0-beta1_linux_amd64.zip
unzip terraform_0.13.0-beta1_linux_amd64.zip
mv terraform terraform_0.13

wget https://releases.hashicorp.com/terraform/0.12.1/terraform_0.12.1_linux_amd64.zip   
unzip terraform_0.12.1_linux_amd64.zip   
mv terraform terraform_0.12.1

rangeを使った方法(IaC感がない)

TerraformにはいくつかのBuilt-in Functionsがあり、中にはCollectionの関数でrangeがあります。 さらには三項演算子もあり、for文もあるので以下のように簡単に書くことができます。

main.tf

output "out" {
  value = [
    for i in range(1, 101): i % 15 == 0 ? "FizzBuzz" : i % 5 == 0 ? "Buzz" : i % 3 == 0 ? "Fizz" : i
  ]
}

これを 0.13.0-beta1 で実行すると以下のようにFuzzBuzzが実装されていることが分かると思います。

❯ ./terraform_0.13 apply -auto-approve

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

out = [
  "1",
  "2",
  "Fizz",
  "4",
  "Buzz",
  "Fizz",
  "7",
  "8",
  "Fizz",
  "Buzz",
  "11",
  "Fizz",
  "13",
  "14",
  "FizzBuzz",
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  "Buzz",
  "Fizz",
  "97",
  "98",
  "Fizz",
  "Buzz",
]

しかし、このコードは 0.12.1 では実行できません。

❯ ./terraform_0.12.1 apply -auto-approve

Error: Error locking state: Error acquiring the state lock: state snapshot was created by Terraform v0.13.0, which is newer than current v0.12.1; upgrade to Terraform v0.13.0 or greater to work with this state

Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.

なぜなら range 関数は 0.12.2 から追加された関数だからです。 何よりインフラを構築するツールなのに何も構築していないのでIaC感がないのが気になります。

Release v0.12.2 · hashicorp/terraform · GitHub

countを使った方法

そこでcountというパラメータを使用します。これは同じリソースを複数作成する際に用いるパラメータです。例えば100個同じリソースを作りたい場合はcount を100に設定します。 また、count.index を使うことでそれぞれのリソースのindexを取得できるので、1から100までの連番の生成が可能となります。以上のものを使って0.12.2 でも動くようにするのとIaC感があるコードになりそうですね!!

main.tf

今回はproviderにdockerを使ってdockerのリソースを複数作成して実装していきます。 dockerのコンテナを複数作成するように実装していきます。

terraform {
  required_providers {
    docker = {
      source = "terraform-providers/docker"
    }
  }
  required_version = ">= 0.13"
}

provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_container" "hello" {
  count = 15
  image = docker_image.hello.latest
  name  = "name-${count.index}"
  labels {
    label = "label-${count.index}"
    value = (count.index + 1) % 15 == 0 ? "FizzBuzz" : (count.index + 1) % 5 == 0 ? "Buzz" : (count.index + 1) % 3 == 0 ? "Fizz" : (count.index + 1)
  }
}

resource "docker_image" "hello" {
  name = "hello-world:latest"
}

output "out" {
  value = [for o in docker_container.hello : o.labels.*.value]
}

とりあえず1から15までを実行した結果が以下のようになります。

❯ terraform apply -auto-approve
❯ terraform output
out = [
  [
    "1",
  ],
  [
    "2",
  ],
  [
    "Fizz",
  ],
  [
    "4",
  ],
  [
    "Buzz",
  ],
  [
    "Fizz",
  ],
  [
    "7",
  ],
  [
    "8",
  ],
  [
    "Fizz",
  ],
  [
    "Buzz",
  ],
  [
    "11",
  ],
  [
    "Fizz",
  ],
  [
    "13",
  ],
  [
    "14",
  ],
  [
    "FizzBuzz",
  ],
]

一見成功してそうに見えますが、上記の count を100にして1から100で実行すると以下のようにコンテナが建てられず、Errorが出てしまいFizzBuzzが実装できないです。 running状態にならなかった場合にはnullが入ってしまいます。

❯ terraform apply -auto-approve
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error: Container 33111f01371fcff7a1de675ffb77523006fda97f869665e61d3e9dc5c3fc19d0 failed to be in running state

  on main.tf line 14, in resource "docker_container" "hello":
  14: resource "docker_container" "hello" {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
❯ terraform output
out = [
  null,
  null,
  null,
  null,
  null,
  [
    "Fizz",
  ],
  null,
  null,
  null,
  null,
  [
    "11",
  ],
  null,
  null,
  null,
  null,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  null,
  null,
  [
    "92",
  ],
  null,
  null,
  null,
  null,
  [
    "97",
  ],
]

main.tf

回避する策としてdockerのvolumeを複数作成するように変更します。

terraform {
  required_providers {
    docker = {
      source = "terraform-providers/docker"
    }
  }
  required_version = ">= 0.13"
}

provider "docker" {
  host = "unix:///var/run/docker.sock"
}

resource "docker_volume" "volume" {
  count = 100
  name  = "name-${count.index}"
  labels {
    label = "label-${count.index}"
    value = (count.index + 1) % 15 == 0 ? "FizzBuzz" : (count.index + 1) % 5 == 0 ? "Buzz" : (count.index + 1) % 3 == 0 ? "Fizz" : (count.index + 1)
  }
}

output "out" {
  value = [for o in docker_volume.volume : o.labels.*.value]
}
❯ terraform apply -auto-approve
❯ terraform output
out = [
  [
    "1",
  ],
  [
    "2",
  ],
  [
    "Fizz",
  ],
  [
    "4",
  ],
  [
    "Buzz",
  ],
  [
    "Fizz",
  ],
  [
    "7",
  ],
  [
    "8",
  ],
  [
    "Fizz",
  ],
  [
    "Buzz",
  ],
  [
    "11",
  ],
  [
    "Fizz",
  ],
  [
    "13",
  ],
  [
    "14",
  ],
  [
    "FizzBuzz",
  ],
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  [
    "91",
  ],
  [
    "92",
  ],
  [
    "Fizz",
  ],
  [
    "94",
  ],
  [
    "Buzz",
  ],
  [
    "Fizz",
  ],
  [
    "97",
  ],
  [
    "98",
  ],
  [
    "Fizz",
  ],
  [
    "Buzz",
  ],
]

うまくいきましたね!!これで古い環境でもFizzBuzzが実装できるようになりました!!

このコードをクラウドの高いGPUインスタンスで実行してみたいので誰か僕に寄付してください(やりません)。

Repository

github.com