Читаем Terraform: инфраструктура на уровне кода полностью

user_data = <

#!/bin/bash

echo "Hello, World" >> index.html

echo "${data.terraform_remote_state.db.outputs.address}" >> index.html

echo "${data.terraform_remote_state.db.outputs.port}" >> index.html

nohup busybox httpd -f -p ${var.server_port} &

EOF

Чем длиннее становится скрипт в параметре user_data, тем более неряшливым выглядит ваш код. Встраивание одного языка программирования (bash) в другой (Terraform) усложняет поддержку обоих, поэтому давайте на секунду остановимся и вынесем bash-скрипт в отдельный файл. Для этого можно использовать встроенную функцию file и источник данных template_file. Рассмотрим их по отдельности.

Terraform включает в себя ряд встроенных функций, которые можно выполнять с помощью выражения такого вида:

function_name (...)

Возьмем для примера функцию format:

format(, , ...)

Эта функция форматирует аргументы в ARGS в соответствии с синтаксисом sprintf, заданным в строке FMT41. Отличным способом поэкспериментировать со встроенными функциями является использование команды terraformconsole. Она создает интерактивную консоль, в которой вы можете попробовать синтаксис Terraform, запросить состояние вашей инфраструктуры и сразу же получить результаты:

$ terraform console

> format("%.3f", 3.14159265359)

3.142

Стоит отметить, что консоль Terraform предназначена только для чтения, поэтому не нужно волноваться о случайном изменении инфраструктуры или состояния.

Существует целый ряд других встроенных функций для работы со строками, числами, списками и ассоциативными массивами42. К их числу относится функция file:

file()

Эта функция читает файл с путем PATH и возвращает его содержимое в виде строки. Например, вы могли бы сохранить скрипт пользовательских данных в файл stage/services/webserver-cluster/user-data.sh и загружать его следующим образом:

file("user-data.sh")

Подвох в том, что скрипту пользовательских данных для кластера веб-серверов необходима определенная динамическая информация из Terraform, включая порт сервера, а также адрес и порт базы данных. Когда скрипт был встроен в код Terraform, он получал эти значения с помощью ссылок и интерполяции. С функцией file это не сработает. Однако вместо этого вы можете воспользоваться источником данных template_file.

Источник данных template_file принимает два аргумента: template (строка, которую нужно обработать) и vars (ассоциативный массив с переменными, которые должные быть доступны во время обработки). Он содержит одну выходную переменную, rendered, которая является результатом обработки template. Чтобы увидеть это в деле, добавьте следующий код источника template_file в файл stage/services/webserver-cluster/main.tf:

data "template_file" "user_data" {

  template = file("user-data.sh")

  vars = {

    server_port = var.server_port

    db_address  = data.terraform_remote_state.db.outputs.address

    db_port     = data.terraform_remote_state.db.outputs.port

  }

}

Как видите, этот код присваивает параметрам template и vars содержимое скрипта user-data.sh и, соответственно, три переменные, которые нужны этому скрипту: порт сервера, адрес и порт базы данных. Для использования этих переменных нужно соответствующим образом обновить скрипт stage/services/webserver-cluster/user-data.sh:

#!/bin/bash

cat > index.html <

Hello, World

DB address: ${db_address}

DB port: ${db_port}

EOF

nohup busybox httpd -f -p ${server_port} &

Обратите внимание на несколько изменений в этом bash-скрипте по сравнению с оригиналом.

• Он ищет переменные с помощью стандартного синтаксиса интерполяции Terraform. Единственными переменными в данном случае являются те, что находятся в ассоциативном массиве vars источника template_file. Стоит отметить, что для доступа к ним не нужен никакой префикс: например, вместо var.server_port следует писать server_port.

• Теперь в скрипте можно заметить синтаксис HTML (скажем,

), который делает вывод более удобным для чтения в браузере.

Замечание о внешних файлах

Одним из преимуществ выноса скрипта пользовательских данных в отдельный файл является возможность написания для него модульных тестов. Код теста может даже заполнить интерполированные значения с помощью переменных среды, поскольку для поиска последних bash использует тот же синтаксис, который в Terraform применяется для интерполяции. Вы можете написать автоматический тест для user-data.sh примерно такого вида:

export db_address=12.34.56.78

export db_port=5555

export server_port=8888

./user-data.sh

output=$(curl "http://localhost:$server_port")

if [[ $output == *"Hello, World"* ]]; then

  echo "Success! Got expected text from server."

else

  echo "Error. Did not get back expected text 'Hello, World'."

fi

Заключительным шагом будет обновление параметра user_data в ресурсе aws_launch_configuration. Присвойте ему обработанный выходной атрибут источника данных template_file:

resource "aws_launch_configuration" "example" {

  image_id        = "ami-0c55b159cbfafe1f0"

  instance_type   = "t2.micro"

  security_groups = [aws_security_group.instance.id]

  user_data       = data.template_file.user_data.rendered

  # Требуется при использовании группы автомасштабирования

  # в конфигурации запуска.

  # https://www.terraform.io/docs/providers/aws/r/launch_configuration.html

  lifecycle {

    create_before_destroy = true

  }

}

