Interview Questions
Docker

Dockerfile

Редактировать на GitHub

Вопросы

Какие инструкции есть у Dockerfile?

ИнструкцияОписание
FROMЗадаёт базовый (родительский) образ.
LABELОписывает метаданные. Например — сведения о том, кто создал и поддерживает образ.
ENVУстанавливает постоянные переменные среды.
RUNВыполняет команду и создаёт слой образа. Используется для установки в контейнер пакетов.
COPYКопирует в контейнер файлы и директории.
ADDКопирует файлы и директории в контейнер, может распаковывать локальные .tar-файлы.
CMDОписывает команду с аргументами, которую нужно выполнить когда контейнер будет запущен. Аргументы могут быть переопределены при запуске контейнера. В файле может присутствовать лишь одна инструкция CMD.
WORKDIRЗадаёт рабочую директорию для следующей инструкции.
ARGЗадаёт переменные для передачи Docker во время сборки образа.
ENTRYPOINTПредоставляет команду с аргументами для вызова во время выполнения контейнера. Аргументы не переопределяются.
EXPOSEУказывает на необходимость открыть порт.
VOLUMEСоздаёт точку монтирования для работы с постоянным хранилищем.

Чем отличается CMD от ENTRYPOINT в Dockerfile?

Эти инструкции Dockerfile задают команду, исполняемую при запуске контейнера. При их использовании есть несколько правил, например:

  • Должна быть минимум одна из них, CMD или ENTRYPOINT, в Dockerfile.
  • Если контейнер используется как исполняемый файл — ENTRYPOINT должна быть определена.
  • Если контейнер запускается с другими аргументами — CMD будет переопределена. Инструкция RUN позволяет вам установить ваше приложение и необходимые для него пакеты. Он выполняет любые команды поверх текущего изображения и создает новый слой, фиксируя результаты. Часто в Dockerfile вы найдете несколько инструкций RUN.

Хорошей иллюстрацией инструкции RUN может быть установка нескольких пакетов систем контроля версий:

RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion

Обратите внимание, что apt-get updateи apt-get installвыполняются в одной инструкции RUN. Это делается для того, чтобы убедиться, что будут установлены самые последние пакеты. Если бы apt-get installэто была отдельная инструкция RUN, то она бы повторно использовала слой, добавленный apt-get update, который мог быть создан давным-давно. Инструкция CMD позволяет вам установить команду по умолчанию , которая будет выполняться только тогда, когда вы запускаете контейнер без указания команды. Если контейнер Docker запускается с командой, команда по умолчанию будет игнорироваться. Если Dockerfile содержит более одной инструкции CMD, все инструкции CMD, кроме последней, игнорируются.

CMD имеет три формы:

  • CMD ["executable","param1","param2"] (исполнительная форма, предпочтительнее)
  • CMD ["param1","param2"]exec (устанавливает дополнительные параметры по умолчанию для ENTRYPOINT в форме
  • CMD command param1 param2 (форма оболочки) docker run -it <image> /bin/bash - тут при наличии CMD он будет проигнорирован, и будет запущен баш Инструкция ENTRYPOINT позволяет настроить контейнер, который будет работать как исполняемый файл. Он похож на CMD, потому что также позволяет указать команду с параметрами. Разница заключается в том, что команда ENTRYPOINT и параметры не игнорируются, когда контейнер Docker запускается с параметрами командной строки. (Есть способ игнорировать ENTTRYPOINT, но вряд ли вы это сделаете.)

Докерфайл

ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]

когда контейнер запускается, как docker run -it <image>будет производиться вывод

Hello world

но когда контейнер запускается, docker run -it <image> Johnэто приведет к

Hello John
  • Краткий ответ cmd подставится после entrypoint при запуске. Тем самым можно запускать контейнер с нужными параметрами. То есть в entrypoint можно передать бинарь, а в cmd передать параметры. CMD может перетереться просто.

Что происходит когда пишешь ENTRYPOINT?

Точка входа в приложение.

Это инструкция в докерфайле, которая всегда будет выполняться при запуске контейнера. Она часто используется для определения основной команды для запуска контейнера. Например для запуска веб-сервера или какой-либо иной службы.

Что происходит пошагово:
Инструкция ENTRYPOINT в Dockerfile задает команду, которая всегда будет выполняться при запуске контейнера. Она часто используется для задания основной команды для запуска контейнера, например, для запуска веб-сервера, базы данных или службы. Вот что происходит шаг за шагом:

  1. В процессе сборки образа Docker читает Dockerfile строка за строкой, сверху вниз. Когда Docker встречает инструкцию ENTRYPOINT, он записывает команду и ее аргументы.

  2. После сборки образа, при запуске контейнера из этого образа Docker выполняет команду, указанную в инструкции ENTRYPOINT.

  3. Если команда Docker run также включает в себя команду, то она передается в качестве аргумента команде ENTRYPOINT.

