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


Основы написания Dockerfile

Dockerfile — фундамент для образов в Docker, описывающий все компоненты приложения: код, его зависимости и среду выполнения.
Докерфайлы — текстовые файлы с инструкциями — позволяют автоматизировать процесс создания образов в Docker. Они сообщают платформе контейнеризации, какие слои и в какой последовательности добавлять в образ. Каждый слой описывает изменения состояния образа по сравнению с предыдущим слоем.
Чтобы все работало, нужно правильно писать инструкции. Это не сложно — главное, понять принцип. Разберемся в структуре Dockerfile и для наглядности приведем простой пример.
Структура Dockerfile
Файлы имеют простую структуру: инструкция и аргументы. Примеры — на скрине.

Инструкции пишутся заглавными буквами, чтобы их сразу было видно. Аргументы представляют собой команды, которые должна выполнять платформа при создании образов и настройке.
Простейший Dockerfile
Чтобы создавать Dockerfile, нужно знать основные инструкции. Всего их 12:
FROM — задает родительский образ для нового образа Docker.
LABEL — описывает метаданные, которые относятся к конкретному образу.
ENV — позволяет объявить постоянные переменные.
RUN — создает слой образа, применяется при установке пакетов в контейнеры.
COPY — позволяет добавлять файлы и папки в контейнеры.
ADD — копирует файлы и папки в контейнер, отвечает за распаковку .tar-файлов.
CMD — описывает команду с аргументами, которые должны выполняться при запуске контейнера.
WORKDIR — определяет рабочий каталог.
ARG — передает аргументы в ходе сборки образа.
ENTRYPOINT — дает команду с аргументами для вызова при выполнении контейнера.
EXPOSE — указывает на открытые порты для доступа к приложению.
VOLUME — объявляет точки монтирования для работы с данными.
Эти инструкции мы подробно рассмотрим в следующем разделе, а пока приведем пример простого docker-файла.

В docker-файле:
Первая строка — аргумент для FROM. Он служит обозначением языка Go конкретной версии.
Вторая строка — инструкция WORKDIR с аргументом, обозначающим каталог, созданный в образе и назначенный рабочим для других инструкций.
Третья строка — инструкция COPY с двумя аргументами. Первый — main.go, указывает путь к каталогу, который нужно скопировать в образ из файловой системы на устройстве разработчика. Второй (точка) означает, что копирование выполнится в рабочий каталог, определенный на прошлом этапе.

