Перейти до вмісту

Модуль 1.1: Інфраструктура як код

Складність: [СЕРЕДНЯ] — Базова концепція

Час на проходження: 30-35 хвилин

Передумови: Базові навички роботи з командним рядком


Що ви зможете зробити

Розділ «Що ви зможете зробити»

Після завершення цього модуля ви зможете:

  • Пояснити, що таке Інфраструктура як код (Infrastructure as Code, IaC) і чому вона замінила ручне налаштування серверів
  • Порівняти інструменти IaC (Terraform, Ansible, Pulumi) та пояснити, коли використовувати кожен з них
  • Написати просту декларативну конфігурацію та пояснити, чим вона відрізняється від скрипта
  • Визначити антипатерни IaC (clickops, імперативні скрипти для декларативних задач, дрейф конфігурації)

У 2012 році Knight Capital Group втратила 460 мільйонів доларів лише за 45 хвилин. Чому? Технічний спеціаліст вручну розгорнув нове програмне забезпечення на 7 з 8 серверів, забувши про восьмий. Ця невідповідність призвела до того, що система почала агресивно купувати дорого і продавати дешево. Одна помилка при ручному налаштуванні знищила багатомільярдну компанію.

До появи Інфраструктури як код (IaC) налаштування серверів було ручним процесом, схильним до помилок, який неможливо було точно відтворити. “На моїй машині працює” було типовим виправданням. IaC змінив усе: інфраструктура стала придатною для версіонування, тестування та повторення. Розуміння IaC є критично важливим, оскільки сам Kubernetes є системою IaC.

Зупиніться та подумайте: Як ваша нинішня організація відстежує зміни в інфраструктурі? Якби ваш основний дата-центр зник сьогодні, чи змогли б ви відновити його з репозиторію, чи покладалися б на чиюсь пам’ять?


Уявіть собі: 2005 рік. Вам потрібно налаштувати вебсервер.

Ручний процес:
1. Замовлення фізичного сервера (2-4 тижні)
2. Очікування, поки дата-центр встановить його в стійку (1 тиждень)
3. Підключення через SSH та встановлення пакетів
4. Налаштування шляхом редагування файлів
5. Надія, що ви пам'ятаєте, що саме зробили
6. Молитва, щоб нічого не зламалося
Документація: "Запитайте Дейва, це він налаштовував"

Проблеми:

  • Немає записів про те, що було зроблено
  • Неможливо відтворити налаштування
  • Різні “ідентичні” сервери поводяться по-різному
  • Дейв іде у відпустку — все ламається

Інфраструктура як код

Розділ «Інфраструктура як код»

IaC означає опис інфраструктури у файлах, які можна версіонувати, поширювати та виконувати.

┌─────────────────────────────────────────────────────────────┐
│ ІНФРАСТРУКТУРА ЯК КОД │
├─────────────────────────────────────────────────────────────┤
│ │
│ Традиційно: │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Людина │ ───► │ Консоль │ ───► │ Сервер │ │
│ │ │ │ (GUI) │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ З IaC: │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Код │ ───► │Інструмент│───► │ Сервер │ │
│ │ (файли) │ │(Terraform)│ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────┐ │
│ │ Git │ Контроль версій, можливість огляду, повторення │
│ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

1. Декларативний чи імперативний

Розділ «1. Декларативний чи імперативний»
Імперативний (Як):
"Встановити nginx, потім відредагувати /etc/nginx/nginx.conf,
потім перезапустити nginx"
Декларативний (Що):
"Я хочу, щоб nginx працював з цією конфігурацією"

Декларативний підхід є кращим — ви описуєте бажаний стан, а інструмент сам визначає, як його досягти.

Виконання одного і того ж коду кілька разів дає однаковий результат:

Terminal window
# Запуск цього 10 разів створить 10 серверів (ПОГАНО)
create_server web-1
# Запуск цього 10 разів гарантує, що існує 1 сервер (ДОБРЕ)
ensure_server_exists web-1

Зупиніться та подумайте: Якщо ви запустите імперативний bash-скрипт, який двічі створює користувача, він, швидше за все, видасть фатальну помилку вдруге, бо користувач уже існує. Що зробить ідемпотентна декларативна система?

