Главная/Справочники/Справочник

Production checklist

Список требований перед выводом сервиса в эксплуатацию. Пять групп: сборка, запуск, наблюдаемость, отказоустойчивость, доставка.

Пункт засчитывается, когда выполнена проверка, а не когда «в целом сделано». Каждый пункт содержит команду.

Как пользоваться

Пройти целиком до первой выкатки, затем — при существенных изменениях. Полное прохождение занимает около часа; невыполненный пункт дешевле найти здесь, чем ночью.


1. Сборка

ТребованиеПроверка
Собирается из чистого клонаgit clone . /tmp/пр && cd /tmp/пр && docker build .
Базовый образ закреплёнgrep '^FROM' Dockerfile — тег или digest
Зависимости зафиксированыФайл блокировки в репозитории
Multi-stage: инструментов сборки нетdocker run --rm ОБРАЗ which gcc
Кэш работаетtouch src/*.py && time docker build . — секунды
.dockerignore полон.git, кэши, окружения, данные
Размер соответствует ожиданиюdocker images ОБРАЗ --format '{{.Size}}' — на диске; docker image inspect … | numfmt --to=si — сколько качается
Тесты выполняются в образеdocker build --target test .
Провал теста останавливает сборкуСломать тест намеренно
Метки прослеживаемости заданыdocker image inspect ОБРАЗ --format '{{json .Config.Labels}}'

Первый пункт — самый частый провал. Работа собирается у автора и не собирается больше нигде: файл вне репозитория, переменная в личном окружении, образ в локальном кэше.


2. Запуск

ТребованиеПроверка
Пользователь не root, числовойdocker image inspect ОБРАЗ --format '{{.Config.User}}'
Точка входа в exec-формеdocker image inspect ОБРАЗ --format '{{json .Config.Entrypoint}}'
PID 1 — само приложениеdocker exec ИМЯ ps -eo pid,cmd | head -2
Слушает 0.0.0.0, не петлюсм. networking cheat sheet
Работает при --read-onlydocker run --rm --read-only --tmpfs /tmp ОБРАЗ
Capabilities сняты--cap-drop ALL плюс явные при необходимости
Ограничения памяти и CPU заданыdocker inspect ИМЯ --format '{{.HostConfig.Memory}}'
Лимиты применилисьdocker exec ИМЯ cat /sys/fs/cgroup/memory.max
Лимиты обоснованы измерениемЧисло в README со ссылкой на замер
Конфигурация из окруженияОдин образ для всех сред
Неверная конфигурация останавливает стартdocker run -e ПАРАМЕТР=мусор ОБРАЗ — ненулевой код
Секреты передаются файлом_FILE-переменные, не значения

Восьмой пункт отличается от седьмого. docker inspect показывает запрошенное; применилось ли оно, видно только изнутри (урок 17.4).

Одиннадцатый пункт. Сервис, стартовавший с испорченной настройкой, выглядит здоровым и отвечает ошибками — худший из исходов.


3. Наблюдаемость

ТребованиеПроверка
Логи в stdout и stderrdocker logs ИМЯ не пуст
Логи структурированыdocker logs ИМЯ | head -5 | python3 -m json.tool
Все строки разбираютсяВключая строки сервера приложений
Буферизация отключенаPYTHONUNBUFFERED=1
Ротация логов настроенаdocker inspect ИМЯ --format '{{json .HostConfig.LogConfig}}'
Идентификатор запроса сквознойОдин запрос — один идентификатор во всех записях
Уровень журналирования настраиваетсяПеременная окружения
Секретов в логах нетdocker logs ИМЯ | grep -iE 'password|token'
Метрики доступныЭндпоинт или экспортёр
Показания cgroup читаются изнутриdocker exec ИМЯ cat /sys/fs/cgroup/memory.events

Третий пункт проверяется не первыми строками, а всеми. Частая ошибка — настроить формат в lifespan: сервер приложений успевает напечатать первые строки своим форматом, и поток получается смешанным.

bash
docker logs ИМЯ 2>&1 | python3 -c '
import json, sys
bad = 0
lines = [line for line in sys.stdin if line.strip()]
for i, line in enumerate(lines, 1):
    try:
        json.loads(line)
    except Exception:
        bad += 1
        print(f"  строка {i} не JSON: {line[:60]}")
print(f"строк: {len(lines)}, не JSON: {bad}")'

4. Отказоустойчивость

ТребованиеПроверка
SIGTERM завершает за секундыdocker run -d --name t ОБРАЗ && time docker stop t
Активные запросы дорабатываютсяДолгий запрос плюс docker stop
stop_grace_period достаточенБольше самой долгой операции
Healthcheck естьdocker inspect ИМЯ --format '{{json .State.Health}}'
Liveness и readiness различаютсяОстановить зависимость: одна 200, другая 503
start_period больше времени стартаИначе проверки убьют инициализацию
Приложение переживает отказ зависимостиdocker compose restart db, запрос после
Приложение переживает перезапускСостояние не в container'е
Политика перезапуска заданаrestart: unless-stopped
Данные в томе, а не в слоеdocker diff ИМЯ — ничего важного
Данные переживают down/upЗаписать, down, up, прочитать
Резервное копирование настроеноПроцедура существует
Восстановление провереноВосстановить в отдельный том

Последний пункт. Резервная копия, восстановление которой не проверялось, копией не является. Это единственный пункт списка, который обычно откладывают «на потом» и не выполняют никогда.

Пятый пункт проверяется парой:

bash
docker compose stop db
curl -s -o /dev/null -w 'healthz: %{http_code}\n' localhost:8000/healthz   # ожидается 200
curl -s -o /dev/null -w 'readyz:  %{http_code}\n' localhost:8000/readyz    # ожидается 503
docker compose start db

Если обе дают одинаковый код — разделения нет, сколько бы эндпоинтов ни было объявлено.


5. Доставка

ТребованиеПроверка
Тег неизменяемыйПо SHA коммита, не latest и не prod
Грязное дерево помечаетсяgit status --porcelain в вычислении тега
Развёртывание по digestВ конфигурации @sha256:
Предыдущий digest записанФайл или переменная окружения
Откат — выполнимая командаНе «развернуть предыдущую версию»
Образ просканированtrivy image --severity HIGH,CRITICAL
Отсутствие сканера отличимо от чистогоТри кода возврата
SBOM приложенsyft ОБРАЗ -o spdx-json
Публикация только при пройденном конвейереКод 0, а не «не провалено»
Порядок этапов обоснованБыстрые проверки первыми

Про откат. План отката — это команда, которую можно выполнить не раздумывая:

bash
ci/rollback.sh production

Всё остальное — пожелание. Проверить план можно единственным способом: выполнить его на работающей системе до того, как он понадобится.


Итоговая таблица

ГруппаПунктовОтметка
1. Сборка10
2. Запуск12
3. Наблюдаемость10
4. Отказоустойчивость13
5. Доставка10
Всего55

Пять пунктов, которые пропускают чаще прочих

Если времени на весь список нет — начните с этих.

ПунктПочему пропускаютЧто произойдёт
Сборка из чистого клона«У меня же собирается»Не соберётся ни у кого другого
Проверка восстановления копииДолго и скучноВыяснится в худший момент
Различие liveness и readinessКажется дублированиемОтказ базы перезапустит все экземпляры
Лимиты, применившиеся на самом делеinspect показал числоЗапрос мог не выполниться
Все строки логов как JSONПервые строки разобралисьСборщик потеряет половину

Что этот список не проверяет

Чего нетПочему
Нагрузочное тестированиеТребует стенда
Готовность команды к дежурствуОрганизационное
Уместность самой контейнеризацииОтдельный вопрос (урок 19.3)
Архитектура приложенияКонтейнеризация её не исправляет

Последняя строка стоит того, чтобы её заметить: пятьдесят пять галочек не делают правильной систему, спроектированную неверно.


Навигация

Вернуться к справочникам
Security checklist
Python container checklist
Grading rubric
Раздел 11. Production
Главное оглавление

Markdown на GitHub ↗