Поради з Terraform: Масштабоване та надійне Infrastructure-as-Code — Частина 2

Це друга частина серії про Terraform, де надано поради та найкращі практики для ефективного керування хмарною інфраструктурою. В OTTO IT потужний відкритий інструмент від Hashicorp використовується для ефективної оркестрації, автоматизації та управління хмарною інфраструктурою через Infrastructure-as-Code (IaC). Після того, як у першій частині ми розглянули основні етапи робочого процесу Terraform, життєвий цикл Terraform та модулі Terraform, ця частина представить конкретні техніки для оптимізації структури директорій та організації ресурсів, а також для роботи з вхідними та вихідними значеннями.

Чітка структура директорій та організація ресурсів 📁

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

🔑 Ключові питання, які слід поставити в цьому контексті:

  • Наскільки складним є мій сервіс?
  • Скільки ресурсів і провайдерів потрібно?
  • Як часто змінюватиметься інфраструктура (щомісяця, щотижня, щодня, після кожного коміту)?
  • Як найкраще і стійко згрупувати ресурси (за середовищем, регіоном чи проєктом)?

Однак слід бути обережним, оскільки спроби "передбачити майбутнє" занадто рано та «перемудрювання» можуть призвести до заплутаного та важко зрозумілого коду. Це стосується як традиційної розробки коду, так і Infrastructure-as-Code. Важливо зберігати структуру Terraform простотою та зрозумілістю, створюючи при цьому гнучку основу для майбутніх змін.

Як описано в першій частині серії про Terraform, API виклики для ресурсів здійснюються під час етапів “terraform plan” та “terraform apply”. Замість того, щоб визначати всю Infrastructure-as-Code в одному великому «монолітному» файлі стану, краще утримувати складність на низькому рівні та реалізовувати керовані файли стану. Файли стану повинні бути малими та компактними, щоб полегшити управління залежностями та прискорити розгортання. Ще одна перевага менших файлів стану — це спрощення тестування та перегляду.

Оскільки конфігурації Terraform змінюються з часом, важливо впроваджувати відповідні заходи структурування на ранньому етапі, щоб забезпечити гнучкість змін і зберегти довгострокову підтримуваність і масштабованість ресурсів. Нижче я наводжу приклад структури Terraform з модульним підходом, де головна гілка слугує «джерелом істини» для всіх середовищ. Однак важливо зазначити, що це лише приклад, і можливі й інші підходи та рішення.

pic

Приклад структури директорій Terraform з модульним підходом

У наведеному прикладі конфігураційні файли використовують спільну директорію, в якій перезапускаються компоненти як “модулі”. Цю директорію також можна реалізувати як окремий репозиторій, що дозволяє використовувати та повторно використовувати її різними додатками та командами.

Крім того, приклад включає директорію інфраструктури, яка слугує для початкового налаштування (наприклад, для відновлення після катастрофи) та для загальних хмарних середовищ, які не прив'язані до конкретного середовища (наприклад, для логування, секретного менеджера).

Організація коду Terraform у прикладі розподілена за середовищем. На перший погляд код може здатися дещо зайвим. Однак ця конфігурація має багато переваг, оскільки забезпечує слабке з'єднання. Ресурси можна керувати незалежно та налаштовувати більш детально, залежно від конкретного середовища. Наприклад, якщо потрібно видалити сервіс, залишаючи при цьому базу даних, це можна легко зробити через окремі файли стану та структури папок.
Аналогічно, якщо в робочому середовищі потрібно більше одиниць обробки, ніж у середовищі для розробки, це можна легко вирішити. Окрім поділу за середовищами розробки, може бути корисно також групувати ці компоненти за шарами інфраструктури (наприклад, мережа, база даних тощо).

Ось швидкий огляд файлів Terraform, що використовуються в прикладі, та їх вмісту:

  • main.tf — Викликає модулі, локальні змінні та джерела даних для створення всіх ресурсів
  • backend.tf — Визначає хмарний бакет, де зберігається віддалений стан
  • variables.tf — Містить декларації змінних, що використовуються в main.tf
  • outputs.tf — Містить вихідні значення ресурсів, створених в main.tf
  • versions.tf — Містить вимоги до версій Terraform та провайдерів

Інша порада — використовувати “terraform graph” та інструменти візуалізації для поточних конфігурацій Terraform, щоб швидко виявляти ділянки для покращення налаштувань.

👉 Підсумовуючи, Infrastructure-as-Code слід писати та підтримувати з тією ж ретельністю, що й код застосунків, дотримуючись найкращих практик і стандартів. Чітка структура директорій сприяє покращенню якості, підтримуваності та співпраці в команді розробників.

Вхідні та вихідні значення — Золото всередину, золото назовні 💎

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

  • При іменуванні ресурсів краще використовувати описові терміни, такі як “private” (приватний), “public” (публічний), “database” (база даних), уникаючи зайвої інформації (наприклад, не повторюйте тип ресурсу в його назві).
  • Використовуйте однину, малі літери, без написаних чисел (“2” замість “two/second”).
  • Розміщуйте аргументи, такі як “count” (лічильник) чи “foreach” (длякожного), на початку блоку ресурсу або джерела даних, а “tags” (теги), “dependson” (залежитьвід) та “lifecycle” (життєвий_циклі) — в кінці.
  • При використанні “count” (лічильник) чи “foreach” (длякожного) віддавайте перевагу булевим значенням замість інших виразів.
  • Використовуйте підкреслення (_) замість дефісів (-) для імен ресурсів, джерел даних, змінних та вихідних значень.
  • Використовуйте дефіси в усіх публічних випадках (імена DNS, екземпляри).
  • Завжди описуйте числові значення (розмір оперативної пам'яті чи диску) з відповідними одиницями (“ramsizegb” (розмірпам'ятів_ГБ)).

