Нарешті дійшов до модулей в Terraform, а саме – треба було розібратися, як між двома модулями передати значення змінних.
Далі – самі базові і прості приклади роботи з модулями та їх values && outputs.
Див. більше в документації – Modules.
Зміст
Корневий модуль
Спочатку, створимо рутовий модуль, який просто створює локальний файл, і в якому далі будемо описувати модулі.
Створюємо тестовий каталог:
[simterm]
$ mkdir modules_example $ cd modules_example/
[/simterm]
В ньому додаємо файл main.tf
, в якому через resource
типу local_file
створюємо файл file.txt, в якому буде текст “file content“:
resource "local_file" "file" { content = "file content" filename = "file.txt" }
Запускаємо init
, что б підтягнути необхідні модулі самого Тераформу:
[simterm]
$ terraform init Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/local... - Installing hashicorp/local v2.2.3... - Installed hashicorp/local v2.2.3 (signed by HashiCorp) ... Terraform has been successfully initialized!
[/simterm]
Потім plan
– перевіряємо чи буде воно робити взагалі, та що саме:
[simterm]
$ terraform plan Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # local_file.file will be created + resource "local_file" "file" { + content = "file content" + directory_permission = "0777" + file_permission = "0777" + filename = "file.txt" + id = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy.
[/simterm]
Виглядає ОК – виконуємо apply
:
[simterm]
$ terraform apply Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # local_file.file will be created + resource "local_file" "file" { + content = "file content" + directory_permission = "0777" + file_permission = "0777" + filename = "file.txt" + id = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes local_file.file: Creating... local_file.file: Creation complete after 0s [id=87758871f598e1a3b4679953589ae2f57a0bb43c] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[/simterm]
І перевіряємо зміст каталогу, в якому запускали:
[simterm]
$ ls -l total 12 -rwxr-xr-x 1 setevoy setevoy 12 Nov 28 13:14 file.txt -rw-r--r-- 1 setevoy setevoy 90 Nov 28 13:09 main.tf -rw-r--r-- 1 setevoy setevoy 854 Nov 28 13:14 terraform.tfstate
[/simterm]
Та зміст файлу file.txt
:
[simterm]
$ cat file.txt file content
[/simterm]
Робить, поїхали далі.
Модулі Terraform
Далі, переходимо власне до модулів.
Створюємо два каталоги під два модулі:
[simterm]
$ mkdir -p modules/file_1 $ mkdir -p modules/file_2
[/simterm]
В кожному створюємо свій main.tf
– modules/file_1/main.tf
та modules/file_2/main.tf
.
В modules/file_1/main.tf
використовуємо той же самий local_file
для створення файлу file_1.txt:
resource "local_file" "file_1" { content = "file_1 content" filename = "file_1.txt" }
Аналогічно в modules/file_2/main.tf
для file_2.txt:
resource "local_file" "file_2" { content = "file_2 content" filename = "file_2.txt" }
Оновлюємо корневий модуль, тобто modules_example/main.tf
– видаляємо resource "local_file"
, і замість нього описуємо два модулі, в яких вказуємо шляхи до каталогів обох модулів:
module "file_1" { source = "./modules/file_1" } module "file_2" { source = "./modules/file_2" }
Запускаеємо init
знову, щоб Тераформ створив свою структуру модулей:
[simterm]
$ terraform init Initializing modules... - file_1 in modules/file_1 - file_2 in modules/file_2 Initializing the backend... Initializing provider plugins... - Reusing previous version of hashicorp/local from the dependency lock file - Using previously-installed hashicorp/local v2.2.3 Terraform has been successfully initialized!
[/simterm]
Перевіряємо в .terraform/modules/
:
[simterm]
$ cat .terraform/modules/modules.json | jq { "Modules": [ { "Key": "", "Source": "", "Dir": "." }, { "Key": "file_1", "Source": "./modules/file_1", "Dir": "modules/file_1" }, { "Key": "file_2", "Source": "./modules/file_2", "Dir": "modules/file_2" } ] }
[/simterm]
Запускаємо plan
:
[simterm]
$ terraform plan local_file.file: Refreshing state... [id=87758871f598e1a3b4679953589ae2f57a0bb43c] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create - destroy Terraform will perform the following actions: # local_file.file will be destroyed # (because local_file.file is not in configuration) - resource "local_file" "file" { - content = "file content" -> null - directory_permission = "0777" -> null - file_permission = "0777" -> null - filename = "file.txt" -> null - id = "87758871f598e1a3b4679953589ae2f57a0bb43c" -> null } # module.file_1.local_file.file_1 will be created + resource "local_file" "file_1" { + content = "file_1 content" + directory_permission = "0777" + file_permission = "0777" + filename = "file_1.txt" + id = (known after apply) } # module.file_2.local_file.file_2 will be created + resource "local_file" "file_2" { + content = "file_2 content" + directory_permission = "0777" + file_permission = "0777" + filename = "file_2.txt" + id = (known after apply) } Plan: 2 to add, 0 to change, 1 to destroy.
[/simterm]
І теперь можна виконувати apply
.
Щоб не вводити кожен раз “yes” – додаємо аргумент -auto-approve
:
[simterm]
$ terraform apply -auto-approve local_file.file: Refreshing state... [id=87758871f598e1a3b4679953589ae2f57a0bb43c] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create - destroy Terraform will perform the following actions: # local_file.file will be destroyed # (because local_file.file is not in configuration) - resource "local_file" "file" { - content = "file content" -> null - directory_permission = "0777" -> null - file_permission = "0777" -> null - filename = "file.txt" -> null - id = "87758871f598e1a3b4679953589ae2f57a0bb43c" -> null } # module.file_1.local_file.file_1 will be created + resource "local_file" "file_1" { + content = "file_1 content" + directory_permission = "0777" + file_permission = "0777" + filename = "file_1.txt" + id = (known after apply) } # module.file_2.local_file.file_2 will be created + resource "local_file" "file_2" { + content = "file_2 content" + directory_permission = "0777" + file_permission = "0777" + filename = "file_2.txt" + id = (known after apply) } Plan: 2 to add, 0 to change, 1 to destroy. local_file.file: Destroying... [id=87758871f598e1a3b4679953589ae2f57a0bb43c] module.file_2.local_file.file_2: Creating... module.file_1.local_file.file_1: Creating... local_file.file: Destruction complete after 0s module.file_2.local_file.file_2: Creation complete after 0s [id=7225b36c22072cd558c23529d0d992c29cb873be] module.file_1.local_file.file_1: Creation complete after 0s [id=82888a6ec6b05fc219759bd241ca5f0d6cba0e23] Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
[/simterm]
Перевіряємо, чи з’вились файли:
[simterm]
$ ll total 24 -rwxr-xr-x 1 setevoy setevoy 14 Nov 28 13:21 file_1.txt -rwxr-xr-x 1 setevoy setevoy 14 Nov 28 13:21 file_2.txt -rw-r--r-- 1 setevoy setevoy 104 Nov 28 13:18 main.tf drwxr-xr-x 4 setevoy setevoy 4096 Nov 28 13:15 modules
[/simterm]
Та їх зміст:
[simterm]
$ cat file_1.txt file_1 content $ cat file_2.txt file_2 content
[/simterm]
Працює? Го далі.
Змінні в модулях Terraform
Тут нічого особливого – все теж саме, як зі звичайними змінними Terraform. Див. документацію – Input Variables.
В файлі modules_example/modules/file_1/main.tf
об’являємо змінну user_name
:
variable "user_name" { type = string } resource "local_file" "file_1" { content = "file_1 content from ${var.user_name}" filename = "file_1.txt" }
Теж саме в другому модулі:
variable "user_name" { type = string } resource "local_file" "file_2" { content = "file_2 content from ${var.user_name}" filename = "file_2.txt" }
Оновлюємо рутовий модуль – передаємо значення user_name
для обох модулів:
module "file_1" { user_name = "user1" source = "./modules/file_1" } module "file_2" { user_name = "user2" source = "./modules/file_2" }
Аплаїмо:
[simterm]
$ terraform apply -auto-approve module.file_1.local_file.file_1: Refreshing state... [id=82888a6ec6b05fc219759bd241ca5f0d6cba0e23] module.file_2.local_file.file_2: Refreshing state... [id=7225b36c22072cd558c23529d0d992c29cb873be] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: -/+ destroy and then create replacement Terraform will perform the following actions: # module.file_1.local_file.file_1 must be replaced -/+ resource "local_file" "file_1" { ~ content = "file_1 content" -> "file_1 content from user1" # forces replacement ~ id = "82888a6ec6b05fc219759bd241ca5f0d6cba0e23" -> (known after apply) # (3 unchanged attributes hidden) } # module.file_2.local_file.file_2 must be replaced -/+ resource "local_file" "file_2" { ~ content = "file_2 content" -> "file_2 content from user2" # forces replacement ~ id = "7225b36c22072cd558c23529d0d992c29cb873be" -> (known after apply) # (3 unchanged attributes hidden) } ... Apply complete! Resources: 2 added, 0 changed, 2 destroyed.
[/simterm]
І перевіряємо:
[simterm]
$ cat file_1.txt file_1 content from user1
[/simterm]
Модулі та Output значень змінних
Що як нам треба із модуля передати значення змінної в рутовий модуль? Використовуємо outputs
– див. документацію Output Values.
Оновлюємо перший модуль – додаємо output
з іменем “file_content“:
variable "user_name" { type = string } resource "local_file" "file_1" { content = "file_1 content from ${var.user_name}" filename = "file_1.txt" } output "file_content" { value = file("file_1.txt") }
Теж саме в другому:
variable "user_name" { type = string } resource "local_file" "file_2" { content = "file_2 content from ${var.user_name}" filename = "file_2.txt" } output "file_content" { value = file("file_2.txt") }
І далі в рутовому модулі використовуємо отриманні значення за допомогою module.<MODULE_NAME>.<OUTPUD_NAME>
для створення файлу concat_file.txt:
module "file_1" { user_name = "user1" source = "./modules/file_1" } module "file_2" { user_name = "user2" source = "./modules/file_2" } resource "local_file" "concat_file" { content = "${module.file_1.file_content}\n${module.file_2.file_content}\n" filename = "concat_file.txt" }
Запускаємо apply
:
[simterm]
$ terraform apply -auto-approve module.file_2.local_file.file_2: Refreshing state... [id=5771aa8b1046de4f4342d492faee20e3c289365d] module.file_1.local_file.file_1: Refreshing state... [id=8a3552bfa2e46f311e7b718f8eed71b69bb8115f] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # local_file.concat_file will be created + resource "local_file" "concat_file" { + content = <<-EOT file_1 content from user1 file_2 content from user2 EOT + directory_permission = "0777" + file_permission = "0777" + filename = "concat_file.txt" + id = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. local_file.concat_file: Creating... local_file.concat_file: Creation complete after 0s [id=a4e1240fb9cdc96fffc1b0984392f6218422d194] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[/simterm]
Перевіряємо:
[simterm]
$ cat concat_file.txt file_1 content from user1 file_2 content from user2
[/simterm]
Передача значень змінних між модулями
І, нарешті, те, з чого почали – як передати значення з одного модулю в інший?
В файлі main.tf
першого модулю додаємо змінну з іменем module_1_value
, якій задаємо дефолтне значення “module 1 value“:
... variable "module_1_value" { type = string default = "module 1 value" } ...
Там же створюємо другу змінну module_2_value
, в яку потім передамо значення з другого модулю:
... variable "module_2_value" { type = string } ...
Додаємо output
щоб повернути значення змінної module_1_value
в рутовий модуль для подальшого використання в другому модулі:
... output "module_1_value" { value = var.module_1_value } ...
Повністю файл тепер виглядає так:
variable "user_name" { type = string } variable "module_1_value" { type = string default = "module 1 value" } variable "module_2_value" { type = string } resource "local_file" "file_1" { content = "file_1 content from ${var.user_name} with value from file_2: ${var.module_2_value}" filename = "file_1.txt" } output "file_content" { value = file("file_1.txt") } output "module_1_value" { value = var.module_1_value }
Тут в ресурсі local_file
будемо використовувати значення, передане з другого модулю.
Повторюємо теж саме для модулю file_2
:
variable "user_name" { type = string } variable "module_2_value" { type = string default = "module 2 value" } variable "module_1_value" { type = string } resource "local_file" "file_2" { content = "file_2 content from ${var.user_name} with value from file_1: ${var.module_1_value}" filename = "file_2.txt" } output "file_content" { value = file("file_2.txt") } output "module_2_value" { value = var.module_2_value }
Повертаємось до корневого модулю та додаємо передачу змінної module_2_value
в першому модулі, та змінної module_1_value
до другого модулю:
module "file_1" { user_name = "user1" module_2_value = module.file_2.module_2_value source = "./modules/file_1" } module "file_2" { user_name = "user2" module_1_value = module.file_1.module_1_value source = "./modules/file_2" } resource "local_file" "concat_file" { content = "${module.file_1.file_content}\n${module.file_2.file_content}\n" filename = "concat_file.txt" }
Теперь в файлі file_1.txt
маємо отримати значення із module "file_2"
, і навпаки.
Запускаємо:
[simterm]
$ terraform apply -auto-approve module.file_1.local_file.file_1: Refreshing state... [id=d74b0e0b3296ab02e7b4791942d983b175d071b4] local_file.concat_file: Refreshing state... [id=e0e88293b53693a484db146b15bd2ab3d8f4d250] module.file_2.local_file.file_2: Refreshing state... [id=12faf027dc96d886c6022b54c878324a21d3d112] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: -/+ destroy and then create replacement Terraform will perform the following actions: # local_file.concat_file must be replaced -/+ resource "local_file" "concat_file" { ~ content = <<-EOT # forces replacement - file_1 content from user1 with value from file_2: variable 2 value - file_2 content from user2 with value from file_1: variable 1 value + file_1 content from user1 with value from file_2: module 2 value + file_2 content from user2 with value from file_1: module 1 value EOT ~ id = "e0e88293b53693a484db146b15bd2ab3d8f4d250" -> (known after apply) # (3 unchanged attributes hidden) } Plan: 1 to add, 0 to change, 1 to destroy. local_file.concat_file: Destroying... [id=e0e88293b53693a484db146b15bd2ab3d8f4d250] local_file.concat_file: Destruction complete after 0s local_file.concat_file: Creating... local_file.concat_file: Creation complete after 0s [id=648854841581b273d26646fff776b33fdf060a19] Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
[/simterm]
Перевіряємо результат:
[simterm]
$ cat concat_file.txt file_1 content from user1 with value from file_2: module 2 value file_2 content from user2 with value from file_1: module 1 value
[/simterm]
Готово.