自由気ままに書いちゃおう

好きなことをつらつらと・・・

【Terraform】(初心者向け)localsとvariableの使い分けについて

localsとvariableの違いについて記載致します。

■動作確認のTerraformバージョンについて

以下バージョンです。

Terraform v1.0.5
on linux_amd64

※1.1.9が出ている中、1.0.5は古い気がするけど・・・

■事の経緯

読解力がないせいか、locals/variableについていろんな丁寧なサイトをみてもどうもしっくりこなかったので、時間はかかったけど自分で検証してみた結果を記載しています。備忘です。。。そのため、間違ってたら申し訳ないです。

■はじめに

私みたいな勘違いをしないように最初に少し補足させていただきます。
variableとlocalsの違いや使い分けを考える際、
moduleを使った場合のvariableとlocalsについては一旦、後回しにした方が混乱しなくてすみます。


そのため、本記事では最初はmoduleは登場させず、後半に触れるようにいたします。

■localsとvariableの定義

まず、localsから。

続いて、variable。


どちらも、「is_prod」という変数名を定義して、値は「true」を設定しています。
書き方が違うのはよくわかったけど、私は「そうですか・・・」って感じでした。。。

■localsとvariableは何が違うのか1:特徴

【locals】

 ① 定義時に、条件式(3項演算子)が使える。
   この場合、var.is_prodがtrueであれば"prod~"、falseなら"dev~"が envnameに代入されます。

 ② 定義したものは、外部から上書き不可
   locals.envを上書きしたい場合、外部(=他のファイル)から上書きすることができません。

 ③ 定義したものは、直接参照不可(outputを利用した間接参照は可能)
   outputで間接参照させることはできます。

上記のように定義しておいて、他のファイルから下記のように呼び出す感じです。

【variable】

言ってしまえば、localsと逆の仕様になっているのがvariableです。

① 定義時に、条件式が使えない。
② 定義したものは、外部から上書き可能。
  例えば、以下のように定義したものを

  $ terraform plan -var 'is_prod=false' のよう実行することで「is_prod」は「false」になります。(defaultを上書きすることができます。)

③ 定義したものは、直接参照可能
  少し語弊がありそうですが、variableは同一階層内のtfファイルやmoduleでsource指定したファイル間で共有(使いまわし)が可能です。
   例えば、main.tf , sub.tfを同一階層に用意した場合、

実行結果は以下の通りです。sub.tfではmain.tfで定義されているis_prodを利用することができます。

注意点としては、variableを複数ファイルで使いまわすことは特に問題ないのですが、同じ名前のvariableを複数ファイルで定義する場合はエラーとなります。
興味本位で以下のようにmain.tfとsub.tfでis_prodを定義する(どちらのファイルも1行目~4行目が該当)とエラーになります。

 

■localsとvariableは何が違うのか2:参照範囲

「localsとvariableは何が違うのか1」では、それぞれの特徴を記載致しました。
ここでは、localsとvariableを定義後に、どこから参照することができるのか、という点について(=参照範囲について)記載致します。
結論から申し上げると、参照範囲は同じです。

【locals】

 参照範囲は、localsを記載したtfファイルおよび同一階層のtfファイルです。

【variable】

 参照範囲は、variableを記載したtfファイルおよび同一階層のtfファイルです。

■動作確認の環境について

ここからはmoduleも取り上げていきます。
以下ファイル構成で、


main.tf とmodules>main.tf という2ファイルが存在している環境です。
※コメントアウトがたくさんありますが、検証時の名残のためご放念ください。

【main.tf】

【modules>main.tf 】

 

■動作確認①:ひとまずplan実行

上記の通り
「main」(main.tfの23行目~25行目の結果)
「module-main」(main.tfの27行目~29行目の結果)が表示されています。

「main」(main.tfの23行目~25行目の結果)は下記でis_prodを定義しており(デフォルトtrue)

20行目のvar.is_prodがtrueとなり、「prod-main.tf」がenvnameに代入されます。

その結果、24行目の処理が実行され、


実行結果は以下の通りとなります。

目線移動は下記のような感じです。


main.tfの11行目にてmoduleの呼び出しが行われていますが、その際にis_prodを改めてfalseとして定義し直しています。なので1行目から4行目で定義されているvariableを上書きしている動作となります。

ここからmodule>main.tfの処理となりますが、1行目~4行目においてもis_prodはfalseのままとなり、

そのまま、

に処理が移ります。
var.is_prodがfalseのため

が出力されることになります。
目線移動は下記のような感じです。

 

■動作確認②:plan実行時に変数を上書き

動作がわかりやすいように、予め少しコードを修正してます。
is_prodはすべてfalseに書き換えています。
左ファイルの3行目と15行目、右ファイルの3行目が全てfalseの状態がスタートラインです。

まず、この状態でplan実行した場合、以下のようになります。

続けて、以下ようにis_prod=trueをつけて実行してみます。

「main」が「prod~」となり、「module-main」が「dev~」となりました。
このように、plan実行時に"変数名=値" で定義することで、variableを上書きすることができます。

■動作確認③:module内での変数について

後回しにしてきたmodule内の変数についてです。(正確には引数と呼ばれるものです)main.tf の10行目から15行目のmodule部分は、15行目で変数名を定義しています。
module の中で指定された変数は11行目で指定されているファイルに引き継がれます。module>main.tf  内でこの変数を利用するときには予め、変数定義をしておく必要があります。

なので、仮にmodule>main.tfの1行目~4行目をコメントアウトしてterraform planを実行するとエラーとなります。

このことからも、実際に変数を使うファイルの中できちんとvariableを定義しておく必要があることがわかります。
では、module>main.tf内でvariableを使わずにis_prodをlocalsで定義してみた場合、どうなるかというと、こちらもエラーとなります。main.tfで定義したmodule内の変数を使いたい場合にはmodule指定先(module>main.tfのことです)でvariableを定義する必要があるということです。

■動作確認④:main.tfでvariableを定義せず変数を使ってみる

main.tfの1行目~4行目をコメントアウトした場合です。
20行目でvariableを使おうとしているので、エラーとなります。

 

■動作確認⑤:main.tfとmodule>main.tfで同じ変数名で違う値を指定する

何を言っているのかわかりにくいと思います。。。。
main.tfの3行目でis_prod=falseを定義しており、
main.tfのmodule(14行目)ではis_prod=trueを定義している場合です。
※この状態を、「同じ変数名で違う値」と表現しています。


この場合、main.tf内のis_prodはfalseとなり、module>main.tf内のis_prodはTrueとなります。
その為、実行結果は以下の通りになります。

■結論:(個人的)使い分け

1.main.tfのmodule内で変数を定義するとき(引数を定義する時)には、module>XXX.tf内にvariableを定義してあげる

2.複数のtfファイルで同じ変数名で異なる値を定義することはできない

3.複数のtfファイルで同じ変数名で異なる値を利用する(使いまわす)ことはできる。

4.moduleを利用した場合、module内の変数(引数)を使う場合には、module指定先(module>main.tf)でvariableを定義する

5.localsは、そのtfファイル内でしか使わない値がある場合に用いる。

6.localsは、3項演算子を使いたい変数が存在する場合に用いる。


最初のうちはこんな感じの理解で何とかなると思います。

以上です。