これは、なにをしたくて書いたもの?
Terraformのモジュールというものを、この前初めて書いてみたのですが、同じリソース定義を別のモジュールに含めた時に、
どういう動きになるのかな?というのを確認してみたいと思いまして。
いろいろ、バリエーションを見ていきましょう。
環境
今回の環境は、こちら。
$ terraform version Terraform v0.12.24
また、TerraformのProviderとしてはMySQLを使用します。MySQLのバージョンは8.0.20で、動作しているサーバーのIPアドレスは
172.17.0.2とします。
まずは、ふつうに使う
最初は、なにも考えずにリソース定義をしてみます。最小でいこうと思うので、MySQLのデータベースを定義するだけにします。
main.tf
terraform { required_version = ">= 0.12.24" } provider "mysql" { endpoint = "172.17.0.2:3306" username = "root" password = "password" version = "1.9.0" } resource "mysql_database" "database" { name = "my_database" }
init。
$ terraform init
インストールされたMySQL Providerのバージョン。
$ terraform version Terraform v0.12.24 + provider.mysql v1.9.0
とりあえず。
$ terraform fmt -check -recursive -diff $ terraform validate
applyしてみます。
$ terraform apply -auto-approve
これはうまくいくので、いったんdestroy。
$ terraform destroy -force
同じ名前のリソースを定義する
結果は見えていますが、同じ名前(resource type name)のリソースを定義してみます。
main.tf
terraform { required_version = ">= 0.12.24" } provider "mysql" { endpoint = "172.17.0.2:3306" username = "root" password = "password" version = "1.9.0" } resource "mysql_database" "database" { name = "my_database" } resource "mysql_database" "database" { name = "my_database" }
planで確認。
$ terraform plan Error: Duplicate resource "mysql_database" configuration on main.tf line 28: 28: resource "mysql_database" "database" { A mysql_database resource named "database" was already declared at main.tf:24,1-37. Resource names must be unique per type in each module.
「モジュール内で、リソースの名前はユニークにしなければならない」と言われていますね。
これで、ある程度このあとの展開が見えた気がします。
モジュールにしてみる
次に、MySQLデータベースの定義をモジュールに切り出してみます。
modules/my-mysql/main.tf
resource "mysql_database" "database" { name = "my_database" }
モジュールを利用。
main.tf
terraform { required_version = ">= 0.12.24" } provider "mysql" { endpoint = "172.17.0.2:3306" username = "root" password = "password" version = "1.9.0" } module "my-mysql" { source = "./modules/my-mysql" }
initして
$ terraform init
apply。
$ terraform apply -auto-approve
これはうまくいくので、destroyします。
$ terraform destroy -force
モジュールのインスタンスを複数にしてみる
同じモジュールは、複数回インスタンス化できるようです。
Modules - Configuration Language - Terraform by HashiCorp
Multiple Instances of a Module
ちょっと、これを試してみましょう。
main.tf
terraform { required_version = ">= 0.12.24" } provider "mysql" { endpoint = "172.17.0.2:3306" username = "root" password = "password" version = "1.9.0" } module "my-mysql" { source = "./modules/my-mysql" } module "my-mysql2" { source = "./modules/my-mysql" }
同じモジュールを、別名で取り込みました。
initして
$ terraform init
planを見てみます。
$ terraform plan
すると、別々のリソース定義として扱われました。
------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.my-mysql.mysql_database.database will be created + resource "mysql_database" "database" { + default_character_set = "utf8" + default_collation = "utf8_general_ci" + id = (known after apply) + name = "my_database" } # module.my-mysql2.mysql_database.database will be created + resource "mysql_database" "database" { + default_character_set = "utf8" + default_collation = "utf8_general_ci" + id = (known after apply) + name = "my_database" } Plan: 2 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------
予想はしていましたが、リソース定義のtype、nameが同じでも、モジュールのインスタンスが異なると別の扱いになるわけですね。
applyしてみます。
$ terraform apply -auto-approve
同じ名前のMySQLデータベースは複数個作れないので、同名のデータベースを2つ作ろうとして失敗します。
Error: Error 1007: Can't create database 'my_database'; database exists on modules/my-mysql/main.tf line 1, in resource "mysql_database" "database": 1: resource "mysql_database" "database" {
なので、こういうことにならないように注意しましょう、ということになりますね。
destroyして破棄。
$ terraform destroy -force
同じモジュールをsourceにしたモジュールを、2つ用意する
最後に、別のモジュールが同じモジュールを参照する形で定義してみましょう。
2つモジュールを用意。中身は同じです。
modules/mysql1/main.tf
module "my-mysql" { source = "../my-mysql" }
こちらも同じ。
modules/mysql2/main.tf
module "my-mysql" { source = "../my-mysql" }
この2つのモジュールを読み込みます。
main.tf
terraform { required_version = ">= 0.12.24" } provider "mysql" { endpoint = "172.17.0.2:3306" username = "root" password = "password" version = "1.9.0" } module "mysql1" { source = "./modules/mysql1" } module "mysql2" { source = "./modules/mysql2" }
initして
$ terraform init
planを見てみます。
$ terraform plan
結果は、同じモジュールを複数インスタンス化した場合と同じですね。
------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.mysql1.module.my-mysql.mysql_database.database will be created + resource "mysql_database" "database" { + default_character_set = "utf8" + default_collation = "utf8_general_ci" + id = (known after apply) + name = "my_database" } # module.mysql2.module.my-mysql.mysql_database.database will be created + resource "mysql_database" "database" { + default_character_set = "utf8" + default_collation = "utf8_general_ci" + id = (known after apply) + name = "my_database" } Plan: 2 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------
これをapplyした場合、やはり失敗します。
$ terraform apply -auto-approve module.mysql1.module.my-mysql.mysql_database.database: Creating... module.mysql2.module.my-mysql.mysql_database.database: Creating... module.mysql1.module.my-mysql.mysql_database.database: Creation complete after 0s [id=my_database] Error: Error 1007: Can't create database 'my_database'; database exists on modules/my-mysql/main.tf line 1, in resource "mysql_database" "database": 1: resource "mysql_database" "database" {
確認できたので、destroy。
$ terraform destroy -force
まとめ
これで、リソース定義のスコープが確認できましたね。
- リソース定義は、同じモジュールでtype、nameの組み合わせでユニークにしなければならない
- モジュールが別になると、この制約はなくなるが、整合性が取れるようにしなければならない
ということですね。