Terraform - ADV IT
Файлы имеют расширение .tf
После устновки можно добавить completion
terraform -install-autocomplete
Для работы с aws:
- Нужен пользователь с programmatic access и соответствующими полиси
- И нужно указать access_key и secret_key в манифесте:
provider "aws" { access_key = "AKIAZ****VWL" secret_key = "JOCF/mUjIZMX*****0" region = "eu-west-3" }
- Дальше можно работать (нужно выполнить
terraform init
чтобы терраформ скачал aws провайдер)
Важно понимать что во время terraform init
будут скачаны тяжелые файлы (aws-провайдер - 200M)
Им в гите делать нечего, да и к тому же они бинарные
Поэтому нужно в .gitignore
добавить .terraform
terraform plan
покажет что будет сделано
[02:31:18] vandud@macbook: terraform-test [0]$ 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:
# aws_instance.vandud-test-ubuntu will be created
+ resource "aws_instance" "vandud-test-ubuntu" {
+ ami = "ami-0f7cd40eac2214b37"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
...
При terraform apply
он выведет план и попросит ввести 'yes'
...
+ kms_key_id = (known after apply)
+ tags = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = (known after apply)
+ volume_type = (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
aws_instance.vandud-test-ubuntu: Creating...
aws_instance.vandud-test-ubuntu: Still creating... [10s elapsed]
aws_instance.vandud-test-ubuntu: Still creating... [20s elapsed]
aws_instance.vandud-test-ubuntu: Still creating... [30s elapsed]
aws_instance.vandud-test-ubuntu: Creation complete after 34s [id=i-00c0314fa4663a683]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[02:35:19] vandud@macbook: terraform-test [0]$
Так как terraform идемпотентен, то повторный запуск ничего не сломает
[02:35:19] vandud@macbook: terraform-test [0]$ terraform apply
aws_instance.vandud-test-ubuntu: Refreshing state... [id=i-00c0314fa4663a683]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
После apply
создается terraform.tfstate
В нем хранится инфа о созданной инфраструктуре и связь между инфраструктурой и описанием ресурсов из манифестов
Если удалить его то терраформ перестанет быть идемпотентным
Поэтому их хранят удаленно, например в s3
Вот пример где видно что после удаления этого файла терраформ хочет создать инфраструктуру заново:
[02:47:28] vandud@macbook: terraform-test [0]$ terraform apply
aws_instance.vandud-test-ubuntu: Refreshing state... [id=i-00c0314fa4663a683]
aws_instance.vandud-test-amazonlinux2: Refreshing state... [id=i-02a90eb65e901e6e8]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
[02:48:04] vandud@macbook: terraform-test [0]$ rm terraform.tfstate
[02:48:18] vandud@macbook: terraform-test [0]$ 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:
# aws_instance.vandud-test-amazonlinux2 will be created
+ resource "aws_instance" "vandud-test-amazonlinux2" {
+ ami = "ami-0b3e57ee3b63dd76b"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
Хорошо что по умолчанию создается terraform.tfstate.backup
...
Plan: 2 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: ^C
Interrupt received.
Please wait for Terraform to exit or data loss may occur.
Gracefully shutting down...
╷
│ Error: Error asking for approval: interrupted
│
│
╵
[02:50:50] vandud@macbook: terraform-test [1]$ ls
lesson-1.tf terraform.tfstate.backup
[02:50:52] vandud@macbook: terraform-test [0]$ mv terraform.tfstate.backup terraform.tfstate
[02:50:58] vandud@macbook: terraform-test [0]$ terraform apply
aws_instance.vandud-test-amazonlinux2: Refreshing state... [id=i-02a90eb65e901e6e8]
aws_instance.vandud-test-ubuntu: Refreshing state... [id=i-00c0314fa4663a683]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
[02:51:06] vandud@macbook: terraform-test [0]$ ls
lesson-1.tf terraform.tfstate terraform.tfstate.backup
[02:51:18] vandud@macbook: terraform-test [0]$
После изменения типа виртуалок:
Сначала удалит старые машины и только после удаления начнет создавать новые
Вручную сделанные изменения будут откачены
Пример ниже показывает как терраформ хочет удалить тэг с сервера который я добавил руками через web
[03:15:48] vandud@macbook: terraform-test [0]$ terraform apply
aws_instance.vandud-test-ubuntu[0]: Refreshing state... [id=i-00c0314fa4663a683]
aws_instance.vandud-test-ubuntu[2]: Refreshing state... [id=i-0171014586a119442]
aws_instance.vandud-test-amazonlinux2: Refreshing state... [id=i-02a90eb65e901e6e8]
aws_instance.vandud-test-ubuntu[1]: Refreshing state... [id=i-08b0b48d29e69ca8e]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_instance.vandud-test-ubuntu[2] will be updated in-place
~ resource "aws_instance" "vandud-test-ubuntu" {
id = "i-0171014586a119442"
~ tags = {
- "astoeu" = "aoeuaoeuaoeu" -> null
# (3 unchanged elements hidden)
}
~ tags_all = {
- "astoeu" = "aoeuaoeuaoeu" -> null
# (3 unchanged elements hidden)
}
# (27 unchanged attributes hidden)
# (4 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
...
Для удаления нужно удалить описание ресурса или можно поставить count = 0
destroy
удалит все что контролируется терраформом
Хранить креды в манифесте нельзя
Можно вынести их в окружение
[03:37:14] vandud@macbook: terraform-test [0]$ export AWS_ACCESS_KEY_ID=AKIA***O2VWL
[04:07:10] vandud@macbook: terraform-test [0]$ export AWS_SECRET_ACCESS_KEY=JOCF/mU****HTNN1FIcGR8Sd0
Функция file()
позволяет подставить на свое место содержимое файла
user_data = file("user_data.sh")
Темплейты принято обозначать расширением .tpl
, например user_data.sh.tpl
Вызвать темплейт можно через функцию templatefile
user_data = templatefile("user_data.sh.tpl", {
f_name = "Ivan",
l_name = "Dudin",
names = ["Alice", "Bob", "Calley", "Den"]
})
И сразу же в этой функции в шаблон передаются переменные
Сам шаблон:
[08:02:00] vandud@macbook: terraform-test [0]$ cat user_data.sh.tpl
#!/bin/bash
apt update
apt install nginx -y
myip=`curl http://2ip.ru`
echo "<h2>WebServer with IP: $myip </h2><br>Build by Terraform!<br><h1>user_data in external file!</h1>" > /var/www/html/index.html
cat <<EOF >> /var/www/html/index.html
Owner: ${f_name} ${l_name} <br>
%{ for name in names ~}
Hello ${name}!<br>
%{ endfor ~}
EOF
systemctl start nginx
Комментарии делаются так
/*
comment
*/
Цикл
resource "aws_security_group" "vandud_webserver_allow_http" {
name = "vandud_webserver_allow_http"
description = "Allow HTTP traffic"
dynamic "ingress" {
for_each = ["80", "443"]
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "allow_http_with_for_each"
}
}
Запретить удаление:
lifecycle { prevent_destroy = true }
[09:54:53] vandud@macbook: terraform-test [0]$ terraform apply
aws_security_group.vandud_webserver_allow_http: Refreshing state... [id=sg-0f78c46cdf8f193d4]
aws_instance.vandud-test-ubuntu: Refreshing state... [id=i-0db43c9b8a2b0f6f1]
╷
│ Error: Instance cannot be destroyed
│
│ on terraform.tf line 5:
│ 5: resource "aws_instance" "vandud-test-ubuntu" {
│
│ Resource aws_instance.vandud-test-ubuntu has lifecycle.prevent_destroy set, but the plan calls for this resource to be destroyed. To avoid this error and continue with the plan, either disable
│ lifecycle.prevent_destroy or reduce the scope of the plan using the -target flag.
Игнорировать какие-то конкретные изменения:
lifecycle { ignore_changes = [user_data] }
elastic ip
resource "aws_eip" "my_static_ip" {
instance = aws_instance.vandud-test-ubuntu.id
tags = { Name = "Elastic IP for Ubuntu" }
}
Сначала создать новый, потом удалить старый:
lifecycle { create_before_destroy = true }
Работает так
...
Plan: 1 to add, 1 to change, 1 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
aws_instance.vandud-test-ubuntu: Creating...
aws_instance.vandud-test-ubuntu: Still creating... [10s elapsed]
aws_instance.vandud-test-ubuntu: Still creating... [20s elapsed]
aws_instance.vandud-test-ubuntu: Still creating... [30s elapsed]
aws_instance.vandud-test-ubuntu: Creation complete after 34s [id=i-0bee1bc2c8ee22d92]
aws_eip.my_static_ip: Modifying... [id=eipalloc-00ba6881fbe733088]
aws_eip.my_static_ip: Modifications complete after 2s [id=eipalloc-00ba6881fbe733088]
aws_instance.vandud-test-ubuntu (8e7594e5): Destroying... [id=i-0db43c9b8a2b0f6f1]
aws_instance.vandud-test-ubuntu: Still destroying... [id=i-0db43c9b8a2b0f6f1, 10s elapsed]
aws_instance.vandud-test-ubuntu: Still destroying... [id=i-0db43c9b8a2b0f6f1, 20s elapsed]
aws_instance.vandud-test-ubuntu: Still destroying... [id=i-0db43c9b8a2b0f6f1, 30s elapsed]
aws_instance.vandud-test-ubuntu: Still destroying... [id=i-0db43c9b8a2b0f6f1, 40s elapsed]
aws_instance.vandud-test-ubuntu: Destruction complete after 42s
Apply complete! Resources: 1 added, 1 changed, 1 destroyed.
Выше видно что сначала удалил, потом создал
То же самое было видно в консоли
После выполнения можно выводить какую-то информацию
output "webserver_instance_id" { value = aws_instance.vandud-test-ubuntu.id }
output "webserver_public_ip_address" { value = aws_eip.my_static_ip.public_ip }
[10:20:16] vandud@macbook: terraform-test [0]$ terraform apply
aws_instance.vandud-test-ubuntu: Refreshing state... [id=i-0bee1bc2c8ee22d92]
aws_security_group.vandud_webserver_allow_http: Refreshing state... [id=sg-0f78c46cdf8f193d4]
aws_eip.my_static_ip: Refreshing state... [id=eipalloc-00ba6881fbe733088]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
webserver_instance_id = "i-0bee1bc2c8ee22d92"
webserver_public_ip_address = "13.36.217.252"
Для этого даже есть отдельная команда
[10:20:44] vandud@macbook: terraform-test [0]$ terraform output
webserver_instance_id = "i-0bee1bc2c8ee22d92"
webserver_public_ip_address = "13.36.217.252"
Манифесты могут быть разделены на несколько файлов
vandud@macbook: terraform-test [0]$ cat outputs.tf
output "webserver_instance_id" { value = aws_instance.vandud-test-ubuntu.id }
output "webserver_public_ip_address" { value = aws_eip.my_static_ip.public_ip }
vandud@macbook: terraform-test [0]$ terraform apply
aws_security_group.vandud_webserver_allow_http: Refreshing state... [id=sg-0f78c46cdf8f193d4]
aws_instance.vandud-test-ubuntu: Refreshing state... [id=i-0bee1bc2c8ee22d92]
aws_eip.my_static_ip: Refreshing state... [id=eipalloc-00ba6881fbe733088]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
webserver_instance_id = "i-0bee1bc2c8ee22d92"
webserver_public_ip_address = "13.36.217.252"
Терраформ читает все .tf
файлы и понимает что к чему
depends_on
позволяет делать зависимости
depends_on = [aws_instance.vandud-test-ubuntu]
При циклической зависимости ничего не заведется
Полезно использовать разную информацию через data sources
No Comments