# Вопросы: Docker Опираются на кейс: [CASE.md](CASE.md). Источники — [VK Cloud.md](../../interview/VK%20Cloud.md), [Реалист банк.md](../../interview/Реалист%20банк.md). ### В чём разница между образом (image) и контейнером? Образ — неизменяемый шаблон: слоёная файловая система + метаданные (какая команда запускается по умолчанию, какие переменные окружения и т.д.), результат `docker build`. Контейнер — запущенный (или остановленный) экземпляр образа с добавленным поверх write-слоем, где живут любые runtime-изменения — по сути процесс на хосте плюс собственная изолированная файловая система, сеть и т.д. Один образ может породить много независимых контейнеров. ### В чём отличия виртуализации от контейнеризации? Виртуализация эмулирует отдельное «железо» через гипервизор — у каждой VM своё полноценное ядро ОС, изоляция максимальная, но накладные расходы выше (полный загруженный образ ОС, медленнее старт). Контейнеризация — все контейнеры хоста делят одно и то же ядро хоста; изоляция достигается через namespaces (что процесс видит — свои PID, сеть, файловую систему) и ограничение ресурсов через cgroups (сколько он может использовать), см. [../linux-bash/QUESTIONS.md](../linux-bash/QUESTIONS.md). Контейнеры легче и стартуют за секунды, но изоляция менее строгая (общее ядро — потенциальная поверхность атаки при уязвимостях в ядре). ### Как Docker понимает, что контейнер умер, и помечает его как exit? Внутри Docker Engine работает `containerd` — реальный рантайм, управляющий процессами контейнеров. Он отслеживает главный процесс контейнера (PID 1 внутри контейнерного namespace); как только этот процесс завершается (штатно или с ошибкой), это фиксируется как событие завершения, и статус контейнера меняется на `Exited` с соответствующим exit-кодом (`docker inspect --format '{{.State.ExitCode}}'`). ### Что такое Docker runtime и зачем нужен containerd? Runtime — компонент, который непосредственно создаёт и управляет изолированными процессами контейнеров на уровне ОС (namespaces, cgroups, файловая система из слоёв образа). `containerd` — низкоуровневый рантайм, на котором построен сам Docker Engine: Docker CLI/демон — это удобная надстройка (сборка образов, compose, registry-взаимодействие) поверх `containerd`, который непосредственно исполняет работу по управлению жизненным циклом контейнеров. Это разделение позволяет другим системам (например, Kubernetes через CRI) использовать `containerd` напрямую, без полного Docker Engine. ### Как зайти внутрь контейнера? ```bash docker exec -it sh # или bash, если есть в образе ``` `exec` запускает новый процесс внутри уже работающего контейнера (в отличие от `docker run`, который создаёт новый контейнер). Если контейнер уже остановлен, `exec` не сработает — нужно либо запустить его заново, либо использовать `docker cp` для файлов без запуска процесса внутри. ### Как скопировать файл в работающий контейнер? ```bash docker cp ./local-file.txt :/path/in/container docker cp :/path/in/container ./local-file.txt # и в обратную сторону, из контейнера на хост ``` ### Если убить процесс Docker (сам демон) — запущенные контейнеры сдохнут? Нет, не обязательно — сами контейнеры управляются `containerd`, а не напрямую демоном `dockerd`; при перезапуске `dockerd` уже запущенные контейнеры продолжают работать (это осознанное архитектурное решение, начиная с версии Docker, где Docker Engine был разделён с `containerd` — раньше, в старых версиях, где всё было завязано на монолитный демон, перезапуск демона действительно ронял контейнеры). После рестарта `dockerd` он заново подключается к уже работающим контейнерам через `containerd` и восстанавливает их видимость в `docker ps`. ### Как работает сеть в Docker? По умолчанию Docker создаёт bridge-сеть (`docker0` для отдельных контейнеров, отдельная сеть на проект в Docker Compose), контейнеры получают виртуальные сетевые интерфейсы, подключённые к этому мосту, и приватные IP внутри него. Docker поднимает встроенный DNS внутри пользовательских (non-default) bridge-сетей — контейнеры резолвят друг друга по имени сервиса/контейнера, а не по IP. Наружу трафик пробрасывается через `-p host_port:container_port`, что настраивает NAT-правила (iptables) для перенаправления с порта хоста на IP контейнера внутри моста. ### Много ли процессов внутри одного контейнера? У контейнеров есть PID? Технически контейнер может запускать сколько угодно процессов (например, если ENTRYPOINT — скрипт, который стартует несколько дочерних процессов), но общепринятая практика — один основной процесс на контейнер (принцип "один контейнер — одна ответственность"), чтобы жизненный цикл контейнера чётко соответствовал жизненному циклу этого процесса. У контейнера есть PID — как у любого обычного процесса хоста (см. `docker inspect --format '{{.State.Pid}}'` в кейсе), плюс внутри контейнера, благодаря PID namespace, главный процесс видит себя как PID 1 в своём изолированном пространстве. ### Entrypoint vs CMD — в чём разница? `ENTRYPOINT` — фиксированная главная команда контейнера, `CMD` — аргументы к ней по умолчанию, которые можно переопределить, просто передав другие аргументы в `docker run image <новые аргументы>`. Если задан только `CMD` без `ENTRYPOINT`, вся команда целиком переопределяется тем, что передано в `docker run`. Практическая польза разделения — можно сделать образ, у которого фиксирована сама программа (`ENTRYPOINT ["myapp"]`), но легко менять флаги запуска без пересборки образа. ### Разница docker ps, docker ps -a, docker logs, docker images? `docker ps` — только работающие контейнеры. `docker ps -a` — вообще все контейнеры, включая остановленные/завершившиеся. `docker logs ` — стандартный вывод (stdout/stderr) процесса внутри контейнера, накопленный с момента старта (`-f` — читать в реальном времени, как `tail -f`). `docker images` — список локально скачанных/собранных образов (в отличие от контейнеров — это шаблоны, а не запущенные экземпляры). ### Как сохранить логи из контейнера? `docker logs > output.log` — перенаправить stdout вывод команды в файл на хосте. Если логи пишутся не в stdout, а в файл внутри контейнера — `docker cp :/path/to/log.file ./log.file`. Для постоянного сохранения логов за пределами жизни контейнера в проде обычно настраивают logging driver (например, `json-file` с ротацией, или отправку в централизованную систему — см. [../elk/CASE.md](../elk/CASE.md)) вместо ручного копирования.