Инструкции и команды в Dockerfile
Разберем двенадцать основных инструкций, которые важно знать и уметь применять.
FROM
FROM — базовая инструкция для создания Docker-образа. Она определяет родительский образ, который будет основой для нового. Именно с этой инструкции обычно начинается любой файл Dockerfile. FROM сообщает платформе о том, что при сборке нового образа должен использоваться тот родительский, который указан.
Пример:
В примере нет тега, который бы указывал, какой именно базовый образ нужен. В этом случае Docker будет использовать последнюю версию из репозитория. Если нужен другой образ, обязательно ставьте тег.
LABEL
Это инструкция или скорее метка для добавления метаданных в образ. Например, она может включать сведения об авторе, версию, дату создания и другую информацию, которая поможет получить полное представление об образе Docker. Использовать LABEL не обязательно, но опытные разработчики рекомендуют это делать.
Пример:
Здесь содержится электронная почта автора, название и версия родительского образа.
ENV
ENV задает переменные среды внутри контейнера. Эти переменные могут быть использованы в дальнейшем при выполнении команд, а также в процессе работы контейнера.
С помощью инструкции задают так называемые константы — значения, которые в одном Dockerfile используются в нескольких командах.
Использование переменных среды помогает сделать образ более гибким и адаптируемым для различных сценариев. Например, при использовании разных настроек для разработки.
Пример ENV:
В примере указаны значения, которые будут повторяться в нескольких командах файла.
RUN
Эта инструкция отвечает за создание слоев в процессе сборки образа. Когда она выполняется, образ пополняется новым слоем, состояние которого фиксируется.
Часто команда используется при установке новых пакетов. Например, тогда она может выглядеть так: RUN apt-get. Это команда подойдет для установки пакетов, если вы используете базовый образ Ubuntu.
COPY
Эта инструкция копирует файлы и директории из контекста сборки в контейнер.
Пример: COPY . ./app.
Инструкция сообщает Docker, что нужно взять папки из локального контекста и поместить их в текущую основную директорию образа. Если такой нет, COPY ее создаст.
ADD
Фактически эта инструкция выполняет те же задачи, что и предыдущая. Только в отличие от COPY, ADD позволяет добавлять в контейнер загруженные из сторонних источников файлы и распаковывать «местные» .tar-файлы.
Пример:
Здесь инструкция используется для копирования файла по ссылке в обозначенную директорию. Кстати, стоит ограничивать добавление файлов, полученных по URL — они «утяжеляют» образ, а удалить их потом нельзя.
Если инструкция содержит длинные команды из нескольких строк, для улучшения читабельности используется символ — \.
CMD и ENTRYPOINT
CMD дает команду, которая должна выполняться при запуске контейнера. Результаты ее выполнения не будут добавляться в образ при сборке.
Нюансы:
Один Dockerfile может содержать только одну инструкцию CMD. Если их будет несколько, платформа отреагирует только на последнюю.
Если в инструкции CMD нет упоминания исполняемого файла, должна также присутствовать инструкция ENTRYPOINT. Она задает точку входа в контейнер. В этом случае инструкции подаются в формате JSON.
Пример:
WORKDIR
Эта инструкция устанавливает рабочую директорию для выполнения команд в Dockerfile. Каждая инструкция, которая идет после WORKDIR, будет выполняться в указанной директории.
WORKDIR позволяет:
упростить обращение к файлам в последующих инструкциях — не нужно будет обозначать полный путь к каждому файлу или директории.
упорядочить структуру контейнера, сделать сборку быстрой и управляемой.
Формат инструкции: WORKDIR <path to working directory>
Пример:
EXPOSE
Это команда обозначает открытые порты, которые контейнер будет использовать для связи с другими контейнерами или хост-системой через команду docker run, о которой мы расскажем немного позже.
EXPOSE не открывает порты, а только указывает на те, которые будут доступны. Например, EXPOSE 80 означает, что контейнерное приложение будет работать на порту с номером 80.
EXPOSE нужна для простого и прозрачного управления конфигурацией сетевых взаимодействий. Она дает разработчикам четкое понимание, какие порты можно использовать, поэтому не придется их искать вручную. К тому же, команда позволяет сделать Dockerfile более документированным и понятным для всех, кто задействован в проекте.
VOLUME
Эта команда в Dockerfile позволяет указывать точки монтирования для внешнего хранения информации приложения и динамически управлять данными. Ее полезные свойства:
Возможность сохранять данные, например, кэши, метаданные, файлы конфигурации за пределами файловой системы Docker-контейнера. Это дает гарантию, что информация никуда не денется при перезапуске контейнера.
Возможность делиться информацией при использовании нескольких контейнеров, объявляющих общий том (механизм хранения и управления данными). Благодаря VOLUME изменения в одном контейнере будут видны другим контейнерам.
Быстрое определение места хранения данных в контейнере.
Если планируете пользоваться этой инструкцией, помните, что с ее помощью нельзя указать параметры хост-директории. Точка монтирования обозначается при создании или при запуске контейнера.
Синтаксис команды: VOLUME ["/data"].
Значение может быть:
Массивом JSON — VOLUME ["/var/log/"].
Текстовой строкой с несколькими аргументами — VOLUME /var/log или VOLUME /var/log /var/db.
Пример использования инструкции VOLUME в Dockerfile:
ARG
Это инструкция, позволяющая задавать переменную, значение которой можно передать в образ из командной строки. Значение может быть по умолчанию включено в Dockerfile. Пример: ARG Version=1.0.
ARG-переменные отличаются от ENV-переменных тем, что во время выполнения контейнера они недоступны. Зато их можно использовать, чтобы задавать значения для ENV-переменных при сборке образа.
Пример сложного Dockerfile
На практике Dockerfile может быть значительно сложнее базового примера, особенно когда речь идет о полноценных приложениях с несколькими сервисами, стадиями сборки и тонкими настройками.
Например:
Этот файл диктует следующие правила:
Двухэтапная сборка — на первом этапе устанавливаются зависимости, на втором копируется только необходимое для работы приложения.
Использование Alpine Linux — уменьшает размер итогового образа.
Безопасность — смена пользователя на непривилегированного node для выполнения приложения.
Оптимизация кэширования — зависимости копируются отдельно от кода приложения.
Production-ориентированность — устанавливаются только production-зависимости.
Оптимизация Dockerfile: уменьшение размера образа и улучшение производительности
Оптимизация Dockerfile — процесс улучшения структуры и инструкций в Dockerfile для уменьшения размера итогового образа и повышения производительности контейнера. Правильно оптимизированный Dockerfile помогает экономить ресурсы, ускорить сборку, усилить безопасность и облегчить управление инфраструктурой. Подсказываем, какие подходы можно внедрить.