Вхідні змінні

Вхідні змінні в Terraform — це потужний інструмент для створення гнучких та багаторазових конфігурацій. Однак їхнє використання може призвести до збільшення складності коду, тому їх слід застосовувати лише за необхідності. Корисно запитати себе, чи дійсно значення потенційної змінної має бути змінним перед її впровадженням. Також подумайте, чи є для цього конкретний варіант використання, чи, можливо, використання локальних змінних буде розумнішим підходом.

  • Зберігайте змінні у файлі variables.tf.
  • Розділяйте обов'язкові змінні від необов'язкових у файлі для кращої читабельності коду.
  • Використовуйте аргумент “description” (опис) для чіткого, контекстного опису змінної (наприклад, чому ця змінна існує? Яке значення очікується?).
  • Використовуйте блок перевірки (validation block) для визначення правил і повідомлень про помилки за порушення правил (можна навіть використовувати регулярні вирази в полі “conditions” для забезпечення дотримання правил іменування/префіксів).
  • Надавайте “default” (за замовчуванням) для необов'язкових змінних.
  • Вказуйте “type” (тип).
  • Віддавайте перевагу простим типам (string (рядок), list(...) (список), map(...) (мапа), any (будь-який)) замість специфічних типів (objects (об'єкти)).
  • Специфічні типи можуть бути корисними, якщо вони мають однакові елементи (мапа, де всі елементи типу “String” (рядок), може бути легше перетворена). Використовуйте “tomap” замість “map”, щоб уникнути створення об'єкта.
  • Використовуйте тип “any” (будь-який), якщо хочете відключити перевірку типів за певною глибиною або підтримувати кілька типів.
  • Для булевих значень використовуйте позитивні назви, такі як “enableexternalaccess” (дозволитизовнішнійдоступ).

Вихідні змінні

Використання вихідних значень може мати багато переваг.
Дитячі модулі можуть використовувати вихідні значення (outputs) для передачі підмножини ресурсів до батьківського модуля. Кореневий модуль може використовувати вихідні значення для виведення значень, наприклад, через CLI. Для ясності, кореневий або батьківський модуль — це модуль, який викликає інші модулі (дитячі модулі) для включення їхніх ресурсів в конфігурацію інфраструктури.

Крім того, вихідні значення можуть використовуватися іншими конфігураціями інфраструктури після розгортання (у випадку віддаленого стану). Для полегшення використання модуля користувачем корисно спроектувати вихідні значення таким чином, щоб було чітко вказано, які типи значень та атрибути вони надають.

  • Зберігайте вихідні значення у файлі outputs.tf.
  • Використовуйте таку конвенцію іменування: (наприклад, для ресурсу “awsvpcendpoint” “test” -> testvpcendpoint_id).
  • Використовуйте множину в іменах, коли значення, що повертається, є списком.
  • Надавайте поля “description” (опис) та “type” (тип).
  • Уникайте поля “sensitive” (чутливий), щоб підвищити безпеку та запобігти несанкціонованим витокам даних.
  • Використовуйте “try” замість “element(concat(…))” для кращої читабельності, більш надійної конфігурації та запобігання помилкам.

Основні висновки 🔑

  1. Довгострокове планування та бачення: Регулярно переглядайте інфраструктуру та адаптуйте її до майбутніх вимог. Розглядайте, як ресурси взаємопов'язані та які існують залежності. Мінімізуйте складність API викликів.
  2. Модульний дизайн і повторне використання: Інфраструктуру слід розділяти на менші, багаторазові модулі. Компактні файли стану допомагають покращити підтримуваність та масштабованість.
  3. Структура директорій і організація: Встановлення послідовної та логічної структури для файлів Terraform робить навігацію та керування простішими. Важливі питання: Наскільки складним є мій сервіс? Скільки ресурсів і провайдерів потрібно? Де можна зробити зручні поділи (проект, регіон, середовище)?
  4. Вхідні та вихідні значення: Використання змінних і вихідних значень корисне для створення гнучких і адаптивних конфігурацій. Найкращі практики спільноти Terraform надають цінну підтримку.

На завершення, важливо враховувати специфічні вимоги та обмеження кожного проекту. Може бути доцільно відступити від рекомендацій і розробити власні рішення.

“Трюк полягає в тому, щоб зважити переваги та недоліки різних підходів і знайти найкраще рішення для кожної ситуації. Як часто буває в ІТ, немає одного правильного способу, а є багато різних способів.”

Наступна частина нашої серії про Terraform буде присвячена тестуванню Infrastructure-as-Code. Слідкуйте за оновленнями! 😉

👉 Читайте цю та інші цікаві статті на нашому Tech Blog.

pic

Автор Ніна

Перекладено з: Terraform Tips: Scalable and Reliable Infrastructure-as-Code — Part 2

Leave a Reply

Your email address will not be published. Required fields are marked *