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

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 ↗