Использование легких базовых образов
Верный способ сократить размер Docker-образов — использование базовых образов и их правильная настройка. Например, подойдет Alpine — дистрибутив Linux с малым количеством пакетов. Размер образа — около 5 МБ. Однако при использовании Alpine в качестве базы для собственного образа нужно настроить все необходимое для корректной работы приложения.
Есть специализированные версии Alpine-образов. Например, образ с простым скриптом print("hello world").

Многоступенчатая сборка
Отличие Dockerfile, описывающих многоступенчатую сборку от обычных в том, что в файлах присутствует несколько инструкций FROM. Это позволяет выборочно копировать артефакты сборки из одной ступени в другую и избавляться от всего, без чего можно обойтись в готовом образе.
Как работает инструкция FROM в таком подходе:
начинает новый шаг сборки;
может использовать родительский образ, отличный от того, который применялся на прошлом этапе;
работает независимо от того, что создавалось на предыдущей стадии сборки.
Вот пример файла Dockerfile, описывающего многоступенчатый подход:
Такой способ сборки позволяет максимально уменьшить размеры готовых образов, но подходит не для всех случаев. Есть смысл его применять, если вы создаете несколько контейнеров.
Удаление ненужных файлов после установки зависимостей
После установки пакетов с помощью apt-get или других менеджеров, обязательно удаляйте ненужные файлы и кэш, чтобы уменьшить размер образа.
Пример:
Можно исключать из состава образа логины и пароли, служебные файлы и секретные сведения, которые нужны только для разработки.
Минимизация количества слоев
Каждая команда в Dockerfile создает новый слой в образе. Чтобы уменьшить количество слоев и размер готового образа, объединяйте несколько команд в одну. Не всегда — только в ситуациях, когда это возможно.
Пример:
Этот метод не только уменьшает размер образа, но и ускоряет сборку, поскольку Docker более эффективно использует кэширование.
Использование .dockerignore для исключения ненужных файлов
Добавьте файл .dockerignore в корневую директорию вашего проекта, чтобы исключить из контекста сборки ненужные файлы, такие, как node_modules, .git, или временные файлы, которые могут влиять на размер образа.
Пример .dockerignore:
Этот способ не только позволяет уменьшить размер образа, но и сокращает риски, что при сборке похожих образов кэш будет признан недействительным. Это позволяет использовать сохраненные данные при повторной сборке, даже если поменяются служебные файлы проекта.
Использование нестандартных библиотек и зависимостей
В Docker можно использовать дополнительные библиотеки и зависимости, но их необходимо обрабатывать. В этом тоже поможет Dockerfile. Главное правило — четко указывать версии библиотек, чтобы в проекте потом не было несовместимости компонентов.
Как управлять зависимостями с помощью Dockerfile:
Создайте файл package.json либо requirements.txt, где укажите все используемые библиотеки и их версии.
При построении образа в Dockerfile укажите на этот файл и с помощью пакетного менеджера установите все библиотеки. Постарайтесь ничего не забыть, поскольку в готовом образе отразится только то, что было указано.
С помощью RUN установите внутри контейнера используемые пакеты и библиотеки. Для скорости и удобства можно объединить команды установки в одну инструкцию.
Осуществляйте многоэтапную сборку, чтобы дополнительные библиотеки можно было устанавливать на разных этапах и потом исключить из готового образа.
Если будете указывать непосредственно в Dockerfile все зависимости, в том числе и нестандартные, можете обойтись без использования файлов requirements.txt и package.json. Однако разработчики рекомендуют их создавать, чтобы отразить в проекте все библиотеки и их версии.
Работа с Docker-образами и контейнерами
Разберем команды для создания образа и сам процесс сборки, особенности запуска контейнера из образа.
Сборка образа из Dockerfile
Собрать образ Docker с помощью инструкций из Dockerfile позволяет команда Docker build. Она выглядит так: docker build [OPTIONS] PATH | URL.
OPTIONS — параметры, влияющие на поведение сборки.
PATH | URL — контекст сборки либо место, где вы настраиваете контейнер.
В таблице — часто используемые параметры с кратким описанием и примерами.
Параметр | Описание | Пример использования |
-t или --tag | Присваивает созданному образу тег для упрощения ссылок и управления версиями | docker build -t sampleapp:latest |
-f или --file | Указывает альтернативное имя или местоположение файла Dockerfile | docker build -f ProductionDockerfile . |
--build-arg | Позволяет передавать переменные в Dockerfile во время сборки | docker build --build-arg VERSION=10 |
--no-cache | Заставляет Docker игнорировать кэш и выполнять сборку с нуля | docker build --no-cache |
--target | Указывает конкретный целевой этап в многоступенчатой сборке | docker build --target mytarget |
--quiet или -q | Показывает только конечный идентификатор изображения, подавляя вывод сборки | docker build --quiet |
При запуске Docker build, Docker считывает Dockerfile и выполняет по порядку все инструкции, формируя многослойный образ. Чтобы ускорить сборку, платформа кэширует те слои, которые не менялись с предыдущего этапа — они не перестраиваются и используются повторно.
Чтобы было понятнее, как работает команда, разберем процесс создания образа пошагово:
1. Создание каталога и выполнение команд в терминале, чтобы перейти в этот каталог:

