Нарешті дійшов до модулей в 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]
Готово.