🐳 Вопросы интервью по Docker

Образы, контейнеры, Dockerfile, Compose и запуск Java-приложений

Вопрос Docker 1
Что такое Docker и зачем он нужен?

Ответ: Docker — платформа для упаковки приложения вместе со всеми зависимостями (JDK, библиотеки, конфигурация) в образ и запуска его в изолированном контейнере. Приложение ведёт себя одинаково на ноутбуке разработчика, в CI и на сервере.

Что это даёт:
  • Воспроизводимость — «у меня работает» превращается в «работает везде»
  • Изоляция — приложения не конфликтуют по версиям зависимостей и портам
  • Быстрый запуск — контейнер стартует за секунды, так как не загружает целую ОС
  • Простое окружение — БД, Redis, Kafka поднимаются одной командой
  • Удобная доставка — образ собирается один раз и разворачивается где угодно
Вопрос Docker 2
Чем контейнеры отличаются от виртуальных машин?
Критерий Контейнер Виртуальная машина
Ядро ОС Общее с хостом Своё у каждой ВМ (гостевая ОС)
Размер Десятки-сотни МБ Гигабайты
Запуск Секунды или меньше Десятки секунд и минуты
Изоляция На уровне процессов (слабее) На уровне железа через гипервизор (сильнее)
Накладные расходы Малые Заметные: память и CPU под гостевую ОС
💡 Важно: контейнеры Linux используют ядро Linux. На macOS и Windows Docker Desktop запускает для этого небольшую Linux-ВМ внутри.
Вопрос Docker 3
В чём разница между образом (image), контейнером и реестром (registry)?
  • Образ — неизменяемый шаблон, набор слоёв файловой системы и метаданных (команда запуска, переменные). Из него создаются контейнеры
  • Контейнер — запущенный (или остановленный) экземпляр образа с добавленным сверху слоем для записи. Как «объект» относится к «классу»
  • Реестр — хранилище образов: Docker Hub, GitHub Container Registry, приватные (Harbor, Nexus, ECR)

docker pull postgres:16           # скачать образ из реестра
docker run -d --name db postgres:16   # создать и запустить контейнер из образа
docker run -d --name db2 postgres:16  # второй независимый контейнер из того же образа
                
💡 Важно: образ называется репозиторий:тег. Тег latest — это просто имя по умолчанию, а не «самая свежая версия»; в продакшене фиксируйте конкретную версию.
Вопрос Docker 4
Как Docker устроен под капотом: namespaces, cgroups и слои?

Ответ: Контейнер — это обычный процесс Linux, к которому применены средства ядра:

Механизм Что обеспечивает
Namespaces Изоляцию: свой набор процессов (PID), сеть (net), файловая система (mnt), hostname (uts), пользователи (user), IPC
cgroups Ограничение и учёт ресурсов: CPU, память, ввод-вывод
Union FS (overlay2) Слоистую файловую систему: слои образа только для чтения плюс слой контейнера для записи
Компоненты:
  • docker (CLI) → dockerd (демон) → containerd → runc (создаёт контейнер)
  • Слои общие: если десять образов основаны на одном базовом, он хранится на диске один раз
💡 Важно: при запуске контейнер получает слой для записи, и данные в нём пропадают после удаления контейнера. Для постоянных данных нужны тома (volumes).
Вопрос Docker 5
Какие основные инструкции есть в Dockerfile?
Инструкция Назначение
FROM Базовый образ (начало сборки)
WORKDIR Рабочая директория для следующих инструкций
COPY / ADD Копирование файлов в образ
RUN Выполнить команду при сборке образа (создаёт слой)
ENV Переменная окружения (доступна и при сборке, и при запуске)
ARG Параметр только на время сборки
EXPOSE Документирует порт, который слушает приложение (порт не публикует)
USER Пользователь, под которым запускается процесс
CMD / ENTRYPOINT Что выполнить при запуске контейнера
HEALTHCHECK Команда проверки работоспособности

FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
                
Вопрос Docker 6
В чём разница между CMD и ENTRYPOINT, COPY и ADD, а также ENV и ARG?
CMD и ENTRYPOINT
  • ENTRYPOINT — основная исполняемая команда контейнера; аргументы из docker run добавляются к ней
  • CMD — команда или аргументы по умолчанию; целиком заменяется, если передать свою команду в docker run
  • Часто используют вместе: ENTRYPOINT задаёт программу, CMD — аргументы по умолчанию

ENTRYPOINT ["java", "-jar", "app.jar"]
CMD ["--spring.profiles.active=prod"]
# docker run my-app --spring.profiles.active=dev   -> заменит только CMD
                
