История создания методологии, философия и обзор всех двенадцати факторов
Методология, которая изменила способ построения веб-приложений в эпоху облаков.
В начале 2010-х годов команда Heroku — одной из первых PaaS-платформ — столкнулась с интересной проблемой. Они наблюдали за тысячами приложений, которые развёртывали их клиенты, и заметили закономерность: некоторые приложения легко масштабировались, были надёжными и простыми в поддержке, а другие постоянно вызывали проблемы.
Инженеры Heroku проанализировали успешные приложения и выделили общие паттерны, которые их объединяли. В 2011 году они опубликовали манифест 12-Factor App — набор из двенадцати принципов для построения SaaS-приложений, которые:
SaaS (Software as a Service) — это модель распространения ПО, при которой приложение работает на серверах поставщика и доступно через интернет. Примеры: Gmail, Slack, Zoom, Salesforce.
Ключевая особенность SaaS: вы не контролируете инфраструктуру. Ваше приложение работает на чужих серверах, в чужих контейнерах, на чужих операционных системах. 12-Factor App учит строить приложения, которые идеально работают в такой среде.
Вот краткий обзор каждого фактора. Детально мы разберём их в последующих темах.
Одна кодовая база в системе контроля версий, множество развёртываний
Всё приложение хранится в одном репозитории (Git). Из этого репозитория развёртываются все окружения: development, staging, production. Никаких разных веток для разных сред — один и тот же код, разная конфигурация.
# Правильно:
git checkout main
DEPLOY_ENV=prod ./deploy.sh
DEPLOY_ENV=staging ./deploy.sh
# Неправильно:
# - Отдельные репозитории для prod и staging
# - Ручное копирование файлов на сервер
Явное объявление и изоляция зависимостей
Все библиотеки, которые использует приложение, должны быть явно указаны в файле зависимостей. Никаких неявных зависимостей «это уже установлено на сервере».
# requirements.txt (Python)
requests==2.31.0
flask==3.0.0
psycopg2==2.9.9
# package.json (Node.js)
{
"dependencies": {
"express": "^4.18.0",
"pg": "^8.11.0"
}
}Храните конфигурацию в переменных окружения
Конфигурация (пароли БД, API-ключи, домены) не должна быть в коде. Используйте переменные окружения для передачи настроек.
# Неправильно:
DB_PASSWORD = 'super_secret_123'
# Правильно:
import os
DB_PASSWORD = os.environ['DB_PASSWORD']Обрабатывайте внешние сервисы как присоединённые ресурсы
Базы данных, кэш (Redis), очереди (RabbitMQ), SMTP-серверы — всё это backing services. Приложение не должно знать, где они находятся — только URL для подключения.
# Приложение получает URL из конфигурации:
DATABASE_URL = os.environ['DATABASE_URL']
# postgres://user:pass@db.example.com:5432/mydb
# При масштабировании просто меняется URL — код не трогаетсяСтрого разделяйте стадии сборки, релиза и запуска
# CI/CD пайплайн:
git push → [BUILD] → [RELEASE] → [RUN]
↓ ↓ ↓
артефакт +config процесс
Выполняйте приложение в виде stateless процессов
Процессы не хранят состояние между запросами. Сессии, данные, файлы — всё во внешних сервисах (БД, кэш, объектное хранилище).
# Неправильно: сессия в памяти процесса
user_sessions = {} # ❌ При перезапуске всё потеряется
# Правильно: сессия в Redis
import redis
r = redis.Redis()
r.set(f'session:{user_id}', data) # ✅Экспортируйте сервисы через привязку портов
Приложение само слушает порт, а не полагается на внешний веб-сервер (Apache, nginx). Веб-сервер может быть добавлен позже как reverse proxy.
# Flask приложение само слушает порт:
app.run(host='0.0.0.0', port=5000)
# Не требуется nginx/apache для запускаМасштабируйтесь через модель процессов
Горизонтальное масштабирование: запускайте больше процессов, а не увеличивайте мощность сервера.
# Kubernetes: увеличить количество реплик
kubectl scale deployment myapp --replicas=10
# Каждый процесс обрабатывает часть нагрузкиМаксимизируйте надёжность через быстрый запуск и корректное завершение
Процессы должны быстро запускаться (секунды) и корректно завершаться при получении сигнала (SIGTERM).
import signal
import sys
def graceful_shutdown(signum, frame):
# Завершить текущие запросы
# Закрыть соединения с БД
# Освободить ресурсы
sys.exit(0)
signal.signal(signal.SIGTERM, graceful_shutdown)Максимально приближайте development к production
Различия между средами должны быть минимальны: одинаковые версии ПО, одинаковые backing services, одинаковая конфигурация (кроме секретов).
# Docker обеспечивает паритет:
# Одинаковый контейнер запускается локально и в production
docker run myapp # Локально
docker run myapp # В productionРассматривайте логи как потоки событий
Приложение пишет логи в stdout/stderr, а среда выполнения собирает, агрегирует и хранит их.
import logging
logging.basicConfig(level=logging.INFO)
logging.info('User logged in') # Вывод в stdoutЗапускайте административные задачи как одноразовые процессы
Миграции БД, консольные команды, скрипты — всё это отдельные процессы, которые запускаются в том же окружении, что и приложение.
# Одноразовый процесс для миграции:
python manage.py migrate
# Консоль для отладки:
python manage.py shellОригинальная методология 2011 года не включала явные требования к телеметрии. Сегодня это обязательный элемент cloud-native приложений:
from prometheus_client import Counter, Histogram
REQUESTS = Counter('http_requests_total', 'Total HTTP requests')
LATENCY = Histogram('http_request_duration_seconds', 'HTTP request latency')# Состояние в памяти приложения
logged_in_users = set()
@app.route('/login')
def login():
logged_in_users.add(user_id) # ❌ При перезапуске потеряется# Секреты в коде
DATABASE_URL = 'postgres://admin:password123@prod-db:5432/app' # ❌# FTP, SCP, ручное копирование
scp app.py user@server:/var/www/ # ❌
ssh user@server "service apache restart"repo-prod/
repo-staging/
repo-dev/ # ❌ Должна быть одна кодовая база
| Преимущество | Описание |
|---|---|
| Быстрый деплой | Развёртывание за секунды, а не часы |
| Легкое масштабирование | kubectl scale — и у вас 100 экземпляров |
| Отказоустойчивость | Сбой одного процесса не влияет на другие |
| Переносимость | Запускается где угодно: локально, в облаке, на bare metal |
| Простота онбординга | Новый разработчик: git clone && docker-compose up |
Пройдитесь по каждому фактору и оцените соответствие:
[ ] Codebase — один репозиторий для всех сред?
[ ] Dependencies — явно объявлены?
[ ] Config — в переменных окружения?
[ ] Backing Services — через URL?
...
Начните с факторов, которые дадут максимальную пользу:
Не пытайтесь изменить всё сразу. Двигайтесь итеративно:
Спринт 1: Вынести конфигурацию в env vars
Спринт 2: Настроить CI/CD пайплайн
Спринт 3: Убрать состояние из процессов
Спринт 4: Добавить health checks
| Категория | Инструменты |
|---|---|
| Контейнеризация | Docker, Podman |
| Оркестрация | Kubernetes, Docker Swarm, Nomad |
| CI/CD | GitHub Actions, GitLab CI, Jenkins, ArgoCD |
| Конфигурация | dotenv, Vault, AWS Secrets Manager |
| Логи | ELK-стек, Loki, Splunk, Datadog |
| Метрики | Prometheus, Grafana, InfluxDB |
| Трейсинг | Jaeger, Zipkin, AWS X-Ray |
После изучения этой темы вы должны уметь ответить на вопросы:
В следующих темах мы детально разберём каждый фактор:
Ключевой вывод: 12-Factor App — это не догма, а набор best practices, проверенных на тысячах приложений. Следуйте принципам там, где они приносят пользу, и адаптируйте под свои нужды.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.