TerraformでFizzBuzz
ネタです。
Terraformとは
AWS、GCP、Azureなどのクラウドやサービスのプロビジョニングと管理を行うInfrastructure as Code(IaC)ツールです。 今回はこのTerraformを使ってFizzBuzzを書いていきます。
Terraformの環境構築
0.13.0-beta1
と 0.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インスタンスで実行してみたいので誰か僕に寄付してください(やりません)。