Сервер живёт три года. За это время его руками обновляли пакеты, меняли конфиги, ставили временные фиксы «на пять минут». Нет ни одного инженера, который точно знает текущее состояние этой машины. 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 подхода.