Выглядит намного аккуратней, чем встраивание bash-скриптов!

Если развернуть этот кластер с помощью команды terraformapply, подождать, пока серверы не зарегистрируются в ALB, и открыть URL-адрес ALB в браузере, можно увидеть нечто похожее на рис. 3.12.

Ура! Ваш кластер веб-серверов теперь может программно обращаться к адресу и порту базы данных через Terraform. Если вы используете настоящий веб-фреймворк (вроде Ruby on Rails), можете задать адрес и порт в виде переменных среды или записать их в конфигурационный файл, чтобы их могла использовать ваша библиотека для работы с БД (как ActiveRecord).

Рис. 3.12. Кластер веб-серверов может программно обращаться к адресу и порту базы данных

Резюме

Причина, по которой вам следует уделять столько внимания изоляции, блокированию и состоянию, заключается в том, что IaC отличается от обычного программирования. При написании кода для типичного приложения большинство ошибок оказываются относительно несущественными и портят только небольшую его часть. Но когда вы пишете код для управления инфраструктурой, программные ошибки имеют более серьезные последствия, поскольку могут затронуть все ваши приложения вместе со всеми источниками данных, топологией сети и практически всем остальным. Поэтому при работе над IaC советую использовать больше «защитных механизмов», чем при написании обычного кода43.

Применение рекомендуемой структуры файлов и каталогов часто приводит к дублированию кода. Если вы хотите запускать кластер веб-серверов как в тестовой, так и в промышленной среде, как избежать копирования и вставки большого количества фрагментов между stage/services/webserver-cluster и prod/services/webserver-cluster? Ответ: использовать модули Terraform, которым посвящена глава 4.

34 Узнайте больше о гарантиях, которые дает S3, по адресу amzn.to/31ihjAg.

35 Ознакомьтесь с тарифами для S3 по адресу amzn.to/2yTtnw1.

36 Подробнее об именах бакетов S3 можно почитать по адресу bit.ly/2b1s7eh.

37 Ознакомьтесь с тарифами для DynamoDB по адресу amzn.to/2OJiyHp.

38 По адресу bit.ly/2lTsewM представлен яркий пример того, что может случиться, если не изолировать состояние Terraform.

39 Подробнее об этом читайте в документации Terragrunt по адресу bit.ly/2M48S8e.

40 Большинство командных оболочек в Linux/Unix/OS X сохраняют каждую вводимую вами команду в файл истории какого-то рода (например, ~/.bash_history). Но если начать команду с пробела, почти все оболочки не станут ее туда записывать. Имейте в виду, что эта возможность может быть отключена в вашей командной оболочке. Чтобы ее включить, придется присвоить переменной среды HISTCONTROL значение ignoreboth.

41 На странице golang.org/pkg/fmt/ можно найти документацию для синтаксиса sprintf.

42 На странице bit.ly/2GNCxOM представлен полный список встроенных функций.

43 Подробнее о защитных механизмах в ПО можно почитать по адресу bit.ly/2YJuqJb.

Перейти на страницу:

Все книги серии Бестселлеры O'Reilly

Искусство управления IT-проектами
Искусство управления IT-проектами

В отличие от множества трудов, посвященных руководству проектами и командами, в этой книге не проповедуются никакие новые учения и не превозносятся великие теории. Скотт Беркун считает залогом успеха практику и разнообразие подходов. В книге описываются основные сложности и проблемные ситуации, возникающие в работе менеджера проекта, даны рекомендации по выходу из них.Издание предназначено не только для лидеров команд и менеджеров высшего звена, но и для программистов, тестеров и других исполнителей конкретных проектных заданий. Также оно будет полезно студентам, изучающим бизнес-менеджмент, проектирование изделий или программную инженерию.Текст нового издания значительно переработан автором с целью добиться большей ясности, кроме того, книга дополнена новым приложением и более чем 120 практическими упражнениями.

Скотт Беркун

Деловая литература
iOS. Приемы программирования
iOS. Приемы программирования

Книга, которую вы держите в руках, представляет собой новый, полностью переписанный сборник приемов программирования по работе с iOS. Он поможет вам справиться с наболевшими проблемами, с которыми приходится сталкиваться при разработке приложений для iPhone, iPad и iPod Touch. Вы быстро освоите всю информацию, необходимую для начала работы с iOS 7 SDK, в частности познакомитесь с решениями для добавления в ваши приложения реалистичной физики или движений — в этом вам помогут API UIKit Dynamics.Вы изучите новые многочисленные способы хранения и защиты данных, отправки и получения уведомлений, улучшения и анимации графики, управления файлами и каталогами, а также рассмотрите многие другие темы. При описании каждого приема программирования приводятся образцы кода, которые вы можете смело использовать.

Вандад Нахавандипур

Программирование, программы, базы данных / Программирование / Книги по IT

Похожие книги