Dockerfile: что скрывается за форматом

Программное обеспечение с открытым исходным кодом Docker утвердилось в качестве стандарта виртуализации контейнеров. Виртуализация контейнеров — это следующий шаг в эволюции виртуальных машин, но с одним существенным отличием. Вместо имитации полной операционной системы в контейнере виртуализируется одно приложение. Сегодня контейнеры Docker используются на всех этапах жизненного цикла программного обеспечения, таких как разработка, тестирование и эксплуатация.

В экосистеме Docker существуют различные концепции. Знание и понимание этих компонентов необходимо для эффективной работы с Docker. В частности, к ним относятся образы Docker, контейнеры Docker и файлы Dockerfiles. Мы расскажем некоторую справочную информацию и дадим практические советы по их использованию.

Что такое Dockerfile?

Dockerfile — это строительный блок в экосистеме Docker. Он описывает шаги по созданию образа Docker. Поток информации следует этой центральной модели: Dockerfile > Docker image > Docker container.

Контейнер Docker имеет ограниченное время жизни и взаимодействует со своим окружением. Представьте себе контейнер как живой организм, например, одноклеточные организмы, такие как дрожжевые клетки. Следуя этой аналогии, образ Docker примерно эквивалентен генетической информации. Все контейнеры, созданные из одного образа, одинаковы, точно так же, как все одноклеточные организмы клонируются из одной и той же генетической информации. Итак, как Dockerфайлы вписываются в эту модель?

Dockerfile определяет шаги по созданию нового образа. Вы должны понимать, что все всегда начинается с существующего базового образа. Вновь созданный образ приходит на смену базовому образу. Существует также ряд специфических изменений. Если вернуться к нашему примеру с дрожжевыми клетками, то изменения соответствуют мутациям. Dockerfile определяет две вещи для нового образа Docker:

  1. Базовый образ, из которого берется новый образ. Это закрепляет новый образ в семейном древе экосистемы Docker.
  2. Ряд специфических изменений, которые отличают новый образ от базового.

Как работает Dockerfile и как из него создается образ?

По сути, Dockerfile — это обычный текстовый файл. Dockerfile содержит набор инструкций, каждая из которых находится на отдельной строке. Эти инструкции выполняются одна за другой для создания образа Docker. Эта идея может быть вам знакома по выполнению сценария пакетной обработки. Во время выполнения к образу шаг за шагом добавляются новые слои. Мы объясняем, как именно это работает, в нашей статье об образах Docker.

Образ Docker создается путем выполнения инструкций в Dockerfile. Этот этап называется процессом сборки и запускается выполнением команды «docker build». Центральным понятием является «контекст сборки». Он определяет, к каким файлам и каталогам имеет доступ процесс сборки. В данном случае в качестве источника выступает локальный каталог. Содержимое исходного каталога передается демону Docker при вызове команды «docker build». Инструкции в Dockerfile получают доступ к файлам и каталогам в контексте сборки.

Иногда вы не хотите включать в контекст сборки все файлы, присутствующие в локальном исходном каталоге. Для этого можно использовать файл .dockerignore. Он используется для исключения файлов и каталогов из контекста сборки. Название позаимствовано из файла .gitignore в Git. Точка в имени файла указывает на то, что это скрытый файл.

Как устроен Dockerfile?

Dockerfile — это обычный текстовый файл с именем «Dockerfile». Обратите внимание, что первая буква должна быть заглавной. Файл содержит одну запись в строке. Вот общая структура Dockerfile:

# Comment
INSTRUCTION arguments

Помимо комментариев, Dockerфайлы содержат инструкции и аргументы. Они описывают структуру образа.

Комментарии и директивы синтаксического анализатора