💡 Форма записи: используйте exec-форму (JSON-массив). В shell-форме (ENTRYPOINT java -jar app.jar) процессом с PID 1 становится sh, и сигнал остановки (SIGTERM) может не дойти до JVM — приложение не завершится корректно.
COPY и ADD
  • COPY просто копирует файлы
  • ADD умеет ещё скачивать по URL и распаковывать tar-архивы; из-за неявного поведения рекомендуется COPY
ENV и ARG
  • ARG существует только во время сборки (--build-arg)
  • ENV сохраняется в образе и доступен приложению при запуске
Вопрос Docker 7
Что такое слои образа, кэш сборки и .dockerignore?

Ответ: Каждая инструкция RUN, COPY, ADD создаёт новый слой. Docker кэширует слои: если инструкция и её входные данные не менялись, слой берётся из кэша. Как только слой изменился, все слои после него пересобираются.

Как использовать кэш:
  • Сначала копировать редко меняющееся (pom.xml, скачивание зависимостей), потом часто меняющееся (исходники)
  • Объединять связанные команды в один RUN и убирать за собой временные файлы в той же команде

COPY pom.xml .
RUN mvn -q dependency:go-offline     # слой с зависимостями: меняется редко
COPY src ./src                       # исходники: меняются часто
RUN mvn -q package -DskipTests
                
.dockerignore

Файл исключает ненужное из контекста сборки: ускоряет сборку, не попадают лишние и секретные файлы.


target/
.git/
.idea/
*.log
.env
                
Вопрос Docker 8
Что такое multi-stage сборка и как уменьшить размер образа?

Ответ: В multi-stage Dockerfile несколько FROM. На первом этапе собирают приложение (нужны JDK и Maven), на втором — копируют только результат в лёгкий образ. Инструменты сборки в итоговый образ не попадают.


# этап 1: сборка
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn -q dependency:go-offline
COPY src ./src
RUN mvn -q package -DskipTests

# этап 2: запуск
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
                
Другие способы уменьшить образ:
  • Брать JRE вместо JDK и компактные базовые образы (-alpine, distroless)
  • jlink — собрать урезанный runtime только с нужными модулями JDK
  • Layered jar в Spring Boot: слои с зависимостями кэшируются отдельно от кода
  • Jib и Cloud Native Buildpacks — сборка образа без Dockerfile
  • .dockerignore и очистка временных файлов в том же RUN
Вопрос Docker 9
Как запускать Java-приложение в Docker и что такое JVM в контейнере?

Ответ: JVM, начиная с JDK 10 (и 8u191), учитывает ограничения контейнера по памяти и CPU. Но без настройки доля памяти для кучи невелика: по умолчанию максимальная куча — около 25% от лимита контейнера.


FROM eclipse-temurin:21-jre
WORKDIR /app
COPY app.jar app.jar
USER 1000
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]
                

docker run -d --name app -p 8080:8080 --memory=512m --cpus=1.5 my-app
                
Что важно знать:
  • -XX:MaxRAMPercentage задаёт долю памяти контейнера под кучу; можно использовать и обычный -Xmx
  • Кроме кучи JVM использует память под метаспейс, стеки потоков, native-память, поэтому Xmx не стоит делать равным лимиту
  • Если процесс превысил лимит, ядро убивает контейнер — статус OOMKilled, код выхода 137
  • Лимит CPU влияет на Runtime.availableProcessors(), а значит на размеры пулов потоков
  • Передавайте конфигурацию через переменные окружения (например SPRING_PROFILES_ACTIVE), а не пересобирайте образ
Вопрос Docker 10
Как хранить данные: volumes, bind mounts и tmpfs?

Ответ: Файлы внутри контейнера исчезают вместе с ним, поэтому для постоянных данных используют монтирование.

Тип Что это Когда использовать
Volume Хранилище, которым управляет Docker (/var/lib/docker/volumes) Данные БД и любое постоянное состояние; переживает удаление контейнера
Bind mount Каталог или файл хоста, смонтированный в контейнер Разработка (исходники, конфигурация с хоста)
tmpfs Временное хранилище в памяти Секреты и временные данные, которые не должны попасть на диск

docker volume create pgdata
docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16   # volume
docker run -d -v $(pwd)/config:/app/config:ro my-app                      # bind mount, только чтение
                
