1. Что такое Docker и в чем его фундаментальное отличие от виртуальных машин (VM)?
Docker — это платформа для упаковки, доставки и запуска приложений в изолированных средах, которые называются контейнерами. Главная особенность технологии заключается в том, как именно достигается эта изоляция. Docker не эмулирует компьютер целиком, а использует встроенные механизмы ядра операционной системы (изначально Linux): namespaces (для изоляции процессов, сетевых интерфейсов, файловой системы) и cgroups (для жесткого ограничения потребляемых ресурсов — CPU и RAM).
Фундаментальное отличие от виртуальных машин
Разница кроется в архитектуре и уровне абстракции:
-
Виртуальные машины (VM): Работают поверх гипервизора, который эмулирует аппаратное обеспечение. Каждая виртуальная машина требует установки полноценной гостевой операционной системы (Guest OS) со своим собственным ядром. Если вам нужно изолированно запустить три приложения, вам придется запустить три тяжеловесные ОС. Это влечет за собой высокие накладные расходы на память и процессор.
-
Docker-контейнеры: Изолируются на уровне ОС и переиспользуют единое ядро хост-системы (Host OS). Внутри контейнера находится только само приложение и его минимальные зависимости (библиотеки, конфигурации).
Ключевые тезисы (почему Docker выигрывает):
-
Общее ядро: Контейнеры обращаются напрямую к ядру хост-системы, в то время как VM пропускают все команды через гипервизор и гостевую ОС.
-
Легковесность: Из-за отсутствия собственной ОС контейнеры «весят» мегабайты, а не гигабайты, и позволяют разместить на одном сервере в разы больше запущенных экземпляров приложений.
-
Скорость запуска: Контейнер стартует за доли секунды. Для хост-системы это равносильно запуску обычного процесса, тогда как старт VM требует полного цикла загрузки операционной системы с нуля.
2. В чем разница между образом (Image) и контейнером (Container)?
Это базовая концепция Docker, и понимание разницы между этими двумя сущностями — фундамент для работы с технологией. Если коротко: образ — это статический шаблон, а контейнер — это работающее по этому шаблону приложение.
-
Docker Image (Образ): Это неизменяемый (read-only) пакет или шаблон. Он содержит всё необходимое для старта приложения: базовую файловую систему, системные библиотеки, зависимости, переменные окружения и сам скомпилированный код. Образы собираются шаг за шагом на основе инструкций из
Dockerfile. Главное свойство образа — иммутабельность. Однажды собранный образ нельзя изменить; чтобы внести правки, нужно собрать новый образ. -
Docker Container (Контейнер): Это запущенный экземпляр образа, изолированный процесс на хост-машине. Когда Docker запускает контейнер, он берет неизменяемый образ и добавляет поверх него тонкий временный слой, доступный для записи и чтения (read-write layer). Именно в этом верхнем слое происходят все изменения во время работы приложения — например, создание временных файлов. Если контейнер остановить и удалить, этот изменяемый слой исчезнет навсегда, а исходный образ останется в целости и сохранности.
Для разработчиков понятнее всего будет сравнение с объектно-ориентированным программированием:
-
Образ — это Класс (Class). Это просто чертеж или описание того, как всё должно быть устроено. Сам по себе класс ничего не выполняет, он просто лежит в коде.
-
Контейнер — это Объект (Object / Instance). Это конкретный экземпляр класса, который был создан в оперативной памяти и начал свою работу.
Из одного неизменяемого образа (класса) можно одновременно запустить десятки абсолютно независимых друг от друга контейнеров (объектов).
3. Что такое Dockerfile? В чем разница между инструкциями CMD и ENTRYPOINT?
Что такое Dockerfile
Dockerfile — это текстовый файл, выступающий в роли манифеста с пошаговыми инструкциями для сборки Docker-образа. По сути, это автоматизированный скрипт: он говорит демону Docker, какую базовую среду взять (инструкция FROM), какие файлы из вашего проекта скопировать внутрь (COPY), какие зависимости установить (RUN) и какой процесс запустить. Каждая такая инструкция создает новый слой в финальном образе.
Разница между CMD и ENTRYPOINT
Обе эти инструкции определяют, что именно должно начать работать при старте контейнера. Разница кроется в том, как они реагируют на попытку пользователя передать свои параметры при запуске через docker run. Это классический вопрос-ловушка, который проверяет, понимаете ли вы логику запуска команд.
-
ENTRYPOINT (Точка входа): Задает жестко зафиксированный исполняемый файл или команду.
ENTRYPOINTневозможно просто так переопределить, добавив слова в конецdocker run(для этого потребуется специальный флаг--entrypoint). Это фундамент поведения контейнера. -
CMD (Команда): Задает либо команду по умолчанию, либо параметры по умолчанию для
ENTRYPOINT. Главная особенностьCMD— она легко и полностью перезаписывается любым текстом, который пользователь напишет в конце командыdocker run.
Как они работают вместе (лучшая практика)
Часто их используют в связке, чтобы сделать контейнер похожим на обычную консольную утилиту. Представим, что мы собираем образ для утилиты ping:
ENTRYPOINT ["ping"]CMD ["google.com"]
-
Если запустить контейнер без параметров (
docker run my-ping-image), он выполнитping google.com(склеивENTRYPOINTиCMD). -
Если передать аргумент при запуске (
docker run my-ping-image yandex.ru), то строкаyandex.ruполностью перезапишетCMD. В итоге выполнитсяping yandex.ru.
Главный процесс (ping) остался неизменным, потому что он защищен в ENTRYPOINT, а параметры мы смогли легко заменить на ходу.
4. Как в Docker сохранять данные? (Volumes vs Bind Mounts)
Главная особенность контейнеров — их эфемерность (временный характер). Если приложение внутри контейнера запишет данные (например, добавит строки в базу данных), эти данные сохранятся в верхнем read-write слое. При удалении контейнера этот слой уничтожается, и данные пропадают навсегда.
Чтобы отвязать жизненный цикл данных от жизненного цикла контейнера, Docker пробрасывает внутрь файловую систему хост-машины. Для этого есть два основных механизма:
-
Volumes (Тома): Это файловые системы, которыми управляет исключительно сам Docker. Они создаются в специальной служебной директории на хосте (в Linux это обычно
/var/lib/docker/volumes/). Сторонние процессы хост-системы не должны с ними взаимодействовать напрямую. -
Когда применять: Это стандарт по умолчанию (best practice). Volumes используются для хранения состояний баз данных, логов и постоянных файлов приложения в продакшене. Они безопаснее, их легко бэкапить, и их могут одновременно использовать несколько контейнеров.
-
Bind Mounts (Привязка директорий): Это жесткий проброс любого конкретного пути с вашего компьютера (например,
/home/user/project/src) прямо внутрь контейнера (например, в/app). -
Когда применять: Исключительно для локальной разработки. Это позволяет вам писать код в вашей IDE на хост-машине, нажимать «Сохранить», и код моментально обновляется внутри работающего контейнера (live-reload). В продакшене использовать Bind Mounts считается плохим тоном, так как вы нарушаете портативность: контейнер начинает зависеть от специфичной структуры папок конкретного сервера.
5. Что такое Docker Compose и для чего он нужен?
Базовые команды Docker отлично подходят для управления одиночными контейнерами. Однако реальные проекты почти всегда состоят из нескольких компонентов. Например: бэкенд на Python, фронтенд на React, база данных PostgreSQL и кэш Redis. Запускать четыре контейнера по очереди через длинные команды docker run, вручную настраивать между ними сеть и порядок запуска — мучительно.
Docker Compose решает эту проблему оркестрации на локальном уровне.
-
Суть: Это инструмент для работы с многоконтейнерными приложениями. Вы переходите от императивного подхода (ввод команд в консоль) к декларативному (описание желаемого результата в коде).
-
Файл
docker-compose.yml: Это сердце Compose. В этом YAML-файле вы описываете всю инфраструктуру проекта разом: какие сервисы запустить, из каких образов, какие пробросить порты, какие подключить тома (Volumes) и переменные окружения. -
Как это работает: Одной короткой командой
docker compose upвы поднимаете весь проект. Compose автоматически создает изолированную виртуальную сеть для этих контейнеров. Благодаря этому контейнеры начинают «видеть» друг друга по названиям сервисов — бэкенд сможет подключиться к базе данных просто по хостуpostgres, не зная ее реального IP-адреса. -
Важное ограничение: Docker Compose предназначен для развертывания инфраструктуры только на одном хосте (сервере). Он идеален для локальной разработки, тестирования или запуска небольших проектов на одном VPS. Для распределения нагрузки на десятки серверов используются уже другие инструменты (Kubernetes, Docker Swarm).
6. Как устроена сеть в Docker? Какие базовые драйверы вы знаете?
По умолчанию контейнеры изолированы от внешнего мира и друг от друга. Чтобы они могли обмениваться данными, Docker использует сетевую подсистему на базе драйверов. На собеседовании от вас ждут понимания четырех основных режимов работы:
-
bridge (мост): Это драйвер по умолчанию. Docker создает виртуальную сеть внутри хост-системы. Контейнеры, подключенные к одной bridge-сети, могут общаться друг с другом по внутренним IP-адресам. Чтобы открыть доступ к контейнеру снаружи, используется «проброс портов» (port mapping), когда порт хост-машины связывается с портом контейнера (например,
8080:80). -
Пользовательские сети (User-defined bridge): Это важнейшее уточнение. Стандартный
bridgeне поддерживает встроенный DNS. Если вы сами создадите сеть (docker network create) и поместите в нее контейнеры, они смогут обращаться друг к другу по именам контейнеров, а не по меняющимся IP-адресам. Именно так работает маршрутизация в Docker Compose. -
host: Полностью отключает сетевую изоляцию между контейнером и хост-машиной. Контейнер использует сетевые интерфейсы самого сервера. Если приложение в контейнере слушает порт 80, оно будет напрямую доступно на 80 порту хоста. Это дает максимальную сетевую производительность, но чревато конфликтами портов и снижает безопасность.
-
none: Абсолютная изоляция. Контейнер получает только
loopbackинтерфейс (localhost). Он не имеет доступа ни к интернету, ни к другим контейнерам. Применяется для выполнения строго изолированных, безопасных задач.
7. Как оптимизировать и уменьшить размер Docker-образа?
Интервьюер задает этот вопрос, чтобы отличить теоретика от практика. Тяжелые образы медленно скачиваются, занимают много места на сервере и содержат больше потенциальных уязвимостей. Вот главные способы их “похудения”:
-
Использование легковесных базовых образов: Вместо полновесных ОС вроде
ubuntuилиcentos(весят сотни мегабайт) стоит использоватьalpine(весит около 5 МБ) илиdistrolessобразы. Они содержат только самый минимум, необходимый для работы. -
Файл
.dockerignore: Работает по аналогии с.gitignore. Прежде чем начать сборку, Docker копирует файлы текущей директории в свой контекст. Если не исключить.git,node_modulesили локальные логи, они отправятся в демон Docker, замедлив сборку и утяжелив кэш. -
Минимизация слоев (объединение RUN): Каждая инструкция
RUN,COPYилиADDв Dockerfile создает новый слой, который навсегда сохраняется в образе. Поэтому установку пакетов нужно делать в один шаг, связывая команды через&&, и сразу же удалять кэш пакетного менеджера в том же слое. -
Пример:
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* -
Multi-stage builds (Многоэтапные сборки): Это самый мощный инструмент. Он критически важен для компилируемых языков (Go, Java, C#, C++). Смысл в том, что в одном Dockerfile описывается несколько стадий (
FROM). На первой стадии вы используете тяжелый образ с компиляторами и исходным кодом, чтобы собрать бинарник. На второй стадии вы берете абсолютно пустой образ (например,scratchилиalpine) и копируете в него только готовый бинарник из первой стадии. Исходный код и инструменты сборки остаются за бортом, а финальный образ весит сущие мегабайты.
8. Что произойдет, если процесс внутри контейнера завершится? Как настроить автоперезапуск?
Это вопрос на понимание фундаментального принципа работы Docker: контейнер живет ровно столько, сколько живет его основной процесс.
Внутри каждого контейнера есть главный процесс, который запускается под идентификатором PID 1 (именно он указывается в инструкциях ENTRYPOINT или CMD). Если этот процесс завершает работу — успешно или из-за ошибки — Docker немедленно останавливает весь контейнер. Контейнер не умеет «висеть в фоне» без работающего приложения.
Чтобы управлять поведением контейнера при падении процесса, в Docker предусмотрены политики перезапуска (Restart Policies). Их задают при запуске через флаг --restart или в файле docker-compose.yml:
-
no(по умолчанию): Docker ничего не сделает. Процесс упал — контейнер остановился. Подходит для разовых задач (например, скриптов миграции БД). -
on-failure: Контейнер будет перезапущен, только если процесс завершился с ошибкой (код возврата отличный от нуля). Удобно для сервисов, которые могут упасть из-за временной потери связи с базой данных. -
always: Docker будет перезапускать контейнер всегда, независимо от того, почему он остановился. Кроме того, контейнер автоматически запустится при старте самого демона Docker (например, после перезагрузки сервера). -
unless-stopped: Работает точно так же, какalways, за одним исключением. Если вы вручную остановили контейнер командойdocker stop, он не включится автоматически после перезагрузки демона Docker или сервера. Это самый популярный вариант для продакшена.
9. Как передавать секреты и конфигурации в контейнер?
Интервьюер задает этот вопрос, чтобы проверить, знаете ли вы базовые правила безопасности и принцип разделения кода и конфигурации. Главный красный флаг для проверяющего — если кандидат скажет, что пароли можно вписать прямо в Dockerfile или захардкодить в приложении.
Правильный подход зависит от окружения (разработка или продакшен):
-
Переменные окружения (Environment Variables): Это стандартный и самый распространенный способ. Вы передаете настройки при запуске контейнера с помощью флага
-e(например,docker run -e DB_PASSWORD=123) или через блокenvironmentв Docker Compose. -
Файлы
.env: Чтобы не писать десятки переменных в консоли, их выносят в отдельный текстовый файл.env, который Docker Compose умеет считывать автоматически. Важно: сам файл.envвсегда должен быть добавлен в.gitignore, чтобы секреты не утекли в репозиторий с кодом. -
Docker Secrets: Встроенный механизм для безопасной передачи паролей, SSH-ключей и сертификатов. Доступен только при работе в режиме кластера (Docker Swarm). Секреты шифруются, хранятся в памяти и монтируются в контейнер в виде временных файлов в директорию
/run/secrets/. -
Внешние хранилища (Vault): В серьезном Enterprise-продакшене с Kubernetes для управления секретами используются специализированные решения, такие как HashiCorp Vault, AWS Secrets Manager или Yandex Lockbox. Приложение при старте само стучится в эти сервисы по токену и забирает нужные пароли в оперативную память.
10. В чем разница между Docker Compose, Docker Swarm и Kubernetes?
Этот вопрос проверяет, понимаете ли вы, как контейнеры работают в реальном масштабируемом продакшене, и видите ли границы применимости разных инструментов оркестрации.
-
Docker Compose: Это инструмент для работы в рамках одного хоста (одного сервера или вашего ноутбука). Он отлично подходит для локальной разработки, тестирования и запуска небольших проектов. Но если этот единственный сервер упадет, ваше приложение перестанет работать. Compose не умеет масштабировать контейнеры на несколько машин.
-
Docker Swarm: Это встроенный в Docker кластерный оркестратор. Он позволяет объединить несколько физических серверов в единый кластер (Swarm) и распределять контейнеры между ними. Его главный плюс — низкий порог входа: если вы знаете Docker Compose, вы легко освоите Swarm. Однако в последние годы он сильно уступил позиции на рынке и применяется в основном в небольших инфраструктурах, где не нужна лишняя сложность.
-
Kubernetes (K8s): Это абсолютный индустриальный стандарт для управления контейнерами на множестве серверов. Kubernetes невероятно мощный: он умеет автоматически масштабировать приложение при наплыве трафика, перезапускать упавшие узлы (self-healing), управлять распределителями нагрузки (Load Balancers) и проводить обновления без даунтайма (Zero-downtime deployment). Архитектура K8s намного сложнее, чем у Swarm, но именно его сегодня требуют на позициях DevOps-инженеров и сильных бэкендеров.
Заключение
Для успешного прохождения собеседования по Docker недостаточно просто заучить наизусть флаги командной строки. Интервьюерам важно видеть, что вы понимаете саму архитектуру: как работает изоляция, почему контейнеры эфемерны, как устроена сеть и как правильно управлять состоянием.
Совет кандидатам: Не бойтесь вопросов, на которые вы не знаете точного ответа. На технических интервью процесс мышления часто важнее заученного факта. Если вы забыли команду, честно скажите: «Я не помню точный синтаксис, но я знаю, что это решается через проброс томов, и логика здесь такая…». Рассуждайте вслух. И, конечно, лучшая подготовка — это практика: открывайте консоль, пишите свои Dockerfile, ломайте и чините зависимости руками.
Анонсы новых статей, полезные материалы, а так же если в процессе у вас возникнут сложности, обсудить их или задать вопрос по этой статье можно в моём Telegram‑сообществе. Смело заходите, если что‑то пойдет не так, — постараемся разобраться вместе.
ссылка на оригинал статьи https://habr.com/ru/articles/1043546/