Найти в Дзене
Nuances of programming

Создание динамического кластера ECS с помощью Terraform

Цель этой статьи предоставить вам наглядные примеры и инструкции по разработке динамического модуля ECS (Elastic Container Service ) с помощью Terraform. При этом предполагается наличие у вас базового представления о данном инструменте.
Оглавление

Источник: Nuances of Programming

Цель этой статьи предоставить вам наглядные примеры и инструкции по разработке динамического модуля ECS (Elastic Container Service ) с помощью Terraform. При этом предполагается наличие у вас базового представления о данном инструменте.

“Динамический” в данном случае означает, что Terraform может легко масштабироваться для обработки большего числа сервисов и задач.

Архитектура ECS (источник )
Архитектура ECS (источник )

0. Сеть

Определение самого кластера ECS не содержит сетевых требований.

Здесь нужно многое объяснить, и я начну с конфигурации сети.

network_configuration {
subnets = var.ecs_service_subnets
security_groups = [aws_security_group.ecs_security_groups[each.value["security_group_mapping" ]].id]
}

В этом инстансе (закрытые) подсети наследуются от модуля, определяющего наш VPC. При создании динамического кластера мы просто ссылаемся на список подсетей в модуле VPC, чтобы создать сервисы в собственном предпочтительном VPC.

Группы безопасности задействуют функцию for_each в Terraform, лежащую в основе многих механик этого модуля.

for_each

Данная функциональность позволяет создавать несколько ресурсов, использующих общие аргументы. Модулю требуется только, чтобы for_each был определен внутри ресурса, и переменная карты передавалась в указанный аргумент.

for_each = var.create_microservices == true ? var.fargate_microservices : {}

В этом случае мы указали, что для создания сервисов create_microservice должен быть true. Далее переменная fargate_microservices выступает в качестве карты, содержащей все необходимые сервису аргументы (пример приводится в разделе “Динамические сервисы”).

Группы безопасности (security groups)

Теперь давайте рассмотрим код модуля, позволяющий определять необходимое число групп безопасности:

Этот блок ресурса будет перебирать определенный вне модуля объект var.security_groups и выбирать переменную для каждой переменной с приставкой each.value .

Вот как определяется одна группа безопасности внутри модуля:

Затем эти инструкции отображаются в соответствующие им сервисы через переменную security_group_mapping внутри каждого сервиса. Эта переменная сопоставляет id группы безопасности (pro-ecs-sg ) с указанным сервисом. Таким образом можно легко добавить еще одну группу безопасности, просто присоединив этот объект карты.

Теперь мы еще раз вернемся к определению сервиса, чтобы посмотреть, как переменная security_group_mapping используется совместно с другими динамическими переменными.

1. Динамические сервисы

Разобравшись с настройками сети, давайте еще раз взглянем на определение сервиса :

Обратили внимание на переменную depends_on ? Этот список переменных обеспечивает создание задач и кластера до создания сервиса. В отсутствие любого из этих ресурсов собрать сервисы не удастся.

Как уже говорилось, для создания сервисов необходимо, чтобы переменная create_microsrvices была установлена как true . Если так и есть, то далее мы передаем карту переменных для определения наших сервисов:

Это похоже на магию, потому что теперь для создания нового сервиса потребуется лишь добавить в эту карту новый элемент.

Переменные определяются следующим образом:

В launch_type вы определяете, как ваш кластер должен запускать контейнеры: используя AWS Fargate или EC2. Чтобы понять, какой тип запуска лучше подходит под ваши требования, ознакомьтесь с руководством по этой ссылке (англ.)

Так как же мы создаем динамические задачи?

Общая схема задач, сервисов и кластеров (источник )
Общая схема задач, сервисов и кластеров (источник )

2. Динамические задачи

Вот полное определение динамических задач (англ.):

В самом верху снова задействуется for_each , для чего var.create_tasks должна быть установлена как true , чтобы прочитать объект карты var.ecs_tasks .

Сложнейшая часть этого проекта в создании динамических container_definitions . Эти переменные определяют выполняющие ваши задачи образы.

Аргумент container_defintions получает объект JSON, где определено, какой образ docker запускать, а также дополнительные необходимые переменные среды.

Все это помещается в тот же динамический цикл for_each , что и остальная часть ресурса, а затем совмещается с extra_template_variables в объекте JSON, позволяя динамическое обнаружение переменных среды.

Передаваемый в модуль объект карты для задач очень похож на объект сервиса:

Опять же здесь легко внедрить новую задачу и отобразить ее обратно на соответствующий сервис (имя семейства), просто добавив дополнительный элемент.

Объект карты для задач определяется в переменных схожим с динамическими сервисами образом:

3. Динамические логи

Вы могли заметить, что блок ресурса, определяющий задачи, содержит аргумент log_group .

aws_logs_group = "/aws/fargate/${aws_ecs_cluster.cluster.name} /${each .value["family" ]}/${var.environment} ",

Здесь указывается, куда должны отправляться логи для соответствующей задачи. Чтобы гарантировать правильную настройку этих групп логов, нужно определить динамический ресурс Cloudwatch:

Пока имя этих ресурсов будет соответствовать значению ключа aws_log_group внутри определения задач, мы будем получать логи в Cloudwatch.

4. IAM

Если для вас это полностью новый этап настройки, то в реализуемом нами решении понадобится определить две новых роли IAM. Ими являются task role и execution role динамических задач.

Task role определяет, с какими ресурсами AWS ваша задача может взаимодействовать. Ниже приведены соответствующие блоки данных и ресурса.

Данные (policy):

Ресурс (role):

Мы позволили задаче также вызывать AssumeRole через Security Token Service , чтобы она могла задействовать временные учетные данные для доступа к другим сервисам.

Execution role устанавливает доступ для агента контейнера ECS и демона Docker:

Этой роли мы дали те же разрешения, что и предыдущей, с помощью того же объекта данных (ecs_task_policy ).

Заключение

Рассмотренный модуль позволил моей команде ускоренно развертывать новые задачи и сервисы ECS, не требуя ручного изменения всех настроек через GUI.

Сам модуль активно задействует аргумент for_each внутри Terraform для масштабирования по мере необходимости. Такая структура оказывается очень полезна при реализации широкомасштабных решений Terraform.

Читайте также:

Читайте нас в Telegram , VK

Перевод статьи Liam Hartley : How To Create a Dynamic ECS Cluster With Terraform