Вопрос Docker 11
Как работают сети в Docker и как контейнеры общаются друг с другом?
Драйвер Особенности
bridge По умолчанию: контейнеры в частной сети хоста. Пользовательская bridge-сеть даёт DNS по имени контейнера
host Контейнер использует сеть хоста напрямую, без изоляции (Linux)
none Без сети
overlay Сеть между несколькими хостами (Swarm)

docker network create backend
docker run -d --name db --network backend postgres:16
docker run -d --name app --network backend -p 8080:8080 my-app
# внутри app база доступна по адресу db:5432
                
💡 Частая ошибка: внутри контейнера localhost — это сам контейнер. К БД в другом контейнере нужно обращаться по имени сервиса (jdbc:postgresql://db:5432/mydb), а не по localhost.

-p 8080:80 публикует порт: порт_хоста:порт_контейнера. EXPOSE порт не публикует, он только документирует.

Вопрос Docker 12
Что такое Docker Compose и как описать приложение с БД?

Ответ: Docker Compose описывает несколько контейнеров приложения в одном YAML-файле (compose.yaml / docker-compose.yml) и запускает их одной командой: docker compose up -d. Compose сам создаёт общую сеть, где сервисы видят друг друга по имени.


services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/mydb
      SPRING_DATASOURCE_USERNAME: app
      SPRING_DATASOURCE_PASSWORD: secret
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d mydb"]
      interval: 5s
      retries: 10

volumes:
  pgdata:
                
Что важно:
  • depends_on без condition ждёт только старта контейнера, а не готовности БД; для ожидания готовности нужен healthcheck и service_healthy
  • restart: no, on-failure, always, unless-stopped
  • Основные команды: up, down (-v удаляет и тома), logs -f, ps, build
  • Compose обычно используют для разработки и тестов, а не как production-оркестратор
Вопрос Docker 13
Какие основные команды Docker нужно знать?
Команда Что делает
docker build -t name:tag . Собрать образ из Dockerfile
docker run -d -p 8080:8080 --name app name Создать и запустить контейнер в фоне
docker ps / docker ps -a Работающие / все контейнеры
docker logs -f app Логи контейнера в реальном времени
docker exec -it app sh Зайти внутрь работающего контейнера
docker stop app / start / restart Управление контейнером
docker rm app / docker rmi image Удалить контейнер / образ
docker images Список образов
docker pull / docker push Скачать / отправить образ в реестр
docker inspect app Подробная информация (JSON): сеть, тома, переменные
docker stats Потребление CPU и памяти
docker system prune Удалить неиспользуемые контейнеры, сети и образы
💡 Разница: docker stop посылает SIGTERM и ждёт (по умолчанию 10 секунд), затем SIGKILL; docker kill сразу посылает SIGKILL. docker run = create + start.
Вопрос Docker 14
Как безопасно передавать секреты и как повысить безопасность контейнера?
Секреты и конфигурация:
  • Не кладите секреты в образ: ни в ENV, ни в COPY, ни в ARG. Они остаются в слоях и видны через docker history
  • Передавайте при запуске: -e, --env-file, Docker/Compose secrets, секреты оркестратора, Vault
  • Не коммитьте .env в репозиторий, добавьте его в .gitignore и .dockerignore
Безопасность контейнера:
  • Запускайте не от root: USER в Dockerfile
  • Используйте минимальные базовые образы и фиксируйте версии (а не latest)
  • Сканируйте образы на уязвимости (Trivy, Docker Scout)
  • Ограничивайте ресурсы (--memory, --cpus) и привилегии (--cap-drop, --read-only)
  • Не используйте --privileged и не монтируйте docker.sock без необходимости
  • Обновляйте образы, подписывайте и берите только из доверенных реестров

RUN useradd -r -u 1001 appuser
USER appuser
                
Вопрос Docker 15
В чём разница между Docker и Kubernetes?

Ответ: Это инструменты разных уровней.

Docker Kubernetes
Собирает образы и запускает контейнеры на одном хосте Оркестратор: управляет контейнерами на кластере из многих машин
Docker Compose — несколько контейнеров на одной машине Автомасштабирование, самовосстановление, плавные обновления (rolling update), балансировка и service discovery
Подходит для разработки и небольших развёртываний Подходит для продакшена с высокой доступностью
Базовые понятия Kubernetes:
  • Pod — минимальная единица запуска, один или несколько контейнеров
  • Deployment — поддерживает нужное число копий Pod и обновления
  • Service — постоянный адрес и балансировка для набора Pod
  • ConfigMap и Secret — конфигурация и секреты
💡 Важно: Kubernetes не обязательно использует Docker для запуска: образы в формате OCI работают и с containerd, и с CRI-O. Docker остаётся стандартом для сборки образов.