Terminal window
git log --oneline infrastructure/
abc123 Add production database replica
def456 Increase web server count to 5
ghi789 Initial infrastructure setup
# "Хто змінив прод?" — Просто перевірте git blame

Ландшафт інструментів IaC

Розділ «Ландшафт інструментів IaC»
┌─────────────────────────────────────────────────────────────┐
│ КАТЕГОРІЇ ІНСТРУМЕНТІВ IaC │
├─────────────────────────────────────────────────────────────┤
│ │
│ PROVISIONING (Створення інфраструктури) │
│ ├── Terraform (хмаро-незалежний, найпопулярніший) │
│ ├── Pulumi (реальні мови програмування) │
│ ├── CloudFormation (тільки AWS) │
│ └── ARM Templates (тільки Azure) │
│ │
│ CONFIGURATION (Налаштування існуючих машин) │
│ ├── Ansible (без агентів, на базі SSH) │
│ ├── Chef (Ruby DSL, на базі агентів) │
│ ├── Puppet (на базі агентів, корпоративний) │
│ └── Salt (на базі Python) │
│ │
│ KUBERNETES-NATIVE (Створення та налаштування K8s) │
│ ├── Helm (менеджер пакетів для K8s) │
│ ├── Kustomize (кастомізація на базі патчів) │
│ └── kubectl apply (пряме застосування YAML) │
│ │
└─────────────────────────────────────────────────────────────┘

Terraform: Галузевий стандарт

Розділ «Terraform: Галузевий стандарт»

Terraform від HashiCorp є найпоширенішим інструментом IaC:

# main.tf - Конфігурація Terraform
# Визначення провайдера (де створювати ресурси)
provider "aws" {
region = "us-west-2"
}
# Визначення ресурсу
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "web-server"
Environment = "production"
}
}
# Визначення виводу
output "public_ip" {
value = aws_instance.web.public_ip
}
Terminal window
# Робочий процес Terraform
terraform init # Завантаження провайдерів
terraform plan # Попередній перегляд змін
terraform apply # Створення інфраструктури
terraform destroy # Повне видалення
ФункціяTerraformCloudFormation
Підтримка хмарБудь-яка хмараТільки AWS
Управління станомВбудованеКерується AWS
СинтаксисHCL (читабельний)JSON/YAML (багатослівний)
Складність навчанняСередняСпецифічна для AWS
СпільнотаВеличезнаОбмежена AWS

Ansible: Налаштування стало простішим

Розділ «Ansible: Налаштування стало простішим»

Ansible використовує YAML “playbooks” для налаштування машин:

# playbook.yml - Ansible playbook
---
- name: Configure web server
hosts: webservers
become: yes # Запуск від імені root
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Copy configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Ensure nginx is running
service:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
Terminal window
# Запуск плейбука
ansible-playbook -i inventory.ini playbook.yml

Ключова перевага: Без агентів. Потрібен лише доступ через SSH.


Kubernetes — ЦЕ і є Інфраструктура як код:

# deployment.yaml - Бажаний стан
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25
Terminal window
# Застосувати бажаний стан
kubectl apply -f deployment.yaml
# Kubernetes узгоджує фактичний стан із бажаним
# Це IaC в дії!

Зв’язок: Kubernetes використовує ті самі декларативні та ідемпотентні принципи, що й Terraform та Ansible.


Компроміси: Ціна IaC

Розділ «Компроміси: Ціна IaC»

Хоча IaC є необхідним для сучасної інженерії, він має певні компроміси:

  • Швидкість чи структура: Налаштування через хмарну консоль (ClickOps) значно швидше для короткого разового експерименту. IaC вимагає написання коду, планування та застосування, що створює додаткові витрати часу для простого завдання.
  • Поріг входження: Команди не можуть просто створювати сервери; вони повинні вивчити доменно-специфічні мови (наприклад, HCL для Terraform) та зрозуміти принципи управління станом (state management).
  • Складність управління станом: Інструменти на кшталт Terraform зберігають стан середовища у файлі. Безпечне керування цим файлом стану (блокування для запобігання одночасним запускам, шифрування для приховування секретів) стає новим операційним завданням.

