Quizzes по разделам
По десять вопросов на раздел: пять на понимание, три на применение, два на диагностику. Занимает 10–15 минут.
Правило. Ответ формулируется до открытия разбора. Прочитанный ответ всегда кажется очевидным — это свойство чтения, а не признак понимания.
Quiz не входит в итоговый балл. Он служит одному: показать, где перечитать раздел, до того как вы потратите три часа на упражнения, опираясь на неверное представление.
Как читать результат
| Верных | Что это значит | Что делать |
|---|---|---|
| 9–10 | Материал усвоен | Дальше |
| 7–8 | Есть пробелы | Перечитать уроки по темам ошибок |
| 5–6 | Усвоено фрагментарно | Перечитать раздел, повторить упражнения |
| 0–4 | Раздел не пройден | Вернуться к разделу целиком |
Quiz 01. Подготовка среды
- Что именно устанавливается при установке Docker Engine, кроме самого демона?
- Почему добавление пользователя в группу
dockerэквивалентно выдаче правroot? - Чем Docker Desktop отличается от Docker Engine на Linux?
- Что произойдёт с запущенными container'ами при перезапуске демона?
- Где Docker хранит образы, тома и метаданные?
- Как проверить, что установка работает, не запуская стороннего образа?
- Как узнать версию клиента и версию демона по отдельности и зачем их различать?
- Как посмотреть, сколько места занимает Docker, с разбивкой по видам?
docker: permission denied while trying to connect to the Docker daemon socket. Причина и два способа исправления?docker versionпечатает версию клиента и ошибку для демона. Что это означает?
Ответы
- Клиент (
docker), демон (dockerd),containerd,runc, плагины (buildx,compose). Клиент — только преобразователь команд в HTTP-запросы к сокету. - Через сокет создаётся container с любыми параметрами, включая монтирование корня хоста. Демон работает от
root, значит и результат — праваroot(урок 17.1). - Desktop запускает Linux в виртуальной машине и добавляет интерфейс; на Linux Engine работает с ядром хоста напрямую. Отсюда различия в производительности ввода-вывода и в доступе к устройствам.
- Зависит от настройки: при включённом
live-restoreпродолжают работать, иначе останавливаются. Сам container'ом владеет shim, а не демон, поэтому продолжение работы возможно в принципе (урок 17.2). /var/lib/docker. Образы — в подкаталоге драйвера хранения, тома — вvolumes, метаданные — вcontainersиimage.docker versionиdocker info— оба обращаются к демону и не требуют загрузки образов.docker version --format '{{.Client.Version}}'и{{.Server.Version}}. Различать нужно, потому что клиент новее демона может использовать недоступные возможности API.docker system df -v— по образам, container'ам, томам и кэшу сборки. Логи container'ов в этот вывод не входят (урок 13.4).- Нет прав на сокет. Способы: добавить пользователя в группу
docker(равно правамroot) или использовать rootless-режим. Второй безопаснее. - Клиент установлен, демон не запущен или недоступен. Проверять —
systemctl status dockerи права на сокет.
Quiz 02. Основы Containerization
- Что такое container с точки зрения ядра Linux?
- Какие механизмы ядра обеспечивают изоляцию и что именно каждый изолирует?
- Чем container отличается от виртуальной машины в терминах ядра?
- Почему container не может использовать ядро другой версии, чем у хоста?
- Что означает «один процесс на container» и почему это правило, а не совет?
- Как посмотреть, в каких namespace находится процесс?
- Как ограничить память container'а и как проверить, что ограничение применилось?
- Как убедиться, что процесс внутри container'а — это обычный процесс хоста?
- Приложение внутри container'а видит все процессы хоста. Что не так с конфигурацией?
uname -rвнутри container'а с Ubuntu показывает ядро Fedora. Это ошибка?
Ответы
- Обычный процесс, которому ядро показывает ограниченный вид системы. Виртуализации нет; планировщик и память те же.
- Namespaces — видимость объектов (PID, сеть, точки монтирования, IPC, имя узла, пользователи); cgroups — объём ресурсов; capabilities — набор привилегированных операций; seccomp — доступные системные вызовы.
- У ВМ своё ядро и гипервизор между ней и оборудованием. У container'а ядро общее с хостом — отсюда и меньшие расходы, и меньшая изоляция (урок 19.2).
- Ядро одно на всех: container содержит только пользовательскую часть системы. Дистрибутив внутри может быть любым, ядро — всегда хостовое.
- Правило, потому что оркестратор наблюдает за PID 1: отказ второго процесса снаружи не виден. Плюс масштабирование становится невозможным — реплицируется весь набор целиком.
readlink /proc/PID/ns/*— сравнивать нужно по номеру inode, а не по поведению.docker run -m 256m; проверять изнутри:cat /sys/fs/cgroup/memory.max.docker inspectпоказывает запрошенное, а не применённое.ps -ef | grepна хосте покажет тот же процесс с другим PID. Изнутри он PID 1, снаружи — обычный номер.- Задан
--pid host: PID namespace не создан, и процессы хоста видны. - Нет. Внутри — файловая система Ubuntu, ядро — хоста. Это и есть главное отличие от ВМ.
Quiz 03. Работа с Images
- Из чего состоит образ и что содержит его манифест?
- Что такое слой и почему слои неизменяемы?
- Чем digest отличается от тега?
- Что происходит при записи в файл, пришедший из нижнего слоя?
- Почему удаление файла в новом слое не уменьшает образ?
- Как найти, какие слои занимают больше всего места?
- Как закрепить образ так, чтобы завтра запустился ровно тот же набор байтов?
- Как перенести образ на машину без доступа к registry?
- Образ пересобран, тег тот же, но container запускает старый код. Две вероятные причины?
docker imagesпоказывает десятки строк<none>:<none>. Откуда они?
Ответы
- Манифест, конфигурация и слои. Манифест перечисляет digest'ы слоёв и конфигурации; конфигурация содержит
Env,Cmd,Userи историю. - Слой — набор изменений файловой системы. Неизменяемы, потому что адресуются по содержимому: изменение даёт другой digest, то есть другой слой.
- Тег — изменяемая ссылка, digest — контрольная сумма содержимого. Один digest всегда означает один набор байтов (урок 14.4).
- Copy-up: файл копируется в верхний слой целиком, и дальше правится копия. Запись одного байта в файл на 128 МиБ даёт слой на 128 МиБ.
- Слои только добавляются. Удаление создаёт запись «файла здесь нет», содержимое остаётся ниже и извлекается (урок 12.6).
docker history образ --human --format 'table {{.Size}}\t{{.CreatedBy}}'.- Ссылаться по digest:
образ@sha256:…. Тег для этого непригоден. docker save образ -o файл.tar, перенести,docker load -i файл.tar.- Первая:
docker pullвыполнен, но container не пересоздан — работает старый. Вторая: тег перезаписан послеpull, локальная копия устарела. - Образы, потерявшие тег: сборка с тем же именем переносит тег на новый образ, старый остаётся безымянным.
Quiz 04. Containers и lifecycle
- Какие состояния проходит container и что вызывает переход между ними?
- Почему container завершается, когда завершается процесс с PID 1?
- Чем
docker stopотличается отdocker kill? - Что означает код возврата 137 и что — 143?
- Почему PID 1 не получает сигналы по умолчанию так же, как обычный процесс?
- Как узнать, почему container завершился, если логи пусты?
- Как посмотреть иерархию процессов внутри container'а?
- Как задать политику перезапуска и чем
alwaysотличается отunless-stopped? docker stopзанимает ровно 10 секунд. Две вероятные причины и как их различить?- Container перезапускается в цикле. С чего начать расследование?
Ответы
created→running→paused/exited→removed. Переходы вызывают команды клиента и завершение процесса PID 1.- Container — это и есть процесс PID 1 со своим окружением. Нет процесса — нечему принадлежать namespace'ам.
stopпосылаетSIGTERMи ждёт grace period, затемSIGKILL.killпосылаетSIGKILLсразу (или указанный сигнал).- 137 = 128 + 9: завершён
SIGKILL— либо OOM killer, либо истёк grace period у PID 1 без обработчика. 143 = 128 + 15: PID 1 умер отSIGTERM, что на практике означает--init. Правильно написанный сервис, обработавший сигнал, даёт 0 — проверено запуском (verify/FACTS.md). - Ядро не применяет к PID 1 действия по умолчанию для сигналов: если обработчик не установлен, сигнал игнорируется. Обычный процесс от
SIGTERMумер бы. docker inspect --format '{{.State.ExitCode}} {{.State.OOMKilled}}', затемdmesgиdocker events— запись мог сделать не процесс, а ядро.docker exec container ps -eo pid,ppid,cmd. Первая строка не должна бытьsh.--restart;alwaysперезапускает и после перезагрузки демона даже остановленный вручную,unless-stopped— нет.- Первая: PID 1 — оболочка (shell-форма
CMD). Вторая: обработчикSIGTERMотсутствует. Различаетpsвнутри container'а: в первом случае PID 1 —sh. - Код возврата и последние строки логов предыдущего запуска:
docker logs --previous. Политика перезапуска маскирует причину.
Quiz 05. Dockerfile
- Что такое контекст сборки и что попадает в образ из него?
- Чем
COPYотличается отADDи почему предпочитают первый? - Как устроен кэш сборки: что делает слой недействительным?
- Чем exec-форма
CMDотличается от shell-формы? - Что означает
EXPOSEи что он не делает? - Как передать секрет в сборку так, чтобы он не попал в слои?
- Как расположить инструкции, чтобы изменение кода не пересобирало зависимости?
- Как убедиться, что стадия тестов действительно выполняется?
- Сборка занимает три минуты после правки одной строки кода. Причина?
docker run образ --helpпечатает справку Python вместо справки приложения. Что не так?
Ответы
- Каталог, отправляемый демону. В образ попадает только то, что явно скопировано инструкциями, но весь контекст передаётся и влияет на кэш — отсюда нужен
.dockerignore. ADDдополнительно распаковывает архивы и загружает по URL. Неявное поведение — источник неожиданностей, поэтому для локальных файлов берутCOPY.- Слой недействителен, если изменилась инструкция или содержимое копируемых файлов. Один недействительный слой обесценивает все последующие.
- Exec-форма запускает процесс напрямую, он становится PID 1. Shell-форма разворачивается в
/bin/sh -c, и PID 1 — оболочка. - Документирует предполагаемый порт. Не публикует его и не создаёт ни одного правила.
RUN --mount=type=secret,id=…плюсdocker build --secret.ARGиENVне годятся: остаются в метаданных и истории.- Сначала копировать файл зависимостей и устанавливать, потом копировать исходники.
- Стадия, на которую нет ссылок, при обычной сборке не выполняется. Запускать явно:
docker build --target test .— и проверить, что сломанный тест останавливает сборку. COPY . .стоит раньше установки зависимостей: любое изменение сбрасывает кэш установки.- Задан только
CMD. Аргументыdocker runзаменяют его целиком. НуженENTRYPOINTдля команды иCMDдля значений по умолчанию.
Quiz 06. Python внутри Container
- Почему
python:3.13-slimобычно предпочтительнееpython:3.13иalpine? - Зачем нужен
PYTHONUNBUFFEREDи что происходит без него? - Чем виртуальное окружение внутри образа помогает multi-stage сборке?
- Почему
USERзадают числом, а не именем? - Что должно происходить в приложении при получении
SIGTERM? - Как передать конфигурацию в приложение и как проверить её при старте?
- Как прочитать ограничение памяти изнутри container'а?
- Как запустить тесты внутри образа так, чтобы их провал остановил сборку?
docker logsпуст, хотя приложение работает и печатает. Причина?- Приложение падает с
PermissionErrorпри записи в смонтированный том. Где искать?
Ответы
slimдаёт малый размер без смены реализации libc.alpineиспользует musl: часть колёс приходится собирать из исходников, и сборка замедляется в разы.- Python буферизует
stdoutблоками, когда он не терминал. Без переменной строки копятся и появляются пачкой — иногда только при завершении. - Окружение по фиксированному пути (
/opt/venv) копируется одной инструкциейCOPY --from, без привязки к версии Python в путях. - Имя внутри образа снаружи не разрешается. Kubernetes с
runAsNonRoot: trueне может убедиться, что UID ненулевой, и pod не стартует. - Прекратить приём новых задач, доработать текущие, закрыть соединения, завершиться — до истечения grace period.
- Через переменные окружения; проверять при старте и падать сразу при неверном значении. Сервис, стартовавший с испорченной настройкой, выглядит здоровым и отвечает ошибками.
cat /sys/fs/cgroup/memory.max— работает без правrootи показывает применённое, а не запрошенное.- Отдельной стадией multi-stage и вызовом
docker build --target test. Проверить, сломав один тест намеренно. - Буферизация вывода: нет
PYTHONUNBUFFERED=1. - Владелец каталога внутри container'а:
ls -ldn. Пустой том получает права из образа при первом подключении.
Quiz 07. Storage
- Чем именованный том отличается от bind mount по управлению и по переносимости?
- Что происходит с данными в записываемом слое при удалении container'а?
- Почему монтирование каталога поверх пути образа скрывает его содержимое?
- Откуда пустой том берёт владельца и права?
- Для чего нужен
tmpfsи чем он отличается от тома? - Как сделать резервную копию именованного тома?
- Как запустить container с корневой файловой системой только для чтения?
- Как проверить, что данные переживают пересоздание container'а?
chmod 777на томе «решил» проблему прав. Чем это плохо и что сделать вместо?- После
-v $(pwd):/appприложение не находит свои модули. Что произошло?
Ответы
- Томом управляет Docker, путь на хосте не важен; bind mount привязан к конкретному каталогу конкретной машины. Том переносим, bind mount — нет.
- Исчезают вместе с container'ом. Записываемый слой — часть container'а, а не образа.
- Монтирование накрывает точку целиком: содержимое образа по этому пути становится недоступно, хотя никуда не делось.
- Из образа — точнее, из каталога, поверх которого подключён, — и только при первом подключении. Дальше права сохраняются.
- Каталог в памяти для временных файлов; исчезает вместе с container'ом и не касается диска. Нужен, например, при
read_only: true. - Запустить вспомогательный container с подключённым томом и заархивировать:
docker run --rm -v том:/data -v "$PWD:/backup" alpine tar czf /backup/том.tgz -C /data . --read-onlyплюс--tmpfs /tmpдля того, что всё же требует записи.- Записать,
docker rm -f, создать заново с тем же томом, прочитать. - Полный доступ получает любой процесс. Вместо — согласовать UID и GID процесса с владельцем каталога, задав их в образе.
- Каталог хоста накрыл каталог образа. Ставить зависимости вне монтируемого пути или монтировать подкаталог.
Quiz 08. Networking
- Что происходит с сетью при создании container'а?
- Чем сеть по умолчанию
bridgeотличается от пользовательской? - Что означает публикация порта на уровне механизма?
- Почему
127.0.0.1внутри container'а — не то же, что на хосте? - Как container обращается к сервису на хосте?
- Как создать сеть, из которой нет выхода в интернет?
- Как проверить, слушает ли приложение нужный адрес, не устанавливая утилит?
- Как выяснить, в каких сетях состоит container?
- Порт опубликован,
docker psэто подтверждает, но ответа нет. Три гипотезы? - Внутри container'а не разрешаются внешние имена, а адреса пингуются. Две причины?
Ответы
- Создаётся network namespace, пара
veth, один конец в container'е, другой в мосте. Адрес выдаётся из подсети моста. - В пользовательской работает встроенное разрешение имён по имени container'а; в сети по умолчанию — только адреса.
- Правило трансляции адресов: трафик на порт хоста направляется на адрес container'а в сети Docker.
- У каждого container'а свой network namespace со своим петлевым интерфейсом.
127.0.0.1внутри — сам container. - По имени
host.docker.internal(при поддержке) либо по адресу шлюза сети Docker. internal: trueу сети в Compose или--internalпри создании. Внутренние имена продолжают разрешаться.- Изнутри:
python -c "import socket; s=socket.socket(); print(s.connect_ex(('0.0.0.0', 8000)))". Ноль — слушает. docker inspect container --format '{{json .NetworkSettings.Networks}}'.- Приложение слушает другой порт; приложение слушает
127.0.0.1; приложение не запустилось. Различает проверка изнутри. - Сеть объявлена
internal: true— и это может быть намеренно. Либо DNS хоста недоступен из сети Docker (например,127.0.0.53).
Quiz 09. Docker Compose
- Какую задачу решает Compose и чего он не делает?
- Что создаёт Compose при
up, кроме container'ов? - Что именно гарантирует
depends_onв форме списка? - Чем
condition: service_healthyотличается отservice_started? - Зачем нужен
service_completed_successfullyи для каких сервисов? - Как разделить конфигурации разработки и эксплуатации?
- Как передать секрет сервису, не записывая его в файл конфигурации?
- Как убедиться, что порядок старта соблюдается воспроизводимо?
docker compose up --scale web=3не работает: «имя занято». Причина?- Приложение падает при старте с
Connection refusedк базе. При этом имя базы разрешается. Что не так?
Ответы
- Описывает многокомпонентную систему на одной машине. Не занимается распределением по узлам, автоматическим восстановлением и масштабированием по нагрузке.
- Пользовательскую сеть проекта, объявленные тома, и присваивает имена по шаблону «проект-сервис-номер».
- Только запуск container'а, а не готовность процесса внутри.
service_startedждёт запуска container'а;service_healthy— успешного healthcheck, то есть готовности принимать запросы.- Для одноразовых задач вроде миграций: зависимый сервис не стартует, пока задача не завершится с кодом 0.
- Базовый файл плюс override:
docker compose -f compose.yaml -f compose.dev.yaml up. Отладочные настройки не попадают в основной файл. - Через
secretsс внешним файлом вне репозитория; в переменные передаётся путь (*_FILE), а не значение. - Запустить из чистого состояния десять раз подряд. Один успешный запуск ничего не доказывает: гонка проявляется не всегда.
- Задан
container_name: имя фиксировано, второй экземпляр создать нельзя. - Либо в строке подключения
localhostвместо имени сервиса, либоdepends_onбез условия готовности — база ещё инициализируется.
Quiz 10. Development workflow
- Что должно отличаться между окружением разработки и эксплуатации, а что обязано совпадать?
- Зачем монтировать код внутрь container'а при разработке и чем за это платят?
- Почему автоперезагрузчик не используют в эксплуатации?
- Как отлаживать приложение внутри container'а?
- Почему образ для разработки и образ для эксплуатации собирают из одного
Dockerfile? - Как ускорить цикл «правка — проверка» без пересборки образа?
- Как запустить одну команду внутри уже работающего container'а?
- Как убедиться, что образ эксплуатации не содержит средств разработки?
- Изменение кода не подхватывается, хотя каталог смонтирован. Две причины?
- Локально работает, в CI падает. С чего начать?
Ответы
- Совпадать обязаны версии зависимостей и способ запуска приложения. Отличаться могут монтирование кода, уровень журналирования, публикация портов, отладочные средства.
- Чтобы не пересобирать образ на каждую правку. Плата — расхождение с тем, что поедет в эксплуатацию, и риск, что каталог хоста накроет содержимое образа.
- Он перезапускает процесс при изменении файлов: лишняя нагрузка, лишняя площадь атаки и непредсказуемое поведение при случайном изменении файла.
- Подключением отладчика по порту либо
docker execс интерактивной оболочкой — если она есть в образе. В образе эксплуатации её лучше не иметь. - Multi-stage: общие стадии дают одинаковые зависимости, а различия сводятся к целевой стадии. Два файла разъезжаются.
- Монтировать только каталог с кодом, оставив зависимости в образе по пути вне монтирования.
docker exec container команда. Для образов без оболочки —docker exec container python -c "…".docker run --rm образ which gcc pip pytest— ничего не должно найтись; плюс проверка размера и списка пакетов.- Смонтирован не тот каталог (или не тот путь внутри); либо процесс не перезапускается, потому что перезагрузчик не включён.
- Сравнить окружения: версия базового образа, переменные, наличие файлов вне репозитория. Проверить сборку из чистого клона во временном каталоге.
Quiz 11. Production
- Какие требования отличают образ, пригодный к эксплуатации, от работающего?
- Зачем разделять liveness и readiness и что происходит при их слиянии?
- Для чего нужна startup-проба, если есть readiness?
- Чем
requestsотличается отlimitsпо смыслу? - Почему конфигурация приходит из окружения, а не из файла в образе?
- Как задать ограничение памяти и убедиться, что оно применилось?
- Как проверить, что приложение переживает
SIGTERMза отведённое время? - Как закрепить версию базового образа так, чтобы сборка была воспроизводимой?
- Отказ базы приводит к перезапуску всех экземпляров приложения. Что настроено неверно?
- Container помечен
unhealthy, но сервис отвечает. Где искать?
Ответы
- Non-root с числовым UID, exec-форма точки входа, обработка
SIGTERM, healthcheck, ограничения ресурсов, логи вstdout, конфигурация из окружения, отсутствие состояния внутри. - Liveness отвечает «жив ли процесс», readiness — «готов ли обслуживать». При слиянии отказ зависимости вызывает перезапуск, который ничего не чинит.
- Чтобы медленный старт не требовал большого начального ожидания у остальных проб: пока startup не пройдена, liveness не выполняется.
requestsвлияет на размещение (сколько зарезервировать),limits— на поведение под нагрузкой (когда тормозить или убивать).- Один образ должен работать во всех средах. Конфигурация в образе означает отдельный образ на среду — то есть в эксплуатацию едет не то, что проверяли.
-m 256m; проверять изнутриcat /sys/fs/cgroup/memory.max, а неdocker inspect.docker run -d, затемtime docker stop. Меньше секунды — обработчик работает; ровно grace period — нет.- Ссылаться на базовый образ по digest:
FROM python:3.13-slim@sha256:…. - Liveness-проба обращается к базе. Она должна проверять только сам процесс.
docker inspect --format '{{json .State.Health}}': код 127 — команды нет в образе, 124 — истёк timeout, 1 — проверка вернула ошибку.
Quiz 12. Security
- От чего container защищает, а от чего нет?
- Почему
rootвнутри container'а по умолчанию равенrootна хосте? - Что даёт
--privilegedи почему это эквивалентно правамrootна хосте? - Почему монтирование
/var/run/docker.sockопаснее, чем кажется? - Что делает профиль seccomp по умолчанию и чего он не делает?
- Как передать секрет в сборку, чтобы он не остался в слоях?
- Как проверить образ на наличие секретов в истории?
- Как снять все capabilities и вернуть только нужную?
- Секрет удалён следующей инструкцией
Dockerfile, но найден в образе. Почему? - Приложение работает только с
--privileged. Как найти, что именно ему нужно?
Ответы
- Защищает хост от ошибок приложения и приложения друг от друга. Не защищает от недоверенного кода и не защищает приложение от его собственных зависимостей.
- Docker не создаёт user namespace: UID 0 внутри — это UID 0 снаружи. Разделяют их namespaces и capabilities, а не преобразование идентификаторов.
- Снимает seccomp, AppArmor, возвращает все capabilities и открывает устройства. Вместе с монтированием каталогов хоста это полный доступ.
- Через сокет создаётся container с любыми параметрами — включая монтирование корня хоста. Сокет выглядит «просто файлом», а даёт полный контроль над демоном, работающим от
root. - Запрещает несколько десятков заведомо опасных системных вызовов из более чем трёхсот. Основная часть интерфейса ядра остаётся доступной.
RUN --mount=type=secretплюсdocker build --secret. Либо multi-stage: слой с секретом останется в промежуточной стадии.docker history --no-trunc образ | grep -iE 'password|secret|token'; надёжнее — распаковатьdocker saveи искать по содержимому слоёв.--cap-drop ALL --cap-add НУЖНАЯ. Искать нужную перебором от пустого набора, а не снятием от полного.- Слои только добавляются. Удаление создаёт запись «файла нет», содержимое остаётся в нижнем слое.
- Запускать с
--cap-drop ALLи добавлять по одной возможности, пока не заработает; проверить, не нужен ли вместо этого доступ к конкретному устройству через--device.
Quiz 13. Observability
- Что происходит с тем, что приложение пишет в
stdout? - Почему логи пишут в
stdout, а не в файл внутри container'а? - Что показывает
docker inspectи чего он показать не может? - Чем
docker statsотличается от чтения/sys/fs/cgroupизнутри? - Почему
docker logsможет быть пуст при работающем приложении? - Как настроить ротацию логов и почему она не включена по умолчанию для всех?
- Как посмотреть сетевые соединения container'а без утилит в образе?
- Как найти, что занимает место, если
docker system dfпоказывает немного? - Container исчез, логи приложения обрываются на обычной строке. Где искать причину?
- Сервис не отвечает,
docker psпоказываетUp. Что проверить в первую очередь?
Ответы
- Демон перехватывает поток и передаёт драйверу журналирования; при драйвере по умолчанию пишет в файл JSON на хосте.
- Файл внутри container'а не виден сборщику логов, исчезает вместе с container'ом и растёт в записываемом слое.
- Показывает намерение: что было запрошено при создании. Не показывает, применилось ли оно — это видно только по показаниям ядра.
docker statsберёт те же данные снаружи и агрегирует. Чтение изнутри даёт применённые значения, включаяmemory.events— счётчики давления, которых вstatsнет.- Буферизация вывода в приложении; либо приложение пишет в файл; либо драйвер журналирования не сохраняет вывод.
--log-opt max-size=10m --log-opt max-file=3илиdaemon.json. По умолчанию не включена ради совместимости — и это самая частая причина заполнения диска.docker exec container cat /proc/net/tcpлибоnsenter -n -t PID ss -tlnpс хоста.- Логи container'ов:
du -sh /var/lib/docker/containers/*/*-json.log. Вsystem dfони не входят. docker inspect --format '{{.State.ExitCode}} {{.State.OOMKilled}}', затемdmesgиdocker events: запись мог сделать не процесс, а ядро.- Healthcheck:
Upозначает «процесс жив», а не «сервис работает». Затем — слушает ли приложение нужный адрес.
Quiz 14. Registry
- Что происходит при
docker pushи что при этом передаётся? - Почему повторная выгрузка того же образа в другой репозиторий передаёт слои заново?
- Сколько разных digest'ов у одного образа и какой годится для закрепления?
- Чем неизменяемый тег отличается от перезаписываемого на практике?
- Что защищает TLS у registry и чего он не защищает?
- Как выгрузить образ в приватный registry с аутентификацией?
- Как узнать digest опубликованного образа, не загружая его?
- Как поднять локальный registry для проверки процесса доставки?
- В эксплуатации работает не тот код, который ожидали. Три места, где могло разойтись?
- Место на диске кончается из-за образов, хотя каждый небольшой. Причина?
Ответы
- Передаются слои, которых в registry ещё нет, затем конфигурация и манифест. Уже имеющиеся слои не передаются.
- Дедупликация действует в пределах репозитория. Другой репозиторий — другое хранилище ссылок, слои загружаются заново.
- Три: у index (списка манифестов), у манифеста конкретной платформы и у конфигурации. Для закрепления годится тот, что показывает
RepoDigests. - Неизменяемый позволяет откатиться: предыдущий образ по-прежнему доступен под своим именем. Перезаписываемый этого не даёт — под именем уже другой образ.
- Защищает содержимое при передаче. Не защищает от подмены манифеста по тегу: тег изменяем, и подмена законна с точки зрения протокола.
docker login registryс токеном, затемdocker tagиdocker push. Пароль передавать через--password-stdin, а не аргументом.docker buildx imagetools inspect образ:тег— обращается к registry без загрузки слоёв.docker run -d -p 5000:5000 registry:2; для проверки процесса этого достаточно, для эксплуатации — нет.pullвыполнен, но container не пересоздан; тег перезаписан междуpullи запуском; опубликовано не то, что собрано.- Перезаписываемые теги оставляют безымянные образы: каждая сборка добавляет ещё один, и они не удаляются.
Quiz 15. Testing
- Что проверяют unit-тесты, что интеграционные, а что — проверки образа?
- Почему тесты запускают внутри образа, а не только локально?
- Почему стадия тестов может не выполниться при обычной сборке?
- Чем проверка образа отличается от проверки исходников?
- Что даёт Testcontainers по сравнению с Compose для интеграционных тестов?
- Как сделать так, чтобы провал теста останавливал сборку?
- Как убедиться, что интеграционные тесты действительно работали с базой?
- Как проверить, что образ запускается не от
root? - Тесты «прошли», но в отчёте 33 пропущенных. Что это означает для конвейера?
- Тесты проходят локально и падают в CI. Первые три вещи для проверки?
Ответы
- Unit — логику без зависимостей; интеграционные — взаимодействие с настоящими базой и очередью; проверки образа — то, что появилось между исходниками и образом благодаря
Dockerfile. - Локально проверяются исходники рядом с тестами. В образе установлен пакет, другие пути и другой пользователь — расхождения находятся только там.
- Стадия, на которую нет ссылок, при сборке целевого образа не нужна и пропускается. Сборка при этом успешна.
- Между ними лежит
Dockerfile: лишний пакет, секрет в слое, забытыйUSER, неверная форма точки входа исходниками не ловятся. - Testcontainers поднимает зависимости из кода теста и убирает их гарантированно (в том числе после
kill -9). Compose требует внешнего управления жизненным циклом. - Прогонять их в стадии сборки (
RUN pytest) либо отдельным шагом с ненулевым кодом возврата. Проверить, сломав один тест намеренно. - Ввести переключатель, превращающий пропуск в отказ при отсутствии базы. Иначе «пропущено» неотличимо от «прошло».
docker image inspect --format '{{.Config.User}}'— значение должно быть числовым и ненулевым.- Что проверено меньше, чем кажется. В конвейере пропуск должен быть отказом: зелёная сборка не должна означать «мы перестали проверять».
- Версия базового образа; переменные окружения; файлы вне репозитория, попадающие в сборку локально и отсутствующие в CI.
Quiz 16. CI/CD
- По какому признаку упорядочивают этапы конвейера?
- Почему логику выносят в скрипты, а не пишут в шагах YAML?
- Зачем конвейеру третий код возврата, кроме «успех» и «провал»?
- Почему сканирование выполняют после сборки, а не до?
- Что экспортирует
cache-toи чего он не экспортирует? - Как перенести кэш сборки между запусками конвейера?
- Как назначить образу тег, по которому можно найти коммит?
- Как проверить, что конвейер падает быстро на частой ошибке?
- Сканер не установился, конвейер зелёный. Чем это опасно?
- «Кэш настроен, а сборка медленная». Самая частая причина?
Ответы
- По отношению «время выполнения / вероятность отказа»: вперёд то, что падает часто и проверяется быстро.
- Тогда конвейер отлаживается локально за секунды, перенос на другую платформу становится механическим, и те же скрипты годятся для проверки образа в тестах.
- Чтобы «не проверено» отличалось от «проверено и чисто». Иначе отсутствие инструмента делает конвейер зелёным ровно тогда, когда проверять перестали.
- Проверяется образ, а не исходники: между ними
Dockerfile, и его вклад исходниками не проверяется. - Экспортирует слои образа. Содержимое
RUN --mount=type=cacheне экспортирует — это разные механизмы. --cache-fromи--cache-toс хранением в registry, обязательно сmode=max.- Тег из короткого SHA коммита плюс признак незафиксированных изменений. Проверять чистоту дерева нужно
git status --porcelain:git diffне видит неотслеживаемых файлов. - Сломать самую дешёвую проверку и замерить время до падения. Минуты вместо секунд означают неверный порядок.
- Зелёный цвет начинает означать «не проверяли», и узнать об этом неоткуда. Публикация должна требовать кода 0, а не «не провалено».
mode=min— значение по умолчанию: экспортируется только последняя стадия, и слой с зависимостями в кэш не попадает.
Quiz 17. Docker internals
- Что делает клиент
dockerи что делает демон? - Из скольких запросов API состоит
docker runи почему? - Какова цепочка от демона до процесса приложения?
- Почему
runcне виден в списке процессов работающего container'а? - Сколько namespace'ов создаёт Docker и какие не создаёт?
- Как сравнить namespace'ы двух процессов надёжно?
- Как прочитать применённые ограничения ресурсов изнутри container'а?
- Как разобрать мультиплексированный поток логов из API?
docker inspectпоказывает лимит памяти, но приложение его не соблюдает. Как проверить?- Один байт записан в файл образа, слой вырос на 128 МиБ. Почему?
Ответы
- Клиент преобразует аргументы в HTTP-запросы к сокету. Всю работу выполняет демон; без клиента можно обойтись, обращаясь к API напрямую.
- Из двух:
POST /containers/createиPOST /containers/ID/start. Между ними container существует, но не запущен. dockerd→containerd→ shim →runc→ процесс. Shim остаётся родителем процесса и держит его стандартные потоки и код возврата.runcвыполняет настройку и завершается. Родителем процесса остаётся shim, поэтому container переживает перезапуск демона.- Шесть из восьми. Не создаёт
user(отсюдаrootвнутри равенrootснаружи) иtime. - По номеру inode:
readlink /proc/PID/ns/*. Сравнение по поведению обманчиво. - Читать
/sys/fs/cgroup/memory.max,cpu.max,pids.max— доступно без правroot. - Каждый фрагмент предваряется восемью байтами: байт 0 — поток (1 stdout, 2 stderr), байты 4–7 — длина. Распаковка:
struct.unpack(">BxxxI", data[:8]). - Прочитать
memory.maxизнутри. Расхождение сinspectозначает, что запрос не был выполнен: отключён контроллер cgroup или несовместимо ядро. - Copy-up: при первой записи файл копируется из нижнего слоя в верхний целиком.
Quiz 18. Docker и Kubernetes
- Какую задачу решает Docker и какую — Kubernetes?
- Почему отказ Kubernetes от
dockershimне потребовал пересборки образов? - Чем pod отличается от container'а?
- Почему
depends_onне имеет аналога в Kubernetes? - В чём разница между
requestsиlimitsи что даёт каждый? - Что нужно добавить в приложение для трёх проб?
- Какие конструкции Compose переносятся напрямую, а какие требуют переосмысления?
- Как определить, нужен ли сервису StatefulSet?
- После конвертации всё работает, но при масштабировании базы данные повреждаются. Причина?
- NetworkPolicy создана, изоляции нет. Гипотеза?
Ответы
- Docker собирает образ и запускает container на машине. Kubernetes поддерживает заданное состояние на множестве машин. Это разные уровни, а не конкуренты.
- Образы соответствуют стандарту OCI, а
dockershimбыл лишь одним звеном между kubelet и runtime. Заменили звено, стандарт не менялся. - Pod — группа container'ов, разделяющих сетевой и часть других namespace'ов. Минимальная единица планирования — pod, а не container.
- Pod'ы запускаются параллельно по устройству системы; гарантировать порядок значило бы отказаться от этого. Правильная замена — повторы подключения в приложении.
requestsучитывается при размещении,limits— при работе. От их соотношения зависит класс качества обслуживания и очередь вытеснения.- Три раздельных эндпоинта:
/startupz,/healthz(без проверки зависимостей) и/readyz(с проверкой). Это работа в коде, а не в манифесте. - Напрямую — образ, команда, окружение, секреты, лимиты, пользователь, ограничения безопасности. Переосмысления требуют
ports, тома,healthcheckи ресурсы; не переносятсяdepends_on,networks,profiles. - По наличию состояния, которое нельзя терять: именованный том с данными. Deployment с одним PVC работает, пока реплика одна.
- База развёрнута как Deployment. Два pod'а обращаются к одному тому — либо
Multi-Attach error, либо два процесса пишут в один файл. - Плагин сети не поддерживает NetworkPolicy. Правило создано и не действует, и это никак не видно — проверять нужно фактическую доступность.
Quiz 19. Ограничения Docker
- Где контейнеризация добавляет расходы, а где их практически нет?
- Почему каждый способ ускорить container ослабляет изоляцию?
- Почему образ с GPU перестаёт быть переносимым?
- Что
systemdдаёт из того же, что Docker, и чего он не даёт? - Почему одних container'ов недостаточно для недоверенного кода?
- Как измерить площадь атаки на ядро своей машины?
- Какой вопрос отбирает случаи, где Docker не нужен?
- Как проверить, что линтер конфигураций не отмечает всё подряд?
- Отладка стала дороже после контейнеризации. Что именно добавилось?
- Линтер даёт ноль находок. Что это говорит о конфигурации, а что — нет?
Ответы
- Расходов почти нет на вычислениях и памяти: это обычный процесс ядра. Есть — на системных вызовах (seccomp), файловой системе (OverlayFS), сети (
veth, NAT) и публикации портов. --network hostснимает сетевую изоляцию,seccomp=unconfined— фильтр вызовов, bind mount — независимость от хоста. Каждый приём убирает ровно то, ради чего container взят.- Устройство пробрасывается, а не виртуализируется: пользовательская часть в образе должна быть совместима с драйвером хоста. Образ привязывается к машине.
- Даёт ограничения ресурсов, изоляцию файловой системы и сети, снятие capabilities, фильтр вызовов — на тех же механизмах ядра. Не даёт упаковки зависимостей и одинаковости окружения между машинами.
- Ядро общее: любая его уязвимость доступна изнутри. Container — граница между вашими сервисами, а не между вами и злоумышленником.
- Число системных вызовов из заголовка ядра (
grep -c '^#define __NR_') и число capabilities изCapBndв/proc/self/status. - «Что перестанет работать, если убрать Docker?» Если ответ — «ничего, кроме привычки», случай попадает в список.
- Прогнать его на заведомо чистой конфигурации и убедиться, что находок нет. Инструмент, отмечающий всё, неотличим от сломанного.
- Уровни между кодом и системой: PID namespace, cgroup, OverlayFS,
veth, мост, NAT. Одно сообщениеConnection refusedначинает означать вдвое больше вещей. - Говорит, что механически проверяемых нарушений нет. Не говорит, знает ли кто-нибудь ещё, как собрать образ, обновлялся ли базовый образ и читает ли кто-нибудь отчёты сканирования.
Что делать с ошибками
Записывайте не «ошибся в вопросе 7», а тему. Три ошибки в одном разделе почти всегда лежат в одной теме, и перечитывать нужно её, а не раздел целиком.
Отдельно стоит отметить вопросы, где ответ был угадан. Угаданный верный ответ хуже честной ошибки: он не попадает в список тем для повторения.
Навигация
Вернуться к системе проверки
Checkpoints
Debugging challenges
Итоговый теоретический тест
Главное оглавление