Комментарии содержат информацию, предназначенную в первую очередь для людей. Например, в Python, Perl и Ruby комментарии в Dockerfile начинаются со знака хэша (#). Строки комментариев удаляются в процессе сборки перед дальнейшей обработкой. Обратите внимание, что только строки, начинающиеся со знака хэша, распознаются как строки комментариев.

Вот правильный комментарий:

# Our base image
FROM busybox

Напротив, ниже приведена ошибка, поскольку знак хэша находится не в начале строки:

FROM busybox # our base image

Директивы синтаксического анализатора — это особый вид комментариев. Они располагаются в строках комментариев и должны находиться в начале Dockerfile. В противном случае они будут рассматриваться как комментарии и удаляться во время сборки. Также важно отметить, что данная директива парсера может быть использована только один раз в Dockerfile.

На момент написания статьи существует только два типа директив синтаксического анализатора: «syntax» и «escape». Директива синтаксического анализатора «escape» определяет используемый символ перехода. Он используется для записи инструкций в несколько строк, а также для выражения специальных символов. Директива синтаксического анализатора «syntax» определяет правила, по которым синтаксический анализатор должен обрабатывать инструкции Dockerfile. Ниже приведен пример:

# syntax=docker/Dockerfile:1
# escape=

Инструкции, аргументы и переменные

Инструкции составляют большую часть содержимого Dockerfile. Инструкции описывают конкретную структуру образа Docker и выполняются одна за другой. Подобно командам командной строки, инструкции принимают аргументы. Некоторые инструкции напрямую сопоставимы с определенными командами командной строки. Так, существует инструкция COPY, которая копирует файлы и каталоги и примерно эквивалентна команде cp в командной строке. Однако отличие от командной строки заключается в том, что некоторые инструкции Dockerfile имеют определенные правила для их последовательности. Кроме того, некоторые инструкции могут появляться только один раз в Dockerfile.

Примечание .

Инструкции не обязательно писать с заглавной буквы. Тем не менее, при создании Dockerfile следует придерживаться этого правила.

Для аргументов необходимо делать различие между жестко закодированными и переменными частями. Docker следует методологии «двенадцатифакторного приложения» и использует переменные окружения для конфигурирования контейнеров. Инструкция ENV используется для определения переменных окружения в Dockerfile. Теперь давайте рассмотрим, как присвоить значение переменной окружения.

Значения, хранящиеся в переменных окружения, могут быть прочитаны и использованы в качестве переменных частей аргументов. Для этого используется специальный синтаксис. Он напоминает сценарии оболочки. Имени переменной окружения предшествует знак доллара: $env_var. Существует также альтернативная нотация для явного разделения имени переменной, в которой оно заключено в фигурные скобки: ${env_var}. Давайте рассмотрим конкретный пример:

# set variable 'user' to value 'admin'
ENV user="admin"
# set username to 'admin_user'
USER ${user}_user

Самые важные инструкции Dockerfile

Сейчас мы представим наиболее важные инструкции Dockerfile. Традиционно некоторые инструкции — особенно FROM — могли появляться только один раз в Dockerfile. Однако сейчас существуют многоступенчатые сборки. Они описывают несколько образов в Dockerfile. Тогда ограничение применяется к каждому отдельному этапу сборки.

Инструкция Описание Комментарий
FROM Установить базовое изображение Должна появляться как первая инструкция; только одна запись на каждом этапе сборки
ENV Установить переменные окружения для процесса сборки и времени выполнения контейнера
ARG Объявить параметры командной строки для процесса сборки Может появляться перед инструкцией FROM
WORKDIR Изменить текущий каталог
USER Изменить принадлежность к пользователю и группе
COPY Копирование файлов и каталогов на изображение Создает новый слой
ДОБАВИТЬ Копирование файлов и каталогов на изображение Создает новый слой; использовать не рекомендуется
RUN Выполнение команды в образе в процессе сборки Создает новый слой
CMD Установка аргументов по умолчанию для запуска контейнера Только одна запись для каждого этапа сборки
ENTRYPOINT Установка команды по умолчанию для запуска контейнера Только одна запись для каждого этапа сборки
EXPOSE Определить назначение портов для запущенного контейнера Порты должны быть открыты при запуске контейнера
VOLUME Включить каталог в образ как том при запуске контейнера в хост-системе

Инструкция FROM

Инструкция FROM задает базовый образ, на котором работают последующие инструкции. Эта инструкция может существовать только один раз на этапе сборки и должна появляться первой. Есть одна оговорка: инструкция ARG может появиться перед инструкцией FROM. Таким образом, вы можете указать, какой именно образ будет использоваться в качестве базового, с помощью аргумента командной строки при запуске процесса сборки.

Каждый образ Docker должен быть основан на базовом образе. Другими словами, каждый образ Docker имеет ровно один родительский образ. Это приводит к классической дилемме «курица или яйцо». Родословная должна где-то начинаться. Во вселенной Docker родословная начинается с образа «scratch». Этот минимальный образ служит началом любого образа Docker.

Инструкции ENV и ARG

Эти две инструкции присваивают значение переменной. Различие между этими двумя инструкциями заключается, прежде всего, в том, откуда берутся значения и в каком контексте доступны переменные. Сначала рассмотрим инструкцию ARG.

Инструкция ARG объявляет переменную в Dockerfile, которая доступна только в процессе сборки. Значение переменной, объявленной с помощью ARG, передается в качестве аргумента командной строки при запуске процесса сборки. Вот пример, в котором мы объявляем переменную сборки «user»:

ARG user

Когда мы запускаем процесс сборки, мы передаем фактическое значение переменной:

docker build --build-arg user=admin

При объявлении переменной можно указать значение по умолчанию. Если соответствующий аргумент не передан при запуске процесса сборки, переменной присваивается значение по умолчанию:

ARG user=tester

Без использования «—build-arg» переменная «user» содержит значение по умолчанию «tester»:

docker build

Здесь мы определяем переменную окружения с помощью инструкции ENV. В отличие от инструкции ARG, переменная, определенная с помощью ENV, существует как в процессе сборки, так и во время выполнения контейнера. Инструкция ENV может быть записана двумя способами.

  1. Рекомендуемое обозначение:
ENV version="1.0"

2. Альтернативная нотация для обратной совместимости:

ENV version 1.0
Совет

Инструкция ENV работает примерно так же, как команда «export» в командной строке.

Инструкции WORKDIR и USER

Инструкция WORKDIR используется для изменения каталогов в процессе сборки, а также при запуске контейнера. Вызов WORKDIR применяется ко всем последующим инструкциям. Во время процесса сборки затрагиваются инструкции RUN, COPY и ADD. Во время запуска контейнера это относится к инструкциям CMD и ENTRYPOINT.

Совет

Инструкция WORKDIR примерно эквивалентна команде cd в командной строке.

Инструкция USER используется для изменения текущего (Linux) пользователя, так же как инструкция WORKDIR используется для изменения каталога. Вы также можете определить принадлежность пользователя к группе. Вызов USER применяется ко всем последующим инструкциям. Во время процесса сборки на инструкции RUN влияет принадлежность к пользователю и группе. Во время выполнения контейнера это относится к инструкциям CMD и ENTRYPOINT.

Совет

Инструкция USER примерно эквивалентна команде su в командной строке.

Инструкции COPY и ADD

Инструкции COPY и ADD используются для добавления файлов и каталогов в образ Docker. Обе инструкции создают новый слой, который укладывается поверх существующего образа. Источником для инструкции COPY всегда является контекст сборки. В следующем примере мы копируем файл readme из подкаталога «doc» в контексте сборки в каталог верхнего уровня «app» образа:

COPY ./doc/readme.md /app/
Совет

Инструкция COPY примерно эквивалентна команде cp в командной строке.

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

Инструкция RUN

Инструкция RUN — одна из самых распространенных инструкций Dockerfile. Когда мы используем инструкцию RUN, мы даем команду Docker выполнить команду командной строки в процессе сборки. Полученные изменения укладываются поверх существующего образа в виде нового слоя. Инструкция RUN может быть записана двумя способами:

  1. Нотация «Shell»: Аргументы, переданные в RUN, выполняются в оболочке образа по умолчанию. Специальные символы и переменные окружения заменяются в соответствии с правилами оболочки. Вот пример вызова, который приветствует текущего пользователя, используя под-оболочку «$()»:
RUN echo "Hello $(whoami)"

2. Нотация «Exec»: Вместо передачи команды оболочке, исполняемый файл вызывается напрямую. При этом могут передаваться дополнительные аргументы. Вот пример вызова, который вызывает инструмент разработчика «npm» и поручает ему запустить сценарий «build»:

CMD ["npm", "run", " build"]
Примечание

В принципе, инструкцию RUN можно использовать для замены некоторых других инструкций Docker. Например, вызов «RUN cd src» в принципе эквивалентен «WORKDIR src». Однако при таком подходе создаются Docker-файлы, которые с увеличением размера становится сложнее читать и управлять ими. Поэтому при любой возможности следует использовать специализированные инструкции.

Инструкции CMD и ENTRYPOINT

Инструкция RUN выполняет команду в процессе сборки, создавая новый слой в образе Docker. В отличие от нее, инструкции CMD и ENTRYPOINT выполняют команду при запуске контейнера. Между этими двумя инструкциями есть тонкое различие.

  • ENTRYPOINT используется для создания контейнера, который при запуске всегда выполняет одно и то же действие. Таким образом, контейнер ведет себя как исполняемый файл.
  • CMD используется для создания контейнера, который при запуске выполняет определенное действие без дополнительных параметров. Заданное действие может быть легко отменено соответствующими параметрами.

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

Наша запись в Dockerfile:

ENTRYPOINT ["echo", "Hello"]
CMD ["World"]

Соответствующие команды в командной строке:

# Output "Hello World"
docker run my_image
# Output "Hello Moon"
docker run my_image Moon

Команда EXPOSE

Контейнеры Docker взаимодействуют по сети. Сервисы, запущенные в контейнере, обращаются к нему через указанные порты. Инструкция EXPOSE документирует назначение портов и поддерживает протоколы TCP и UDP. Когда контейнер запускается командой «docker run -P», он прослушивает порты, определенные EXPOSE. Кроме того, назначенные порты могут быть перезаписаны командой «docker run -p».

Вот пример. Наш Dockerfile содержит следующие инструкции EXPOSE:

EXPOSE 80/tcp
EXPOSE 80/udp

Затем доступны следующие способы активации портов при запуске контейнера:

# Container listens for TCP/UDP traffic on port 80
docker run -P
# Container listens for TCP traffic on port 81
docker run -p 81:81/tcp

Инструкция VOLUME

Dockerfile определяет образ Docker, который состоит из слоев, уложенных друг на друга. Слои доступны только для чтения, поэтому при запуске контейнера всегда гарантируется одно и то же состояние. Нам нужен механизм для обмена данными между запущенным контейнером и хост-системой. Инструкция VOLUME определяет «точку монтирования» внутри контейнера.

Рассмотрим следующий фрагмент Dockerfile. Мы создаем каталог «shared» в каталоге верхнего уровня образа, а затем указываем, что этот каталог должен быть смонтирован в хост-системе при запуске контейнера:

RUN mkdir /shared
VOLUME /shared

Обратите внимание, что мы не можем указать фактический путь в хост-системе в Dockerfile. По умолчанию каталоги, определенные инструкцией VOLUME, монтируются на хост-системе в каталог «/var/lib/docker/volumes/».

Как редактировать Dockerfile?

Помните, что Dockerfile — это (простой) текстовый файл. Его можно редактировать обычными методами. Обычный текстовый редактор, вероятно, является самым популярным. Это может быть редактор с графическим интерфейсом. Здесь нет недостатка в вариантах. Наиболее популярные редакторы включают VSCode, Sublime Text, Atom и Notepad++. Кроме того, ряд редакторов доступен в командной строке. Помимо оригинальных редакторов Vim и Vi, широко используются упрощенные редакторы Pico и Nano.

Примечание

Редактирование обычного текстового файла следует выполнять только в редакторах, подходящих для этой цели. Ни в коем случае не используйте для редактирования Docker-файла текстовые редакторы, такие как Microsoft Word, Apple Pages, LibreOffice или OpenOffice.

Оцените статью
cdelat.ru
Добавить комментарий