Найкращі практики IaC

Розділ «Найкращі практики IaC»
Terminal window
infrastructure/
├── terraform/
├── main.tf
├── variables.tf
└── outputs.tf
├── kubernetes/
├── deployments/
└── services/
└── ansible/
└── playbooks/

2. Використовуйте модулі та компоненти повторного використання

Розділ «2. Використовуйте модулі та компоненти повторного використання»
# Не повторюйтеся
module "web_server" {
source = "./modules/ec2-instance"
name = "web-1"
instance_type = "t2.micro"
}
module "api_server" {
source = "./modules/ec2-instance"
name = "api-1"
instance_type = "t2.small"
}

3. Розділяйте середовища

Розділ «3. Розділяйте середовища»
Terminal window
environments/
├── dev/
└── main.tf # Маленькі інстанси, одна репліка
├── staging/
└── main.tf # Середні інстанси, тестування
└── prod/
└── main.tf # Великі інстанси, висока доступність

4. Ніколи не редагуйте вручну

Розділ «4. Ніколи не редагуйте вручну»
Золоте правило: якщо цього немає в коді, воно не існує.
Ручні зміни = дрейф конфігурації = баги о 3 годині ночі

┌─────────────────────────────────────────────────────────────┐
│ РОБОЧИЙ ПРОЦЕС IaC │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Написання ──► 2. Огляд ──► 3. Тестування │
│ коду (PR/MR) (Plan) │
│ │ │ │
│ │ ▼ │
│ 6. Моніторинг ◄── 5. Застосування ◄── 4. Затвердження │
│ стану змін (Merge) │
│ │
│ Усі зміни проходять через огляд коду │
│ Усі зміни можна перевірити (аудит) │
│ Усі зміни можна скасувати │
│ │
└─────────────────────────────────────────────────────────────┘

  • NASA використовує Terraform для управління своєю хмарною інфраструктурою. Якщо це достатньо добре для космосу, це достатньо добре і для вашого стартапу.
  • Назва Ansible походить з науково-фантастичних романів Урсули Ле Гуїн, де “ansible” — це пристрій для миттєвого зв’язку крізь космос.
  • “Худоба, а не домашні тварини” (Cattle, not pets) — це принцип IaC. Ставтеся до серверів як до худоби (замінні, пронумеровані), а не як до домашніх тварин (з іменами, незамінні). Ви повинні мати можливість без хвилювань видалити та відтворити будь-який сервер.
  • “Дрейф конфігурації” (Configuration Drift) спочатку був терміном системного адміністрування, що описував явище, коли сервери в кластері з часом стають дедалі менш схожими через нерегулярні, недокументовані ручні оновлення.

ПомилкаЧому це шкодитьРішення
Ручні зміни після деплою IaCДрейф конфігураціїПовторний деплой з коду
Невикористання контролю версійНемає історії змін, неможливо відкотитисяВикористовуйте Git для всього
Хардкодинг секретівЗагроза безпеціВикористовуйте менеджери секретів
Монолітні конфігураціїВажко підтримуватиВикористовуйте модулі
Відсутність бекапу стануВтрата даних про інфраструктуруДистанційне зберігання стану
Відсутність тестів IaC в CI перед застосуваннямПомилка в синтаксисі зупинить продВикористовуйте лінтери та plan в CI/CD
Ігнорування виводу planВипадкове видалення ресурсівЗавжди читайте diff перед затвердженням
Специфічний для середовища хардкодингКод не можна використати для staging/prodВикористовуйте змінні для відмінностей середовищ

Практична вправа: IaC за допомогою kubectl

Розділ «Практична вправа: IaC за допомогою kubectl»

Перед тим, як перейти до практики, розглянемо приклад IaC в Kubernetes.

Мета: Створити декларативну конфігурацію для простого Pod.

Крок 1: Код (Бажаний стан)

apiVersion: v1
kind: Pod
metadata:
name: my-web-pod
spec:
containers:
- name: nginx
image: nginx:alpine

