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

Карта решений

Таблицы «задача → подход → альтернативы → цена». Используется при проектировании: помогает выбрать осознанно и увидеть, чем платишь.

Правило чтения: колонка «цена» не менее важна, чем «подход». Решение без названной цены — не решение, а предпочтение.

Содержание


Нужна ли контейнеризация

Первое решение, и единственное, которое стоит принимать до всех остальных.

Признак задачиПодходАльтернативаЦена выбора
Зависимости не ставятся из репозитория дистрибутиваContainerПакет дистрибутиваИнфраструктура сборки навсегда
Несколько машин, окружения должны совпадатьContainerУправление конфигурациейТо же
Одна машина, один сервис, зависимости в дистрибутивеsystemd-unitContainerНет одинаковости между машинами
Однократный скриптВиртуальное окружениеContainerЗависимости из системы
Статический сайтХостинг или веб-сервер из пакетаContainerПрактически ничем
Жёсткие требования к задержкамbare metalContainerНет одинаковости окружения
Работа с GPU или устройствомContainer или пакетОбраз привязан к драйверу хоста
Недоверенный кодМикро-ВМ или отдельная машинаContainerСтоимость на порядок выше

Главный вопрос: что перестанет работать, если убрать Docker? Ответ «ничего, кроме привычки» означает, что решаемой проблемы нет (урок 19.3).


Базовый образ

ЗадачаПодходАльтернативыЦена
Обычный сервис на Pythonpython:X.Y-slimalpine, полный
Критичен размерalpineslim, distrolessСборка колёс из исходников; различия musl
Минимум площади атакиdistrolessslimНет оболочки — отладка сложнее
Нужны системные библиотекиslim плюс apt-getПолный образСлой пакетов и его обновление
Требуется воспроизводимостьЗакрепление по digestТегОбновление вручную
Много образов в организацииСвой базовый образПубличныеЕго нужно поддерживать

Умолчание: slim с конкретным тегом. Отклонение от него требует довода.


Зависимости

ЗадачаПодходАльтернативыЦена
Приложение на PythonФайл блокировкиrequirements.txt с ==Обновление через инструмент
Быстрая установкаuvpipЕщё один инструмент в образе сборки
Разделение средrequirements-dev.txtГруппы в pyproject.toml
Изоляция от системыВиртуальное окружение в /opt/venvУстановка в системуОдна лишняя инструкция
Ускорение повторных сборокCache mountСлой с кэшемНе переносится в CI
Перенос кэша в CIcache-to с mode=maxБез кэшаМесто в registry

Ловушка: --mount=type=cache вместе с --no-cache-dir — взаимоисключающие. Второй отключает ровно то, что кэшируется.


Конфигурация

ЗадачаПодходАльтернативыЦена
Значения, различные по средамПеременные окруженияФайл в образеНужна проверка при старте
Много значенийФайл, монтируемый снаружиМного переменныхЕщё одна сущность
СекретыФайл через secretsПеременнаяПуть вместо значения в коде
Секреты при сборке--mount=type=secretARGТребует BuildKit
Проверка значенийПри старте, с отказомПри использованииПадение вместо тихой работы
Обнаружение опечаток в именахЯвная сверка с полямиextra="forbid"Восемь строк кода

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


Состояние и данные

ЗадачаПодходАльтернативыЦена
Данные эксплуатацииИменованный томBind mountПроцедуры копирования — ваши
Конфигурация снаружиBind mount только для чтенияТомПривязка к машине
Временные файлы при read_onlytmpfsТомИсчезают при перезапуске
Код при разработкеBind mount подкаталогаПересборкаРасхождение с эксплуатацией
База данныхУправляемая вне container'аContainer с томомСтоимость сервиса
База в container'е неизбежнаТом плюс шесть процедурКопирование, восстановление, миграции — ваши
Разделяемое состояние нескольких экземпляровВнешнее хранилищеОбщий томЕщё один компонент

Шесть вопросов до того, как помещать базу в container: как делается копия; как проверяется восстановление; как восстановить на момент времени; что с правами; как переносить между машинами; как обновлять версию СУБД. Docker не отвечает ни на один.


Сеть

ЗадачаПодходАльтернативыЦена
Связь сервисовПользовательская сетьСеть по умолчанию
Изоляция данныхОтдельная сеть с internal: trueОдна сетьЕщё одна сущность
Доступ снаружиПубликация порта только у входного сервисаПубликация у всех
РазработкаПубликация на 127.0.0.1На всех адресах
Производительность сети критична--network hostBridgeИзоляция снята целиком
Обращение к хостуhost.docker.internalАдрес шлюзаРазличия между платформами
Отладка без утилит в образе--network container:имяУстановка утилит в образ

