Основы Docker: Dockerfile
Dockerfile — это текстовый документ, содержащий все команды, которые пользователь мог бы вызвать в командной строке для сборки Docker-образа. Docker последовательно выполняет инструкции из Dockerfile для создания образа.
Структура Dockerfile
Dockerfile состоит из последовательности инструкций (обычно по одной на строку), которые выполняются для создания слоев образа. Общий формат инструкции выглядит так:
INSTRUCTION argumentИнструкции регистронезависимы, но общепринятой практикой является написание их заглавными буквами для лучшей читаемости.
Основные инструкции Dockerfile
Вот некоторые из наиболее часто используемых инструкций в Dockerfile:
FROM: Указывает базовый образ, на основе которого будет строиться ваш новый образ. Это должна быть первая некомментированная инструкция в Dockerfile. Вы можете указать имя образа из Docker Hub или локально созданный образ.dockerfileFROM ubuntu:latest FROM node:18-alpine FROM php:8.2-fpm-alpineRUN: Выполняет команды в новом слое поверх текущего образа и фиксирует результаты.RUNиспользуется для установки программного обеспечения, настройки системы и выполнения других действий, необходимых для вашего приложения.Существует два формата инструкции
RUN:RUN <command>(shell form): Команда выполняется в оболочке (/bin/sh -cна Linux илиcmd /S /Cна Windows).RUN ["executable", "param1", "param2"](exec form): Команда выполняется напрямую без оболочки. Этот формат рекомендуется для ясности и избежания проблем с экранированием.
dockerfileRUN apt-get update && apt-get install -y curl wget unzip RUN ["npm", "install"] RUN ["php", "-r", "echo 'Hello from PHP!';"]COPY: Копирует файлы и директории из<src>в<dest>в файловой системе образа.<src>может быть файлом или директорией на хост-машине (относительно контекста сборки) или URL-адресом.<dest>— это абсолютный путь внутри образа.dockerfileCOPY . /app COPY config.ini /etc/app/ COPY ["./data.json", "/var/data/"] COPY [https://example.com/app.tar.gz](https://example.com/app.tar.gz) /tmp/ADD: Похожа наCOPY, но имеет некоторые дополнительные возможности:- Если
<src>является локальным tar-архивом (gzip, bzip2, xz), он будет автоматически распакован в<dest>. - Если
<src>является URL-адресом, Docker скачает файл по этому URL-адресу и скопирует его в<dest>.
Рекомендуется использовать
COPYвместоADDдля простых операций копирования файлов и директорий, так какCOPYболее явно указывает на выполняемое действие. ИспользуйтеADDтолько тогда, когда вам действительно нужна функциональность распаковки tar-архивов или скачивания файлов по URL.dockerfileADD app.tar.gz /app/ ADD [https://example.com/image.jpg](https://example.com/image.jpg) /images/- Если
WORKDIR: Устанавливает рабочую директорию для последующих инструкцийRUN,CMD,ENTRYPOINT,COPYиADD. Если директория не существует, она будет создана. Можно использовать несколько инструкцийWORKDIR, и они будут выполняться относительно предыдущей.dockerfileWORKDIR /app RUN npm install COPY . . WORKDIR /app/config RUN echo "Configuration done" > config.logENV: Устанавливает переменные окружения в образе. Эти переменные будут доступны запущенным контейнерам.Существует два формата:
ENV <key> <value>: Устанавливает одну переменную. Значение после первого пробела будет считаться значением переменной. Пробелы в значении нужно экранировать или заключать значение в кавычки.ENV <key>=<value> ...: Устанавливает одну или несколько переменных в форматеключ=значение.
dockerfileENV APP_HOME /opt/app ENV PATH "$PATH:$APP_HOME/bin" ENV DB_HOST=localhost DB_USER=admin DB_PASS=secretEXPOSE: Информирует Docker, на каких сетевых портах приложение внутри контейнера прослушивает соединения.EXPOSEне публикует порт хост-машины на порт контейнера — для этого необходимо использовать флаг-pпри запуске контейнера (docker run -p host_port:container_port).dockerfileEXPOSE 80 EXPOSE 443 8080CMD: Указывает команду, которая будет выполнена при запуске контейнера из образа. В Dockerfile может быть только одна инструкцияCMD. Если указано несколько, то только последняя будет иметь эффект.Существует три формата:
CMD ["executable", "param1", "param2"](exec form): Рекомендуемый формат для большинства случаев.CMD <command> <param1> <param2>(shell form): Команда выполняется в оболочке.CMD <parameter>(entrypoint as executable): Предоставляет аргументы для инструкцииENTRYPOINT.
CMDпредоставляет команду по умолчанию, которую можно переопределить при запуске контейнера с помощьюdocker run <image> <command> <args>.dockerfileCMD ["node", "server.js"] CMD ["python", "app.py", "--debug"] CMD apachectl -DFOREGROUNDENTRYPOINT: Настраивает исполняемый файл, который будет запущен при запуске контейнера. Похожа наCMD, но имеет некоторые отличия в поведении при передаче аргументов черезdocker run. В Dockerfile может быть только одна инструкцияENTRYPOINT.Существует два формата:
ENTRYPOINT ["executable", "param1", "param2"](exec form): Рекомендуемый формат.ENTRYPOINT <command> <param1> <param2>(shell form).
Аргументы, переданные через
docker run <image> <args>, будут добавлены в конец инструкцииENTRYPOINTв формате exec form. При использовании shell form аргументы могут быть проигнорированы или интерпретированы как часть команды оболочки.Часто
ENTRYPOINTиспользуется для запуска основного приложения, аCMDпредоставляет аргументы по умолчанию для этого приложения.dockerfileENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"]В этом примере при запуске контейнера выполнится
/usr/local/bin/docker-entrypoint.sh nginx -g daemon off;. Если при запуске контейнера передать дополнительные аргументы (docker run <image> -c /etc/nginx/my.conf), то команда станет/usr/local/bin/docker-entrypoint.sh nginx -g daemon off; -c /etc/nginx/my.conf.USER: Устанавливает имя пользователя или UID, который будет использоваться для выполнения последующих инструкцийRUN,CMDиENTRYPOINT.dockerfileUSER nobody USER 1001VOLUME: Создает точку монтирования с указанным именем и отмечает ее как внешний том, управляемый Docker. Это полезно для сохранения данных, которые должны переживать жизненный цикл контейнера, или для обмена данными между контейнерами.dockerfileVOLUME /data VOLUME ["/var/www", "/var/log/apache2"]ARG: Определяет переменную-аргумент, которую можно передать во время сборки образа с помощью флага--build-argкомандыdocker build.dockerfileARG VERSION=latest FROM ubuntu:$VERSION RUN echo "Using Ubuntu version: $VERSION"При сборке:
docker build --build-arg VERSION=20.04 -t my-ubuntu:custom .ONBUILD: Указывает команду, которая будет выполнена при сборке образа, который наследуется от текущего образа.ONBUILDкоманды не выполняются при сборке текущего Dockerfile.dockerfile# В базовом образе ONBUILD COPY . /app ONBUILD WORKDIR /app ONBUILD RUN npm install # В производном образе FROM my-base-image:latest # При сборке этого образа будут выполнены COPY, WORKDIR и RUN из базового образа
Порядок инструкций
Рекомендуется располагать инструкции в Dockerfile таким образом, чтобы минимизировать перестройку слоев при изменении файла. Общие рекомендации:
- Начните с наиболее редко меняющихся инструкций (например, установка базовых пакетов).
- Затем добавьте инструкции, которые меняются чаще (например, копирование исходного кода приложения).
- Инструкции, зависящие от часто меняющихся файлов, должны идти последними.
Это позволяет Docker использовать кэшированные слои для неизменившихся инструкций, что значительно ускоряет процесс сборки.
Пример Dockerfile для Node.js приложения
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]- Начинаем с базового образа
node:18-alpine. - Устанавливаем рабочую директорию
/app. - Копируем файлы
package.jsonиpackage-lock.json(если есть) для кэширования установки зависимостей. - Устанавливаем production-зависимости.
- Копируем остальной исходный код приложения.
- Информируем Docker, что приложение слушает порт 3000.
- Указываем команду для запуска приложения при старте контейнера.
Контекст сборки
При выполнении команды docker build, Docker отправляет контекст сборки на Docker daemon. Контекст сборки включает файлы и директории, расположенные в указанном пути (. в большинстве случаев). Инструкции COPY и ADD могут ссылаться только на файлы и директории внутри контекста сборки.
Игнорирование файлов (.dockerignore)
Вы можете создать файл .dockerignore в корне контекста сборки, чтобы указать файлы и директории, которые не нужно включать в контекст сборки. Это может значительно ускорить процесс сборки и уменьшить размер образа. Синтаксис .dockerignore похож на синтаксис .gitignore.
Пример .dockerignore:
node_modules
.git
.DS_StoreDockerfile является ключевым элементом в процессе контейнеризации с помощью Docker. Понимание его инструкций и лучших практик позволяет создавать эффективные и воспроизводимые Docker-образы для ваших приложений.