Крок 2: Дія (Apply) Замість запуску kubectl run my-web-pod --image=nginx:alpine (імперативно), ми застосовуємо файл (декларативно):

Terminal window
kubectl apply -f pod.yaml

Крок 3: Узгодження (Ідемпотентність) Якщо ми знову запустимо kubectl apply -f pod.yaml, Kubernetes порівняє бажаний стан (наш файл) із фактичним станом, що працює в кластері. Оскільки вони точно збігаються, він нічого не робитиме.


Завдання: Відчути принципи IaC на прикладі ресурсів Kubernetes.

Крок 1. Створити Deployment декларативно

Terminal window
cat << 'EOF' > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: iac-demo
spec:
replicas: 2
selector:
matchLabels:
app: iac-demo
template:
metadata:
labels:
app: iac-demo
spec:
containers:
- name: nginx
image: nginx:1.25
EOF
kubectl apply -f deployment.yaml

Крок 2. Перевірити ідемпотентність та внесення змін

Terminal window
# 1. Застосувати знову (ідемпотентність)
kubectl apply -f deployment.yaml
# Зверніть увагу, вивід скаже "deployment.apps/iac-demo unchanged"
# 2. Змінити код
sed -i '' 's/replicas: 2/replicas: 4/' deployment.yaml
# 3. Застосувати зміни
kubectl apply -f deployment.yaml
# 4. Перевірити зміни
kubectl get deployment iac-demo
# Тепер показує 4 репліки

Крок 3. Написати з нуля Тепер, не копіюючи зверху, напишіть новий файл з назвою config.yaml, який створює Kubernetes ConfigMap з назвою app-settings та ключем theme, встановленим у значення "dark". Потім застосуйте його декларативно.

Рішення для кроку 3
  1. Створення декларативного файлу:
Terminal window
cat << 'EOF' > config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-settings
data:
theme: "dark"
EOF
  1. Застосування з використанням принципів IaC:
Terminal window
kubectl apply -f config.yaml
  1. Очищення ресурсів вправи:
Terminal window
kubectl delete -f deployment.yaml
kubectl delete -f config.yaml
rm deployment.yaml config.yaml

Контрольні запитання