Создание в каталоге файла «index.html». Пример содержимого — на скрине ниже.

2. Выбор базового образа из локального репозитория/Docker Hub. Этот образ станет основой пользовательского образа и будет содержать все зависимости.
3. Создание Dockerfile с необходимыми инструкциями. В файле на скрине содержатся FROM, COPY и CMD, а также EXPOSE для открытия порта.

4. Проверка установки Docker с помощью команды docker --version.

5. Переход в папку, где находится Dockerfile и запуск в терминале команды docker build -t sampleapp:v1. Если все сделано правильно, на экране будет отображаться процесс сборки.

6. Проверка образа после сборки с помощью команды docker images. На экране появится список всех доступных образов. Только что созданный тоже должен быть в этом перечне с присвоенным тегом и метаданными.

7. Запуск образа в качестве контейнера с помощью команды docker run -p 8080:80 sampleapp:v1. На этом этапе нужно сопоставить порт компьютера с портом контейнера. Порт компьютера можно при необходимости изменить. Также следует убедиться, что указаны версия и имя образа.

8. Доступ к приложению после запуска контейнера. Необходимо открыть браузер и перейти к localhost:8080. В браузере должна отобразиться веб-страница.
Запуск контейнеров из образов
Контейнеры можно запускать с помощью команд docker run и docker start. Давайте разберемся, как они работают.
Команда docker run применяется для запуска контейнера из образа. Она создает новый контейнер и запускает его, позволяет выставить все необходимые настройки.

По умолчанию контейнер заканчивает работу после завершения основных процессов. Команда docker run с флагом (-d) позволяет выполнить запуск в фоновом режиме. Это выглядит так: docker run -d nginx.
Если нужно вводить команды, контейнер можно запустить в интерактивном режиме с помощью команды с флагом (-it): docker run -it ubuntu bash.
Если контейнер временный, можно настроить его автоматическое удаление после завершения работы. Поможет команда с флагом (–rm): docker run --rm ubuntu echo "Hello, Docker!”.
Если нужно задать контейнеру имя, воспользуйтесь командой с флагом (–name): docker run --name my_nginx nginx.
И еще одна опция — ограничение ресурсов контейнера. Например, команда с флагом (–cpus) ограничивает использование ядер процессора, с флагом (–memory) — оперативной памяти. Как это выглядит: docker run --memory=512m --cpus=1 nginx.
Перейдем к команде docker start. Она позволяет запускать контейнеры, которые ранее были остановлены. Если нужно запустить один, применяется команда docker start mycontainer, если несколько — docker start first_container second_container third_container.
Знание этих команд и понимание принципов их работы упрощает взаимодействие с контейнерами. Их можно использовать, даже если вы пока глубоко не разобрались в Docker и ее инструментах.
Советы и рекомендации
Обобщаем основные моменты, касающиеся быстрого создания образов без увеличения их размера:
Используйте в качестве базовых только официальные образы, которые защищаются и регулярно обновляются.
Используйте легкие базовые образы, например, основанные на Alpine Linux.
Удаляйте временные файлы и кэшированные данные.
Собирайте в финальном образе только необходимые зависимости.
Комбинируйте в инструкции RUN несколько команд. Также можно объединять команды установки пакетов. Для их разделения пользуйтесь символом \.
Размещайте команды, которые точно будут меняться, ближе к концу Dockerfile.
Пользуйтесь .dockerignore.
Откажитесь от установки пакетов, без которых можно обойтись.
Убедитесь, что вы установили менеджер пакетов, с которым будете работать.
Эти методы ускоряют сборку и помогают создавать компактные, быстрые и безопасные образы, что важно для эффективного использования Docker в реальных проектах.
Заключение
Если вы хотите освоить экосистему Docker, нужно научиться уверенно работать с файлами Dockerfile. Описанных в статье инструкций хватит для создания образов. А вот для управления контейнерами на серверах используются более продвинутые системы — например, Kubernetes. Вы можете попробовать развернуть Kubernetes на базе управляемого сервиса Evolution Managed Kubernetes от Cloud.ru.