Про --network host. Прежде чем брать — измерить, действительно ли сеть узкое место. Обычно нет.


Запуск и процессы

ЗадачаПодходАльтернативыЦена
Точка входаExec-формаShell-форма
Аргументы снаружиENTRYPOINT плюс CMDТолько CMD
Нужна подстановка оболочкиЯвный sh -cShell-формаТребуется exec внутри
Сборщик зомби-процессовinit: trueСвой init в образе
Несколько процессовНесколько container'овСупервизор внутриОтказ второго не виден снаружи
Число рабочих процессовПеременная окруженияОт числа ядерos.cpu_count() видит ядра хоста
Непривилегированный запускUSER числомИменемKubernetes не запустит по имени
Мягкое завершениеОбработчик плюс ограничение по времениТолько обработчикЗависший запрос блокирует выход

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

ЗадачаПодходАльтернативыЦена
Логиstdout в JSONФайл в container'еНастройка формата
Настройка форматаПри импорте модуляВ lifespanПервые строки уйдут другим форматом
Ротацияmax-size и max-fileБез ротации
Связывание записейИдентификатор запросаБез негоПроброс через контекст
«Жив ли процесс»/healthz без зависимостейОбщая проверкаЕщё один эндпоинт
«Готов ли обслуживать»/readyz с зависимостямиОбщая проверкаЕщё один эндпоинт
Медленный старт/startupzБольшая начальная задержкаЕщё один эндпоинт
РесурсыЧтение cgroup изнутриdocker stats
Давление памятиmemory.eventsТолько текущее потребление

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


Тестирование

ЗадачаПодходАльтернативыЦена
Логика без зависимостейUnit-тестыТолько интеграционные
Взаимодействие с базойНастоящая базаПодделкаМедленнее; нужна база в CI
Управление зависимостями в тестахTestcontainersComposeЕщё одна зависимость
То же без новых зависимостейCompose плюс --waitTestcontainersУправление жизненным циклом вручную
Проверка образаОтдельные проверки собранного образаТолько тесты исходников
Тесты в конвейереСтадия test плюс явный вызовТолько стадияСтадия без ссылок не выполняется
Отсутствие зависимостиОтказ, а не пропускПропускПереключатель для локальной работы

Про последний пункт. «33 skipped» в отчёте выглядит как успех. В конвейере пропуск должен быть отказом.


Доставка

ЗадачаПодходАльтернативыЦена
Именование образаТег по SHA коммитаlatest, prodНужен шаг обновления ссылки
РазвёртываниеПо digestПо тегуШаг подстановки digest
ОткатЗаписанный предыдущий digest«Предыдущая версия»Хранение состояния
Логика конвейераСкрипты ci/*.shШаги YAML
Порядок этаповПо время / вероятность отказаПроизвольный
СканированиеТри кода возвратаДваНемного кода
Состав образаSBOM инструментомИз файла зависимостейЕщё один инструмент
Кэш между запускамиRegistry, mode=maxБез кэшаМесто в registry
ПубликацияТолько при коде 0При «не провалено»

Масштаб

ПризнакПодходАльтернативыЦена
Одна машина, до десяти сервисовComposeОркестраторНет автоматического восстановления
Одна машина, нужна доступностьВторая машина плюс балансировщикКластерАвтоматики нет
Несколько машин, нагрузка растётУправляемый KubernetesСвой кластерЗнания всё равно нужны
Несколько команд, общая инфраструктураKubernetesCompose на машину командеПостоянная стоимость
Оркестрация проще KubernetesNomadKubernetesМеньше экосистема
Нет узлов вовсеServerless-платформаКластерОграничения и привязка

Проверка перед переходом: чек-лист из урока 18.4. Отрицательные признаки в нём весят больше положительных намеренно — они отсекают решения, принятые по инерции.


Как пользоваться картой при проектировании

  1. Пройти сверху вниз, отмечая выбранное.
  2. Для каждого выбора выписать цену из последней колонки.
  3. Сложить цены и посмотреть на список целиком.

Третий шаг даёт то, ради чего карта существует. Каждое решение по отдельности выглядит разумным; сумма показывает, во что обошлась совокупность — и иногда заставляет пересмотреть первое решение из первой таблицы.


Навигация

Вернуться к справочникам
Каталог антипаттернов
Production checklist
План дальнейшего развития
Главное оглавление

Markdown на GitHub ↗