Розділ «Контрольні запитання»
  1. Ви запускаєте скрипт деплою критичної бази даних. Конвеєр (pipeline) ламається на пів дорозі. Ви запускаєте його знову. Замість створення дубліката бази даних, інструмент розпізнає першу і просто завершує налаштування. Який принцип тут працює?

    Відповідь Це демонструє **ідемпотентність**. Виконання ідемпотентної операції кілька разів дає той самий ефект, що й одноразове виконання. Інструмент порівнює поточний стан із бажаним і вносить лише необхідні зміни, а не сліпо виконує команди. Це запобігає помилкам на кшталт створення дублікатів ресурсів.
  2. Вашій команді потрібно запустити 50 інстансів AWS EC2, налаштувати VPC та встановити балансувальники навантаження. Після запуску віртуальних машин на них потрібно виконати складні налаштування користувачів на рівні ОС та встановити специфічні бінарні файли додатків. Яка комбінація інструментів буде найбільш доречною?

    Відповідь Використання **Terraform** для створення інфраструктури (provisioning) та **Ansible** для її налаштування (configuration) буде найбільш доречним підходом. Terraform чудово справляється з декларативним створенням та керуванням хмарними ресурсами (VPC, інстанси EC2). Ansible найкраще підходить для налаштування операційних систем та програмного забезпечення на цих інстансах після їх створення. Їх поєднання дозволяє використовувати сильні сторони обох інструментів.
  3. Молодший інженер пише bash-скрипт з 15 операторами if/else, щоб перевірити, чи встановлено Nginx, встановити його, якщо він відсутній, а потім запустити сервіс, якщо він зупинений. Ви пропонуєте замінити його 5-рядковим YAML-файлом Kubernetes. Чому підхід з YAML є фундаментально іншим та безпечнішим?

    Відповідь Bash-скрипт є **імперативним** — він диктує покрокові інструкції ("як" це зробити). YAML-файл Kubernetes є **декларативним** — він описує бажаний кінцевий стан ("що" має бути). Декларативні підходи безпечніші, оскільки вони покладаються на контролер (як Kubernetes), який постійно узгоджує фактичний стан із бажаним. Це усуває потребу в крихкій логіці `if/else` і автоматично обробляє неочікувані початкові умови.
  4. Під час інциденту інженер підключається через SSH до прод-сервера і вручну редагує конфігураційний файл, щоб збільшити значення тайм-ауту. Проблему вирішено. Через два тижні команда деплоїть нову версію додатка через свій IaC-конвеєр, і проблема з тайм-аутом негайно повертається. Що сталося?

    Відповідь Це класичний приклад **дрейфу конфігурації** (configuration drift). Ручна зміна, зроблена під час інциденту, не була зафіксована в репозиторії IaC. Коли через два тижні запустився конвеєр IaC, він застосував конфігурацію, визначену в системі контролю версій. Це фактично перезаписало ручне виправлення і повернуло проблему з тайм-аутом, доводячи, чому всі зміни повинні проходити через код.
  5. О 3 годині ночі виникає критичний баг на поді. Черговий інженер виявляє, що рядок підключення до бази даних був змінений на сервері додатків. Ніхто не знає, хто і коли його змінив. Як Інфраструктура як код вирішує цю проблему?

    Відповідь IaC покладається на **контроль версій** (наприклад, Git) як на єдине джерело істини. Якщо всі зміни вносяться через IaC, ручне редагування на сервері або неможливе, або автоматично скасовується. Інженер міг би просто подивитися на історію Git (наприклад, `git log` або `git blame`), щоб побачити, хто саме змінив рядок підключення. Крім того, вони могли б побачити, коли це було зроблено, і переглянути pull request, який затвердив цю зміну, отримавши повний журнал аудиту.
  6. Ваша організація вимагає, щоб усі зміни в інфраструктурі були підзвітними, зворотними та перевірялися колегами перед застосуванням. Розробник скаржиться, що Kubernetes робить це неможливим, бо йому доводиться цілий день використовувати команди kubectl run. Як ви виправите це непорозуміння?

    Відповідь Розробник використовує Kubernetes імперативно через CLI, що порушує принципи IaC. Kubernetes за своєю суттю є системою IaC, якщо її використовувати правильно. Визначаючи ресурси в YAML-файлах і зберігаючи їх у Git, організація може забезпечити огляд змін. Застосування їх через CI/CD конвеєр гарантує, що Kubernetes повністю підтримує підзвітні, зворотні та рецензовані зміни інфраструктури.
  7. Ви застосовуєте YAML-файл Deployment до кластера, створюючи 3 репліки вебдодатка. Через десять хвилин ви випадково натискаєте “Вгору” та “Enter” у терміналі, знову запускаючи ту саму команду kubectl apply -f deployment.yaml. Що зробить кластер?

    Відповідь Кластер не зробить **нічого**. Оскільки команда `apply` є ідемпотентною та декларативною, Kubernetes порівнює бажаний стан у YAML-файлі з поточним станом у кластері. Бачачи, що 3 репліки вебдодатка вже працюють з точно такою конфігурацією, він не вносить жодних змін. Він просто повідомить, що ресурс не змінився.

Інфраструктура як код трансформує управління інфраструктурою:

Основні принципи:

  • Декларативність замість імперативності
  • Ідемпотентні операції
  • Контроль версій
  • Зміни, що підлягають огляду (review)

Ключові інструменти:

  • Terraform: Створення хмарних ресурсів
  • Ansible: Налаштування машин
  • Kubernetes: Оркестрація контейнерів (IaC вбудовано)

Чому це важливо:

  • Відтворюваність середовищ
  • Журнал аудиту для всіх змін
  • Аварійне відновлення (відбудова з коду)
  • Співпраця через огляд коду

Зв’язок з Kubernetes: Усе, що ви робите в Kubernetes, відповідає принципам IaC. YAML-файли — це ваш код інфраструктури.


Модуль 1.2: GitOps — використання Git як єдиного джерела істини для інфраструктури.