«1. Обзор

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

2. Организация файлов ресурсов

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

Лучше использовать тот факт, что внутри модуля Terraform будет читать любой файл «.tf» и обрабатывать его содержимое. Порядок, в котором мы объявляем ресурсы в них, не имеет значения — в конце концов, это работа Terraform. Мы должны держать их в порядке, чтобы мы могли лучше понять, что происходит.

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

    variable.tf: сюда помещаются все входные переменные модуля, а также их значения по умолчанию, если применимо. main.tf: здесь мы будем размещать наши определения ресурсов. Предполагая, что мы используем принцип единой ответственности, его размер должен оставаться под контролем модулей: если наш модуль содержит какие-либо подмодули, они будут помещены сюда только в каталоге верхнего уровня, объявляет, какие провайдеры мы будем использовать в проекте, включая их версии

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

Кроме того, по мере развития нашего модуля мы должны следить за размером файла main.tf. Хорошим признаком того, что нам следует подумать о реорганизации его в подмодули, является то, что он начинает увеличиваться в размерах. На этом этапе мы должны реорганизовать его, переместив тесно связанные ресурсы, такие как экземпляр EC2 и подключенный том EBS, во вложенные модули. В конце концов, есть вероятность, что наш файл main.tf верхнего уровня содержит только ссылки на модули, сшитые вместе.

3. Использование модулей

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

Тем не менее, мы все еще можем повторно использовать некоторые уроки, извлеченные из кодовых баз приложений, которые могут помочь с правильной организацией модулей. Среди этих уроков весьма полезным является Единая ответственность из набора принципов S.O.L.I.D.

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

Давайте взглянем на образец структуры каталога проекта Terraform, в котором используется этот принцип:

$ tree .
├── main.tf
├── modules
│   ├── ingress
│   │   └── www.petshop.com.br
│   │       ├── main.tf
│   │       ├── outputs.tf
│   │       └── variables.tf
... other services omitted
│   └── SvcFeedback
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── outputs.tf
├── terraform.tfvars
└── variables.tf

Здесь мы использовали модули для каждого важного аспекта нашей инфраструктуры: базы данных, входа, обмена сообщениями, внешних служб и серверные службы. В этом макете каждая папка, содержащая файлы .tf, представляет собой модуль, содержащий три файла:

    variable.tf — входные переменные для модуля main.tf — определения ресурсов outputs.tf — определения выходных атрибутов ~~ ~ Преимущество этого соглашения состоит в том, что потребители модуля могут сразу перейти к его «контракту» — переменным и выходным данным — если они хотят, пропуская детали реализации.

4. Конфигурация провайдера

Большинство провайдеров в Terraform требуют, чтобы мы предоставили допустимые параметры конфигурации, чтобы он мог манипулировать ресурсами. Например, провайдеру AWS нужен ключ/секрет доступа и регион, чтобы он мог получить доступ к нашей учетной записи и выполнять задачи.

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

4.1. Использование переменных для настройки провайдера

«В этом подходе мы определяем переменную проекта для каждого требуемого параметра провайдера:

Теперь мы используем их в объявлении нашего провайдера:

variable "aws_region" {
  type = string
}
variable "aws_access_key" {
  type = string
}a
variable "aws_secret_key" {
  type = string
}

Наконец, мы предоставляем фактические значения, используя файл .tfvar: ~ ~~

provider "aws" {
  region = var.aws_region
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
}

Мы также можем комбинировать файлы .tfvar и переменные среды при выполнении команд Terraform, таких как plan или apply:

aws_access_key="xxxxx"
aws_secret_key="yyyyy"
aws_region="us-east-1"

Здесь мы использовали сочетание переменных среды и аргументов командной строки для передачи переменной ценности. Помимо этих источников, Terraform также просматривает переменные, определенные в файле terraform.tfvars и любом файле с расширением «.auto.tfvars» в папке проекта.

$ export TF_VAR_aws_region="us-east-1"
$ terraform plan -var="access_key=xxxx" -var-file=./aws.tfvars

4.2. Использование конфигурации, специфичной для провайдера

Во многих случаях провайдеры Terraform могут выбирать учетные данные из того же места, что и собственный инструмент. Типичный пример — провайдер Kubernetes. Если в нашей среде уже есть собственная утилита kubectl, настроенная так, чтобы она указывала на наш целевой кластер, нам не нужно предоставлять дополнительную информацию.

5. Управление состоянием

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

Всегда используйте правило исключения для файлов *.tfstate в нашем файле конфигурации VCS. Для Git это может быть глобальное правило исключения или файл .gitignore нашего проекта. Примите как можно скорее удаленный бэкэнд вместо локального бэкэнда по умолчанию. Кроме того, перепроверьте ограничения доступа к выбранному бэкенду.

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

Здесь мы сообщаем Terraform, что он будет использовать бэкэнд PostgreSQL для хранения информации о состоянии. Удаленные серверные части обычно требуют дополнительной настройки. Как и у провайдеров, рекомендуемый подход заключается в передаче необходимых параметров через переменные среды или файлы «.auto.tfvars». целевая среда. В этих сценариях нам следует избегать более чем одного запуска Terraform в одной и той же целевой среде — это может вызвать всевозможные условия гонки и конфликты и, вероятно, приведет к хаосу.

terraform {
  backend "pg" {}
}

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

Еще один способ обеспечить правильное управление файлами состояния — использовать выделенный сервер для запуска Terraform. Для этого мы можем использовать любые инструменты CI/CD, такие как Jenkins, GitLab и другие. Для небольших команд/организаций мы также можем использовать бесплатный уровень предложения Terraform SaaS.

6. Рабочие пространства

Рабочие пространства позволяют нам хранить несколько файлов состояний для одного проекта. Основываясь на аналогии с веткой VCS, мы должны начать использовать их в проекте, как только нам придется иметь дело с несколькими целевыми средами. Таким образом, у нас может быть единая кодовая база для воссоздания одних и тех же ресурсов независимо от того, куда мы указываем Terraform.

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

Имея это в виду, обычной практикой является называть рабочие пространства именами сред. Например, мы можем использовать такие имена, как DEV, QA и PRD, чтобы они соответствовали нашим существующим средам.

Если бы у нас было несколько команд, работающих над одним и тем же проектом, мы могли бы также указать их имена. Например, у нас может быть рабочее пространство DEV-SQUAD1 для команды, работающей над новыми функциями, и DEV-SUPPORT для другой команды, которая будет воспроизводить и исправлять производственные проблемы.

7. Тестирование

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

Типичный тест состоит из развертывания тестовой конфигурации во временной среде и запуска серии тестов для нее. Что должны охватывать тесты? Ну, это во многом зависит от специфики того, что мы создаем, но некоторые из них довольно распространены:

Доступность: правильно ли мы создали наши ресурсы? Достижимы ли они? Безопасность. Оставили ли мы открытыми несущественные сетевые порты? Мы отключили учетные данные по умолчанию? Корректность: правильно ли наш модуль использовал свои параметры? Отметил ли он какие-либо отсутствующие параметры?

На момент написания этой статьи тестирование Terraform все еще остается развивающейся темой. Мы можем писать наши тесты, используя любую среду, которую захотим, но те, которые ориентированы на интегрированные тесты, как правило, лучше подходят для этой задачи. Некоторые примеры включают, среди прочего, FitNesse, Spock и Protractor. Мы также можем создавать наши тесты, используя обычные сценарии оболочки, и добавлять их в наш конвейер CI/CD.

    8. Заключение

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

Как обычно, весь код доступен на GitHub.

«

As usual, all code is available over on GitHub.