Среда Terraform - как сделать это СУХОЕ

Мы активно используем Terraform для выделения ресурсов облака AWS. Наша базовая терраформная структура выглядит так:

├─ modules
├── x
├── y
├─ environments
├── dev
│   ├── main.tf
│   ├── output.tf
│   └── variables.tf
└── uat
│   ├── main.tf
│   ├── output.tf
│   └── variables.tf
└── prod
    ├── main.tf
    ├── output.tf
    └── variables.tf

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

В настоящее время наша основная проблема связана с файлами output.tf - каждый раз, когда мы расширяем существующий модуль или добавляем новый модуль, нам нужно настроить для него конфигурацию среды (это ожидается), но нам все равно нужно скопировать / вставить требуемый части в output.tf для вывода результатов инициализации (например, IP-адресов, AWS ARN и т. д.).

Есть ли способ избавиться от дублированных файлов output.tf? Можем ли мы просто определить желаемые выходы в самих модулях и видеть все определенные выходы всякий раз, когда мы запускаем terraform для конкретной среды?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
0
2 512
3

Ответы 3

Один из способов решить эту проблему - создать среду base, а затем создать символическую ссылку на общие элементы, например:

├─ modules
├── x
├── y
├─ environments
├── base
│   ├── output.tf
│   └── variables.tf
├── dev
│   ├── main.tf
│   ├── output.tf -> ../base/output.tf
│   └── variables.tf -> ../base/variables.tf
├── uat
│   ├── main.tf
│   ├── output.tf -> ../base/output.tf
│   └── variables.tf -> ../base/variables.tf
├── super_custom
│   ├── main.tf
│   ├── output.tf # not symlinked
│   └── variables.tf # not symlinked
└── prod
    ├── main.tf
    ├── output.tf -> ../base/output.tf
    └── variables.tf -> ../base/variables.tf

Этот подход действительно работает только в том случае, если ваши файлы output.tf и variables.tf одинаковы для каждой среды, и хотя у вас могут быть варианты без символических ссылок (например, super_custom выше), это может сбивать с толку, поскольку не сразу очевидно, какие среды являются пользовательскими, а какие нет. т. YMMV. Я стараюсь, чтобы изменения между средами были ограничены файлом .tfvars для каждой среды.

Стоит прочитать Отличный пост Charity Major о файлах tfstate, который поставил меня на этот путь.

спасибо за Ваш ответ. Я думал о символических ссылках, но не очень-то интересовался этим подходом ... если это единственный способ, я все же приму его. Спасибо за ссылку на этот пост, он действительно информативный, отличное прочтение!

Kristof Jozsa 21.03.2018 11:02

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

spikeheap 21.03.2018 17:51

Если ваши среды dev, uat и prod имеют одинаковую форму, но разные свойства, вы можете использовать рабочие места для разделения состояния среды вместе с отдельными файлами *.tfvars для указания различных конфигураций.

Это могло выглядеть так:

├─ modules
│   ├── x
│   └── y
├── dev.tfvars
├── prod.tfvars
├── uat.tfvars
├── main.tf
├── outputs.tf
└── variables.tf

Вы можете создать новое рабочее пространство с помощью:

terraform workspace new uat

Тогда развертывание изменений становится:

terraform workspace select uat
terraform apply --var-file=uat.tfvars

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

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

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

Kristof Jozsa 22.03.2018 12:56

Кроме того, я считаю, что собственная домашняя страница Terraform перечисляет это как антипаттерн в разделе Best Practices, так что, по их мнению, это, вероятно, не лучший подход :(

Kristof Jozsa 22.03.2018 12:57

У вас есть ссылка на это? Рабочие области были разработаны для использования отдельно для каждой среды (terraform.io/docs/enterprise/guides/recommended-practices/…‌). Я согласен, что это звучит рискованно, если вы вводите команды вручную, но мы обошли это, заключив эти команды в один сценарий, так что вы всегда последовательны.

spikeheap 22.03.2018 17:51

Также потенциально актуальным является открытый запрос функции для автоматической загрузки файла .tfvars соответствующей рабочей области (github.com/hashicorp/terraform/issues/12845).

spikeheap 22.03.2018 17:54

да, см. terraform.io/docs/state/workspaces.html, параграф «Лучшие практики». Я бы также выделил эту часть: «Сами по себе рабочие области полезны для изоляции набора ресурсов для тестирования изменений во время разработки. Например, ветвь в VCS обычно ассоциируется с временным рабочим пространством, чтобы можно было разрабатывать новые функции, не затрагивая рабочее пространство по умолчанию.». Исходя из этого, я не думаю, что рабочие места лучше всего подходят для этой проблемы.

Kristof Jozsa 22.03.2018 20:26

Привет, @KristofJozsa, я думаю, что в этом разделе говорится, что рабочие области должен должны использоваться для этого класса проблем, однако, если у вас есть сложные различия в конфигурации, вам следует также использовать terraform_remote_state для инкапсуляции конфигурации в каждый модуль. Когда они говорят «Только рабочие пространства», они имеют в виду «Рабочие пространства полезны как единственный механизм изоляции для разработчиков», а не «Рабочие пространства полезны только для изоляции разработчиков».

spikeheap 26.03.2018 15:41

Мы создали и открыли исходный код Террагрунт, чтобы решить эту самую проблему. Одна из функций Terragrunt - возможность загрузки удаленных конфигураций Terraform. Идея состоит в том, что вы определяете код Terraform для своей инфраструктуры только один раз, в одном репо, например, modules:

└── modules
 ├── app
 │   └── main.tf
 ├── mysql
 │   └── main.tf
 └── vpc
     └── main.tf

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

variable "instance_count" {
  description = "How many servers to run"
}

variable "instance_type" {
  description = "What kind of servers to run (e.g. t2.large)"
}

В отдельном репо, называемом, например, live, вы определяете код для всех ваших сред, который теперь состоит только из одного файла .tfvars на компонент (например, app/terraform.tfvars, mysql/terraform.tfvars и т. д.). Это дает вам следующий макет файла:

└── live
    ├── prod
    │   ├── app
    │   │   └── terraform.tfvars
    │   ├── mysql
    │   │   └── terraform.tfvars
    │   └── vpc
    │       └── terraform.tfvars
    ├── qa
    │   ├── app
    │   │   └── terraform.tfvars
    │   ├── mysql
    │   │   └── terraform.tfvars
    │   └── vpc
    │       └── terraform.tfvars
    └── stage
        ├── app
        │   └── terraform.tfvars
        ├── mysql
        │   └── terraform.tfvars
        └── vpc
            └── terraform.tfvars

Обратите внимание, что ни в одной из папок нет конфигураций Terraform (файлов .tf). Вместо этого каждый файл .tfvars определяет блок terraform { ... }, который указывает, откуда загружать код Terraform, а также зависящие от среды значения для входных переменных в этом коде Terraform. Например, stage/app/terraform.tfvars может выглядеть так:

terragrunt = {
  terraform {
    source = "git::[email protected]:foo/modules.git//app?ref=v0.0.3"
  }
}

instance_count = 3
instance_type = "t2.micro"

А prod/app/terraform.tfvars может выглядеть так:

terragrunt = {
  terraform {
    source = "git::[email protected]:foo/modules.git//app?ref=v0.0.1"
  }
}

instance_count = 10
instance_type = "m2.large"

См. Документация Террагрунт для получения дополнительной информации.

Другие вопросы по теме