Сервер живе три роки. За цей час його руками оновлювали пакети, змінювали конфіги, ставили тимчасові фікси «на п'ять хвилин». Немає жодного інженера, який точно знає поточний стан цієї машини. ansible-playbook падає на нестандартних значеннях, які хтось поправив напряму. Такий сервер називають snowflake server — унікальний і крихкий. Типова ситуація: після чергового puppet apply половина продакшену впала, тому що на одному інстансі вручну переписали nginx.conf. Відкотити — нікуди, кожен сервер індивідуальний. Доводиться розбиратися з кожним окремо, втрачаючи години даунтайму. Наша команда DevOps-інженерів з 10-річним досвідом щодня стикається з такими проблемами та допомагає компаніям перейти на надійну модель immutable infrastructure.
Immutable infrastructure — це принципова відмова від оновлення серверів. Замість apt-get upgrade або ansible — створення нового образу, запуск нових інстансів, видалення старих. Сервер не змінюється ніколи після деплою. Такий підхід гарантує ідентичність середовищ і спрощує відкати.
Чому immutable infrastructure вигідніше?
Порівняємо старий підхід і новий у таблиці:
| Критерій | Snowflake (ручне оновлення) | Immutable (заміна сервера) |
|---|---|---|
| Час відновлення після збою | Години — потрібно з'ясовувати, що змінювали | 5-7 хвилин — деплой попереднього AMI |
| Дрейф конфігурації | Неминучий, кожен сервер унікальний | Відсутній, всі сервери з одного образу |
| Безпека | Ризик незадокументованих змін | Повний аудит через образи та Git |
| Витрати на підтримку | Високі — ручні правки та runbook | Низькі — автоматизація та самовідновлення |
Phoenix Server паттерн
Концепція проста: кожен сервер — тимчасовий. Як птах Фенікс, він згорає та з'являється новий. Конфігурація та код додатку запікаються в образ. Дані зберігаються поза сервером — у S3, RDS, EFS.
Для VM-інфраструктури це реалізується через Packer + Terraform:
# packer/api-server.pkr.hcl
source "amazon-ebs" "api" {
ami_name = "api-server-${var.version}-${formatdate("YYYYMMDD", timestamp())}"
instance_type = "t3.medium"
region = "eu-west-1"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
}
}
build {
sources = ["source.amazon-ebs.api"]
provisioner "ansible" {
playbook_file = "ansible/api-server.yml"
extra_arguments = ["--extra-vars", "app_version=${var.version}"]
}
post-processor "manifest" {
output = "packer-manifest.json"
}
}Packer збирає AMI. Ansible provisioner запікає додаток прямо в образ. Після збірки — packer-manifest.json містить ID нового AMI.
Terraform: заміна інстансів через Launch Template
resource "aws_launch_template" "api" {
name_prefix = "api-server-"
image_id = var.ami_id # ID з packer-manifest.json
instance_type = "t3.medium"
tag_specifications {
resource_type = "instance"
tags = {
Name = "api-server"
Version = var.app_version
}
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_autoscaling_group" "api" {
name = "api-${var.app_version}"
desired_capacity = 3
min_size = 2
max_size = 6
vpc_zone_identifier = var.private_subnet_ids
launch_template {
id = aws_launch_template.api.id
version = "$Latest"
}
instance_refresh {
strategy = "Rolling"
preferences {
min_healthy_percentage = 50
instance_warmup = 120
}
}
lifecycle {
create_before_destroy = true
}
}instance_refresh — вбудований механізм AWS для заміни інстансів без даунтайму. При зміні image_id у Launch Template — ASG поступово замінює старі інстанси новими, підтримуючи мінімум 50% healthy.
CI/CD пайплайн: від коміту до нового образу
---
# .github/workflows/deploy.yml
jobs:
build-ami:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build AMI with Packer
run: |
packer init packer/
packer build \
-var "version=${{ github.sha }}" \
packer/api-server.pkr.hcl
- name: Extract AMI ID
id: ami
run: |
AMI_ID=$(jq -r '.builds[-1].artifact_id' packer-manifest.json | cut -d: -f2)
echo "ami_id=$AMI_ID" >> $GITHUB_OUTPUT
deploy:
needs: build-ami
steps:
- name: Update Terraform
run: |
terraform apply \
-var "ami_id=${{ needs.build-ami.outputs.ami_id }}" \
-var "app_version=${{ github.sha }}" \
-auto-approve
---
Кожен коміт у main → новий AMI → оновлення ASG. Жодного ssh у продакшн сервери. Жодних ansible-playbook проти живих інстансів.
Як впровадити immutable infrastructure: покроковий план
- Аудит поточної інфраструктури: виявити всі компоненти, що зберігають state на диску, і спланувати їх міграцію.
- Виніс даних: перенести бази в RDS, файли в S3, сесії в Redis. Налаштувати екстерналізацію логів.
- Створення Packer-шаблонів: для кожного типу сервера — окремий шаблон з Ansible provisioner, що запікає додаток та залежності.
- Налаштування Terraform-модулів: Launch Template з image_id з Packer, Auto Scaling Group з instance refresh.
- Збірка CI/CD пайплайну: GitHub Actions або GitLab CI: commit → build AMI → update Terraform → вивід у прод.
- Тестування та rollback: перевірити заміну інстансів, виконати відкат на попередній AMI.
- Навчання команди: передача документації та runbook.
Критично: що не повинно бути на сервері
Immutable infrastructure працює лише якщо дотримуються кілька правил:
Всі дані поза сервером. База даних — у RDS. Завантажені файли — у S3. Сесії — у Redis. Логи — у CloudWatch Logs або Loki. Якщо дані зберігаються на диску інстанса, вони губляться при заміні.
Конфігурація через environment variables. Жодних конфіг файлів, які створюються при деплої. Тільки змінні середовища з Secrets Manager або Parameter Store:
# user-data script для інстанса
export DB_URL=$(aws ssm get-parameter --name /api/db-url --with-decryption --query Value --output text)
export SECRET_KEY=$(aws secretsmanager get-secret-value --secret-id api/secret-key --query SecretString --output text)
systemctl start apiЗаборона SSH у продакшн. Якщо інженер може зайти та щось змінити руками — immutability порушена. SSM Session Manager замість прямого SSH, і лише для екстреної діагностики з повним аудит логом.
Rollback — це деплой попереднього AMI
# Відкочуємо на попередній AMI
terraform apply \
-var "ami_id=ami-0abcdef1234567890" \
-var "app_version=previous-sha" \
-auto-approve5-7 хвилин на заміну інстансів. Передбачувано. Без сюрпризів у стилі «відкат пройшов, але конфіг інший». Immutable infrastructure швидше в 10 разів за швидкістю відновлення порівняно з традиційним підходом — емпіричні дані з наших проектів.
Що робити з legacy, які зберігають state на диску?
Найскладніше при переході — legacy компоненти, які зберігають state на диску: додатки з file-based sessions, cron jobs що пишуть у /tmp, додатки з хардкоженими шляхами до конфігів. Це потрібно рефакторити до переходу на immutable. Ми допомагаємо провести аудит, виявити такі місця та спланувати міграцію. На це йде більше часу, ніж на саме налаштування Packer + Terraform, але без цього immutable не працює.
Що входить у роботу під ключ
Ми беремо на себе весь цикл: від аудиту до передачі документації. У результаті ви отримуєте:
- Packer-шаблони для збірки образів усіх компонентів
- Terraform-модулі з Auto Scaling та instance refresh
- CI/CD пайплайн (GitHub Actions / GitLab CI) з автоматичним деплоєм та відкатом
- Runbook з експлуатації та відновлення
- Навчання вашої команди роботі з новою інфраструктурою
- Гарантію стабільної роботи протягом 30 днів після впровадження
Приклад типового плану робіт
| Етап | Термін |
|---|---|
| Аудит: що зберігається на сервері, що потрібно виносити | 1 день |
| Packer шаблон + Ansible provisioner | 1.5 дня |
| Terraform ASG з instance_refresh | 1 день |
| CI/CD пайплайн (build AMI + deploy) | 0.5 дня |
| Тест rollback + runbook | 0.5 дня |
Вартість розраховується індивідуально після аудиту інфраструктури. Оцінимо ваш проект — напишіть нам, щоб отримати консультацію та попередній план.
Зв'яжіться з нами для аудиту вашої інфраструктури та замовте впровадження immutable підходу.