Например, если у вас есть Dockerfile со следующим ENTRYPOINT:

ENTRYPOINT ["/app/start.sh"]

И запускается контейнер из этого образа с помощью команды:

docker run -it my_image echo "Hello, World!"

Докер выполнит команду ENTRYPOINT с командой run в качестве аргумента:

/app/start.sh echo "Hello, World!"

Обратите внимание, что команду ENTRYPOINT можно отменить при запуске контейнера, используя флаг --entrypoint в команде docker run. В этом основной смысл, что можно переопределить аргумент, или вообще его отменить.

В чем разница между ADD и COPY

В Dockerfile, инструкции ADD и COPY обе используются для копирования файлов и директорий из локальной файловой системы в образ контейнера, но между ними есть несколько важных различий:

  • COPY поддерживает только базовое копирование локальных файлов в контейнер
  • ADD имеет дополнительный функционал, к примеру, может извлекать архивы (напр, .tar, .tar.gz, .zip и другие форматы) и загружать файлы по URL. Но если, например, копировать через него архив, то он распакуется как каталог. Это уменьшает размер образа

В большинстве случаев предпочтительнее использовать COPY, так как это более предсказуемо и ясно, а ADD стоит использовать только тогда, когда вам действительно нужны её дополнительные возможности, такие как извлечение архивов или загрузка файлов по URL.

В чем отличие ARG от ENV?

ENV позволяет создавать переменные окружения, которые будут работать во время работы контейнера. ARG позволяет закинуть переменные, которые будут доступны во время сборки. Но они недоступны в контейнере. Однако через ARG можно задавать значения переменных по умолчанию для ENV

Какие есть best practices для написания Dockerfile?

  1. Запускать только один процесс на контейнер.
  2. Стараться объединять несколько команд RUN в одну для уменьшения количества слоёв образа.
  3. Частоизменяемые слои образа необходимо располагать ниже по уровню, чтобы ускорить процесс сборки, т.к. при изменении верхнего слоя, все нижеследующие слои будут пересобираться.
  4. Указывать явные версии образов в инструкции FROM, чтобы избежать случая, когда выйдет новая версия образа с тегом latest.
  5. При установке пакетов указывать версии пакетов.
  6. Очищать кеш пакетного менеджера и удалять ненужные файлы после выполненной инструкции.
  7. Использовать multistage build для сборки артифакта в одном контейнере и размещении его в другом.

Что такое Docker squash?

Это утилита на питоне, которая позволяет объединить слои в один. Также это экспериментальный параметр с помощью которого можно создать сжатый образ.

Как уменьшить размер образа докера? У нас много COPY, RUN

  1. Использовать специальные облегченные базовые версии докер-образов.
  2. Уменьшать размер слоев, запуская RUN нечасто, объединив команды в одну
  3. Не устанавливать рекомендованные пакеты. И удалять содержимое /var/lib/apt/lists/*
  4. Docker-multistage-build. Тут указываем несколько FROM. И можно копировать результат одного FROM-а в другой

Пример

# 1 =====================================
# специальный образ, который содержит все необходимые
# для сборки библиотеки и приложения
# размер образа ~730mb
FROM diproart/ruby:2.6.4-alpine3.10 AS builder

# полный набор пакетов
ENV COMMON_PACKAGES \
tzdata \
   ...

ENV ..

RUN set -xe \
   && apk update \
   && apk upgrade \
   && apk add --no-cache --update ${COMMON_PACKAGES} \
   && rm -rf /var/cache/apk/* /tmp/* /var/tmp/*

# additional clean
#RUN rm -rf /usr/local/bundle/cache/*gem

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . .
RUN

# 2 =====================================
# чистый образ, в который добавим только самое необходимое
# размер образа ~51mb
FROM ruby:2.6.4-alpine3.10

# только необходимые для работы
# в production пакеты
ENV PRODUCTION_PACKAGES \
tzdata \
   ...

ENV ...

RUN set -xe \
   && apk update \
   && apk upgrade \
   && apk add --no-cache --update ${PRODUCTION_PACKAGES} \
   && rm -rf /var/cache/apk/* /tmp/* /var/tmp/*

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

WORKDIR /usr/src/app

# копируем скомпилированное приложение
# и пакеты в напрямую в образ из предыдущего шага
COPY --from=builder /usr/src/app .
COPY --from=builder /usr/local/bundle/ /usr/local/bundle/

EXPOSE 3000
ENTRYPOINT [ "bundle", "exec" ]
CMD [ "rails", "s", "-b", "0.0.0.0" ]

Последнее обновление: 11 сент. 2025 г., 14:56:43