Как запустить докер файл

Обновлено: 06.07.2024

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

Эту статью я писал, используя Debian 9 на VirtualBox. Конечно, это не обязательное условие, но докер сам по себе, на мой взгляд, ставит много лишнего в систему, поэтому я предпочитаю держать его в виртуальной машине.

Из чего состоит Docker ¶

Сам по себе докер, это виртуальная машина. И нужно рассматривать его именно как полноценную виртуальную машину, в которой есть свой жёсткий диск, оперативная память и сетевая карта. Если вы работали с виртуальными машинами, напримкер, VirtualBox, то многие вещи будут уже знакомы, правда, с той разницей, что докер не имеет красивую GUI-оболочку, а управляется в основном из консоли.

Основные компоненты докера:

  • Образ (image) - образ диска, который будет запускаться в контейнере.
  • Контейнер (container) - виртуальная машина, в которой запущен образ.
  • Репозиторий образов (image repository) - удалённое или локальное хранилище для образов.

Нужно помнить, что в контейнере всегда запускается образ. При этом, если докер не нашёл образ в локальном хранилище, то он будет искать его в удалённом репозитории (как правило, на Dockerhub).

Как запустить образ ¶

Как бы странно это не казалось, но, если вам хочется уже что-то запустить, то образ даже и собирать-то не надо. Достаточно установить docker и выполнить:

Это приведёт к следующим действиям:

  1. Докер скачает образ hello-world в локальное хранилище.
  2. Создаст новый контейнер.
  3. Запустит контейнер, в котором выполнится команда /hello .

Если запустить команду несколько раз, то будет создано несколько контейнеров. Убедиться в этом можно, если выполнить docker ps -a :

Чтобы удалить ненужные контейнеры и образы, выполните:

Поздравляю! Теперь вы стали почти докер-мастером.

Немного теории ¶

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

Именно на идеи изоляции процесса построена основная часть логики докера. Контейнер работает, пока работает начальный процесс (его называют entry point или command). Как только процесс завершается, контейнер останавливается. Это ключевое отличие докера от привычных виртуальных машин (вроде VirtualBox).

Благодаря изоляции процессов, на одной машине можно запускать много версий приложения, которое в обычных условиях будет конфликтовать. Например, можно запустить сразу MySQL 8 и MySQL 5, nodejs 8 и nodejs 10. Без докера сделать это тоже можно, но проблематичней.

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

Как использовать ресурсы контейнера ¶

По умолчанию контейнер закрыт от любых контактов извне. Вы не можете ни скопировать в него файл, ни подключиться к сокету. Он закрыт. Но при запуске контейнера можно пробросить порт или папку. Тогда к нему можно будет подключиться, добавить файл или что-то скачать. Всё это делается при создании (запуске) контейнера через аргументы.

Проброс портов ¶

Для примера запустим контейнер с Debian 9 и пробросим локальный порт 3132 на 80 порт контейнера:

Пояснения к команде:

  • docker run - создаёт и запускает новый контейнер.
  • --tty - подключает виртуальную консоль. Это нужно, чтобы команда cat не завершала работу, иначе контейнер остановится.
  • --detach - запускает выполнение контейнера в фоне. Без этого аргумента консоль будет ждать, когда контейнер остановится (для остановки придётся использовать другую консоль).
  • --entrypoint /bin/cat - использовать в качестве процесса системную утилиту cat . Просто потому, что она не завершится пока не закроется stdin, а значит и контейнер будет работать.
  • --name my_container - уникальное имя, которое используется для управления контейнером. Если его не указывать, то докер сам придумает какое-нибудь имя.
  • --publish 3132:80 - проброс портов. Сначала надо указать порт машины (можно указать вместе с IP), потом порт в контейнере.

Общий принцип запуска контейнеров довольно простой:

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

Теперь давайте рассмотрим, как выполнять команды внутри контейнера. Для примера установим и запустим консольный сервер php 7:

Пояснения к команде:

  • docker exec - выполняет команду внутри запущенного контейнера.
  • --tty - подключает виртуальную консоль. Без этого аргумента вывод будет неправильным.
  • --interactive - подключает ввод. Без него не будет работать клавиатура.
  • my_container - имя контейнера, в котором выполняется команда.
  • команда и аргументы - команда, которая будет выполнена внутри контейнера.

Чтобы проверить, работает сервер или нет, нужно подключиться на 3132 порт основной машины, например так:

В этом примере я использовал две разные консоли. На одной я запускал сервер, а на другой curl. Ещё можно использовать браузер, если докер установлен у вас в системе.

Проброс папки ¶

В предыдущем примере я создал index.php прямо в контейнере. Это не самый удобный способ разработки проектов в через докер. Во-первых, много файлов так не создашь, во-вторых ими сложно управлять, а, в-третьих, если удалить контейнер, они тоже удалятся. Чтобы решить эти проблемы, можно пробросить (примонтировать) папку из реальной машины в виртуальный контейнер. Делается это, как всегда, при создании контейнера, через аргумент --volume исходная_папка:папка_контейнера .

Прежде, чем начать что-то менять, надо удалить старый контейнер:

Теперь подготовим наш "проект":

А теперь запускаем контейнер с пробросом папки проекта:

Если вы помните, я удалил контейнер, в котором был установлен php, а это значит, что мне заново придётся установить пакет php7.0-cli:

Теперь в контейнере есть и проект, и php, можно запускать сервер:

Теперь проверяем, как работает наш проект:

Для наглядности давайте создадим ещё один файл в "проекте", чтобы удостовериться, что всё работает как надо:

Должно вывести что-то вроде этого:

Если у вас получилось, смело пишите в резюме, что владеете докером!

Собираем образ (image) ¶

В предыдущих примерах я два раза установил один и тот же пакет в два разных контейнера. Это, мягко говоря, неудобно. Докер предлагает более гибкое и простое решения - собрать образ с уже установленными пакетами и некоторыми настройками.

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

Прежде, чем писать файл, я бы хотел определить проблемы, которые нужно решить:

  1. Установить пакет php7.0-cli.
  2. Сделать точку входа (чтобы не мучить cat)

Указать проброс портов или папки в Dockerfile файле нельзя (несмотря на директивы EXPOSE и VOLUME, проброс и монтирование можно делать только при запуске контейнера). Сделано это специально по причинам безопасности, иначе владелец образа в репозитории мог бы подключать любую системную папку в контейнер без ведома пользователя и красть данные.

Создаём Dockerfile в любой папке со следующим содержимым:

Несколько слов об установке пакетов. Изначально в сборках *-slim отсутствует дерево пакетов (для уменьшения размера образа), поэтому надо обязательно выполнять apt-get update . После установки желательно удалить ненужные файлы и папки, поэтому выполняются команды очистки.

Небольшое отступление про точку входа. Как я уже говорил, основная специализация докера, это изолирование процесса. Поэтому в одном контейнере запускается всегда один процесс, и точка входа тоже всегда одна. Если нужно запустить вместе несколько процессов (например, php-frm и nginx), то пишется скрипт, который становится точкой входа и запускает нужные приложения. Но объявить несколько точек входа, на данный момент, нельзя.

Теперь нужно собрать образ командой:

Пояснения к команде:

  • docker build - запускает сборку образа.
  • -t my_image:1.0.1 - задаёт имя и тэг образа. Если тэг не указан, используется значение lastest .
  • -f Dockerfile - явно указывает расположение Dockerfile. Можно опустить, если файл называется Dockerfile и находится в текущей директории.
  • $/project - рабочая директория для сборки образа. Относительные пути в Dockerfile будут строиться от этой папки.

Готово! Теперь можно запустить контейнер из нашего образа:

Если всё сделано правильно, то список запущенных контейнеров должен быть таким:

Ура! Теперь вы гуру :) Конечно, это далеко не все возможности докера, но это то, на чём строятся большие проекты. В основе каждого проекта стоят контейнеры, которые запускаются из образов. Комбинации контейнеров образуют кластеры, которые обеспечивают безотказную работу крупных приложений.

Что дальше ¶

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

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

  • Сохранение образов контейнеров в виде кода.
  • Быстрое и точное воссоздание образов контейнеров для обслуживания и обновления.
  • Непрерывная интеграция между образами контейнеров и циклом разработки.

За такую автоматизацию отвечают два компонента Docker — файл Dockerfile и команда docker build .

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

Docker build — команда подсистемы Docker, использующая файл Dockerfile и запускающая процесс создания образа.

В этом разделе рассказывается о том, как использовать файлы Dockerfile с контейнерами Windows, а также объясняются наиболее распространенные инструкции и базовый синтаксис таких файлов.

Здесь также рассматривается концепция образов контейнеров и их слоев. Дополнительные сведения об образах и их слоях см. в документации по базовым образам контейнеров.

Полный обзор файлов Dockerfile см. в справке по Dockerfile на странице .

Базовый синтаксис

Файл Dockerfile необходимо создавать без расширения. Чтобы сделать это в Windows, создайте файл с помощью удобного для вас редактора, а затем сохраните его, используя нотацию "Dockerfile" (вместе с кавычками).

Дополнительные примеры файлов Dockerfile для Windows см. в репозитории файлов Dockerfile для Windows.

Инструкция

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

Формат инструкции FROM выглядит следующим образом:

Ниже приведен пример команды FROM.

Чтобы загрузить Windows Server Core версии ltsc2019 из Реестра контейнеров (Майкрософт):

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

Инструкция RUN выглядит следующим образом:

Различие между формой исполняемого файла (exec form) и формой оболочки (shell form) заключается в способе выполнения инструкции RUN . При использовании формы исполняемого файла указанная программа запускается явным образом.

Ниже приведен пример формы исполняемого файла.

Полученный образ выполняет команду powershell New-Item c:/test :

В отличие от предыдущего примера здесь та же операция выполняется с использованием формы оболочки:

Полученный образ содержит инструкцию RUN cmd /S /C powershell New-Item c:\test .

Рекомендации по использованию инструкции RUN с Windows

В Windows при использовании инструкции RUN в формате исполняемого файла необходимо экранировать инструкции символы обратной косой черты.

Если целевая программа является установщиком Windows, чтобы запустить фактическую процедуру (автоматической) установки, необходимо извлечь программу установки, используя флаг /x:<directory> . Прежде чем выполнять какие-либо другие действия, необходимо дождаться завершения выполнения команды. В противном случае процесс будет завершен преждевременно и без установки. Дополнительные сведения см. в приведенном ниже примере.

Примеры использования инструкции RUN с Windows

В следующем примере для установки служб IIS в образе контейнера используется система DISM.

Этот пример устанавливает распространяемый пакет Visual Studio. Start-Process и параметр -Wait используются для запуска программы установки. Это гарантирует, что установка будет завершена до перехода к следующей инструкции в Dockerfile.

Подробные сведения об инструкции RUN см. в справочнике по RUN на странице .

Инструкция COPY копирует файлы и каталоги в файловую систему контейнера. Эти файлы и каталоги должны иметь путь, являющийся относительным для Dockerfile.

Формат инструкции COPY выглядит следующим образом:

Если источник или назначение содержит пробел, заключите путь в квадратные скобки и двойные кавычки, как показано в следующем примере:

Рекомендации по использованию инструкции COPY с Windows

В Windows для путей назначения необходимо использовать символы косой черты. Например, здесь показаны допустимые инструкции COPY .

При этом следующий формат с обратными косыми чертами работать не будет:

Примеры использования инструкции COPY с Windows

В следующем примере содержимое исходного каталога добавляется в каталог с именем sqllite в образе контейнера.

В следующем примере все файлы, начинающиеся с config, добавляют в каталог c:\temp образа контейнера.

Дополнительные сведения об инструкции COPY см. в справочнике по инструкции COPY.

ДОБАВИТЬ

Инструкция ADD похожа на инструкцию COPY, но с дополнительными возможностями. Кроме копирования файлов с узла в образ контейнера, инструкция ADD также позволяет скопировать файлы из удаленного расположения с помощью задания URL-адреса.

Формат инструкции ADD выглядит следующим образом:

Если источник или назначение содержит пробел, заключите путь в квадратные скобки и двойные кавычки.

Рекомендации по выполнению инструкции ADD с Windows

В Windows для путей назначения необходимо использовать символы косой черты. Например, здесь показаны допустимые инструкции ADD .

При этом следующий формат с обратными косыми чертами работать не будет:

Кроме того, в системе Linux во время копирования инструкция ADD распаковывает сжатые пакеты. В Windows эта функция недоступна.

Примеры использования инструкции ADD с Windows

В следующем примере содержимое исходного каталога добавляется в каталог с именем sqllite в образе контейнера.

В следующем примере все файлы, начинающиеся с "config", добавляют в каталог c:\temp образа контейнера.

В этом примере Python для Windows скачивается в каталог c:\temp образа контейнера.

Дополнительные сведения об инструкции ADD см. в справочнике по инструкции ADD.

WORKDIR

Инструкция WORKDIR задает рабочий каталог для других инструкций Dockerfile, например RUN и CMD , а также рабочий каталог для запущенных экземпляров образа контейнера.

Формат инструкции WORKDIR выглядит следующим образом:

Рекомендации по использованию инструкции WORKDIR с Windows

Если в Windows рабочий каталог содержит обратную косую черту, ее следует экранировать.

Примеры

Подробные сведения об инструкции WORKDIR см. в справочнике по WORKDIR.

Инструкция CMD задает команду по умолчанию, выполняемую при развертывании экземпляра образа контейнера. Например, если в контейнере будет размещен веб-сервер NGINX, CMD может включать инструкции для запуска этого веб-сервера, например с помощью команды nginx.exe . Если в файле Dockerfile указано несколько инструкций CMD , вычисляется только последняя из них.

Формат инструкции CMD выглядит следующим образом:

Рекомендации по использованию инструкции CMD с Windows

В Windows для путей к файлам, указанным в инструкции CMD , следует использовать символы косой черты или экранировать символы обратной косой черты \\ . Допустимы следующие инструкции CMD :

Однако следующий формат без соответствующих косых черт работать не будет:

Дополнительные сведения об инструкции CMD см. в справочнике по инструкции CMD.

Escape-символ

Во многих случаях инструкция Dockerfile должна занимать несколько строк. Для этого можно использовать escape-символ. Escape-символ Dockerfile по умолчанию — обратная косая черта ( \ ). Однако, поскольку обратная косая черта также является разделителем пути к файлу в Windows, использование его для разделения нескольких строк может вызвать проблемы. Чтобы их избежать, можно изменить escape-символ по умолчанию с помощью директивы анализатора. Дополнительные сведения о директивах анализатора см. в этом разделе.

В следующем примере показана инструкция RUN, которая занимает несколько строк и использует escape-символ по умолчанию.

Чтобы изменить escape-символ, поместите директиву Parser для escape-символа на первую строку Dockerfile. Это показано в следующем примере.

В качестве escape-символов можно использовать только символы: \ и ` .

Дополнительные сведения о директиве анализатора для escape-символа см. в этом разделе.

PowerShell в Dockerfile

Командлеты PowerShell

Командлеты PowerShell можно выполнять в Dockerfile при помощи операции RUN .

Вызовы REST

При сборе данных или файлов из веб-службы удобно использовать командлет PowerShell Invoke-WebRequest . Например, при сборке образа, включающего Python, можно задать для $ProgressPreference значение SilentlyContinue , чтобы ускорить загрузку, как показано в следующем примере.

Invoke-WebRequest также работает на сервере Nano Server.

Сейчас Nano Server не поддерживает WebClient.

Сценарии PowerShell

В некоторых случаях удобно скопировать крипт в контейнеры, используемые при создании образа, и затем запустить его из контейнера.

Это ограничивает возможности кэширования слоев образов, а также ухудшает удобочитаемость файла Dockerfile.

Этот пример копирует сценарий с компьютера сборки в контейнер с помощью инструкции ADD . Затем этот сценарий выполняется с помощью инструкции RUN.

Команда Docker build

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

Формат команды docker build выглядит следующим образом:

Например, следующая команда создает образ с именем "iis".

При инициации процесса сборки в выходных данных указывается состояние и выводятся все возникающие ошибки.

В результате создается новый образ контейнера, который в этом примере носит имя "iis".

Это третья часть серии статей про Docker и она всецело посвящена Docker-файлам. В первой части основные концепции Docker объясняются на простых примерах из жизни. Во второй статье — краткий обзор экосистемы Docker.

Docker-образы

Docker-образ создаётся во время сборки, а Docker-контейнер — во время запуска приложения.

Каждый Docker-образ содержит файл с именем Dockerfile (он без расширения). При вызове docker build предполагается, что Dockerfile будет находиться в текущей рабочей директории. Но с помощью флага -f можно указать другое расположение.

Sportmaster Lab , Санкт-Петербург , От 170 000 до 250 000 ₽

При загрузке Docker-образа из удалённого репозитория скачиваются только отсутствующие у вас слои. Docker экономит место и время, повторно используя уже существующие слои.

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

Эта статья предполагает использование Unix Docker-образа. Вы, конечно, можете использовать и Windows Docker-образ, но он медленнее, менее удобный и, вообще, его не часто применяют. Так что, пользуйтесь Unix по возможности.

Несколько Docker-инструкций

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

Docker-файл чисто теоретически может содержать только одну строчку:

В этом примере хранилище образов — Ubuntu. Ubuntu — название официального Docker-репозитория, в котором и содержится данная ОС.

Заметьте, что этот Docker-файл содержит тег для базового образа: 18.04, который указывает Docker’у, какую именно версию образа нужно использовать. Если тег не указан, по умолчанию берётся последняя версия образа. Но лучше всё же указывать тег базового образа. Когда Docker-файл, приведённый выше, используется для создания локального Docker-образа впервые, он загружает слои, указанные в образе Ubuntu.

При создании Docker-контейнера, вы помещаете наверх слой, который впоследствии можно будет изменить.

Когда образ запущен, и нужно произвести некоторые изменения, файл копируется на верхний слой, доступный для редактирования. Узнать, как это делается, можно здесь.

Подробнее про Docker-файл

Кроме того, что ваш однострочный образ сжат, он ещё и медленный, предоставляет мало информации и ничего не делает во время запуска контейнера. Посмотрите на более длинный Docker-файл, который запускает более легковесный образ, а также выполняет скрипт во время запуска.

Но что же это всё обозначает?

В роли базового образа выступает официальный Python-образ с тегом 3.7.2-alpine3.8. Как вы можете увидеть из исходников, образ включает в себя Linux, Python и ничего более. Alpine-образы очень популярны, потому что они маленькие, быстрые и безопасные. Однако Alpine-образы не поставляются сразу со всеми компонентами, характерными для вашей ОС. Некоторые пакеты вам придётся установить самостоятельно.

LABEL

Следующая инструкция — LABEL . LABEL добавляет метаданные к образу, предоставляет контактную информацию. Она не замедляет процесс запуска и не занимает много места, наоборот, обеспечивает образ полезной информацией, так что обязательно используйте её. Больше про LABEL читайте здесь.

ENV создаёт переменную окружения, которая становится доступной во время запуска контейнера. В примере выше вы могли видеть использование переменной ADMIN при создании контейнера.

ENV удобна для обозначения констант. Если константа используется в нескольких местах файла Dockerfile, и вам понадобится изменить её значение позднее, это можно будет сделать в одном месте.

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

RUN создаёт слой во время запуска. Docker фиксирует состояние образа после каждой инструкции RUN .

apk — это сокращение от Alpine Linux package manager. Если вы используете базовый образ не Alpine Linux, то установка пакетов производится командой RUN apt-get .

RUN и её родственные инструкции: CMD , ENTRYPOINT — могут быть как форме оболочки, так и в форме shell-скрипта. Во втором случае используют JSON-синтаксис: RUN ["my_executable", "my_first_param1", "my_second_param2"] . А в примере выше использовалась форма оболочки: RUN apk update && apk upgrade && apk add bash .

Позднее в вашем Docker-файле вы будете создавать новую директорию, используя ["mkdir", "/a_directory"] . Не забывайте, что в JSON нужно использовать двойные кавычки!

Инструкция COPY . ./app говорит Docker’у, что нужно скопировать файлы и папки из вашей локальной сборки в рабочую директорию образа. COPY создаст все нужные папки, если они отсутствуют.

ADD делает то же самое, что и COPY , но с двумя отличиями. ADD может загружать файлы по URL, а также извлекать локальные TAR-файлы.

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

CMD — инструкция для запуска чего-либо во время запуска самого контейнера. По ходу сборки она не фиксирует никакого результата. В примере выше во время сборки запускался скрипт my_script.py .

Ещё пара моментов о CMD :

  • Только одна CMD -инструкция на весь Docker-файл. Иначе все кроме последней будут проигнорированы;
  • CMD может включать исполняемый файл;
  • Если же CMD не содержит никакого файла, обязательно должна быть инструкция ENTRYPOINT . В этом случает обе инструкции должны быть в формате JSON;
  • Аргументы командной строки для запуска Docker переопределяют аргументы, предоставленные CMD в Docker-файле.

Готовы к большему?

В следующем примере представлены ещё несколько Docker-инструкций:

Для Alpine Docker-образа вы используете apk. apk для типичной Linux-сборки — apt-get . Например, пакеты для базового Ubuntu-образа могут быть установлены и обновлены так: RUN apt-get update && apt-get install my_package .

В дополнение к apk и apt-get , Python-пакеты могут быть установлены через pip, wheel и conda. Методы варьируются в зависимости от языка.

Нижележащие слои должны предоставить свое средство установки и управления пакетами. Если возникнет проблема с установкой пакетов, убедитесь, что у вас установлен менеджер пакетов.

Можно использовать RUN вместе с pip и списком нужных пакетов. Для этого объедините команды установки пакетов в одну инструкцию и разделите их символом продолжения строки ( \ ). Этот метод позволяет улучшить читаемость и уменьшить количество слоев (из-за отсутствия возможности использовать несколько RUN инструкций).

Также вы можете запустить установщик, указав ему файл, содержащий все зависимости для вашего образа. Обычно он называется requirements.txt.

WORKDIR

Меняет текущую рабочую директорию в контейнере для инструкций: COPY , ADD , RUN и ENTRYPOINT .

  • Предпочтительно задать абсолютный путь с помощью WORKDIR, а не перемещаться по файловой системе с помощью команд cd в Docker-файле;
  • WORKDIR автоматически создаёт директорию, если её ещё нет;
  • Можно использовать несколько WORKDIR -инструкций. Если используются относительные пути — каждая инструкция поменяет рабочую директорию.

Определяет переменную для передачи из командной строки в образ. Для ARG можно указать значение по умолчанию: ARG my_var=my_default_value .

В отличие от ENV -переменных, ARG -переменные не доступны для запущенных контейнеров. Однако вы можете использовать их для установки дефолтных значений для ENV -переменных, когда вы создаёте образ. И затем ENV-переменные сохраняются. Больше про это вы найдёте здесь.

ENTRYPOINT

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

Вместо этого аргументы командной строки, передаваемые docker run myimagename , добавляются к аргументам инструкции ENTRYPOINT . Например, docker run my_image bash добавляет аргумент bash в конец, ко всем другим аргументам ENTRYPOINT .

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

  • Если вам нужно запускать одну и туже команду несколько раз, выбирайте ENTRYPOINT ;
  • Используйте ENTRYPOINT , когда ваш контейнер выступает в роли исполняющейся программы;
  • При наличии дополнительных дефолтных аргументов, которые могут быть изменены через командную строку, лучше подойдёт CMD .

В примере выше, ENTRYPOINT ["python", "my_script.py", "my_var"] запускает в контейнере Python-скрипт my_script.py с аргументом my_var . Затем переменная my_var может быть использована в my_script argparse. Заметьте, у my_var есть дефолтное значение, ранее установленное в Docker-файле при помощи ARG . Так что, если аргумент не будет задан через командную строку, возьмётся его значение по умолчанию.

Как правило, Docker рекомендует вам использовать исполняемую форму с JSON-синтаксисом ENTRYPOINT ["executable", "param1", "param2"] .

EXPOSE

Инструкция EXPOSE показывает, какой порт пробрасывать из контейнера.

Используйте команду docker run с флагом -p для пробрасывания и сопоставления нескольких портов во время запуска. Флаг в верхнем регистре -P будет пробрасывать все открытые порты.

VOLUME

VOLUME определяет, где контейнер будет хранить постоянные данные и получать к ним доступ.

Заключение

В этой статье не были упомянуты такие инструкции, как USER , ONBUILD , STOPSIGNAL , SHELL , и HEALTHCHECK , информацию про них вы сможете найти здесь.

Dockerfile — это текстовый файл, в котором описан рецепт создания образа Docker. Рецепт состоит из инструкций, которые выполняются последовательно. Они содержат информацию об операционной системе, выбранной платформе, фреймворках, библиотеках, инструментах, которые нужно установить.

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

Как понять

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

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

Инструкции записываются построчно. На первом месте указывается команда для Docker, которую нужно выполнить, а затем — список аргументов этой команды:

Образ Docker легче всего представить в виде слоёного пирога или бургера: новый слой — новая инструкция. Образы для типичного веб-приложения могут быть собраны примерно так:

Примеры образов Docker для веб-приложений

Каждая новая инструкция — новый слой. В качестве инструкции можно выполнить команду в терминале, скопировать файлы внутрь образа или настроить связь с внешним миром с помощью сетевого окружения и томов. Docker объединяет файловые системы отдельных слоёв в одну во время сборки, используя механизм Union File Systems.

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

После того как слои образа описаны в файле конфигурации, необходимо произвести сборку образа с помощью команды:

Как пишется

Работу с Dockerfile можно разбить на два этапа: описание инструкций и сборка образа. Набор инструкций — последовательность действий, чтобы собрать образ.

Описание инструкций Dockerfile

FROM . Установка базового образа

Dockerfile обычно начинается с инструкции FROM . Эта инструкция задаёт базовый образ.

В качестве базового образа может быть использован образ с чистой операционной системой, образ с уже установленной и настроенной платформой или вообще любой другой образ. Вот так можно установить Ubuntu 18.04 как базовый образ:

RUN . Запуск команд терминала

Инструкция RUN позволяет запускать команды терминала при сборке. Это самая используемая инструкция, ей можно создать папку, установить недостающие пакеты или запустить shell скрипт.

Например, установим платформу Node.js поверх образа с чистой Ubuntu:

При сборке образа теперь будет произведена установка последней версии Node.js.

COPY и ADD . Копирование файлов проекта

Инструкции COPY и ADD позволяют перенести файлы с компьютера, который запускает сборку, внутрь образа.

Например, перенесём все содержимое папки, где лежит Dockerfile в папку /app внутри образа:

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

ENTRYPOINT и CMD . Запуск приложения

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

Инструкция ENTRYPOINT используется для запуска приложения при старте контейнера:

В отличие от инструкции RUN эта инструкция получает полный доступ к инфраструктуре терминала на компьютере пользователя. Вместе с командой запуска контейнера вы можете передавать параметры команде, которая прописана после ENTRYPOINT или пользоваться системой сигналов Linux. Внутрь образа можно положить программу и запускать её внутри контейнера, передавая через параметры текстовые файлы со своего компьютера. Например, можно упаковать в контейнер утилиту для проверки орфографии yaspeller. В примере ниже она используется для проверки орфографии слов на русском и английском языках в файлах с расширением *.md и *.txt :

Затем необходимо собрать образ, указав явно имя образа для удобства:

Запускать проверку орфографии в любой папке для файлов с расширением *.md и *.txt можно теперь простой командой:

Вместо . можно писать название файла или папки. Ключ --rm означает, что после завершения работы контейнер удалится из списка использованных Docker. Это важно, поскольку, пока контейнер хранится в этом списке, нельзя запустить контейнер с таким же именем, несмотря на то, что контейнер уже отработал и не используется.

Инструкция CMD делает практически то же самое. Обычно это также команда запуска приложения:

CMD — инструкция запуска по умолчанию, она игнорируется в том случае, если пользователь вашего образа прописывает в явном виде, что и как запускать после запуска контейнера на основе образа. Обычно CMD вообще используется для передачи параметров по умолчанию вашему приложению, которые пользователь может переопределить.

В чем же разница между ENTRYPOINT и CMD ? В ваших намерениях.

Используйте ENTRYPOINT , если вы не хотите, чтобы пользователь вашего образа переопределял поведение приложения в контейнере. Используйте CMD , если записываете команду по умолчанию, которую пользователь с лёгкостью может переопределить на этапе запуска контейнера.

Есть две формы записи аргументов ENTRYPOINT и CMD : в виде строки и в виде массива строк. Первый вариант (так называемый shell режим) используется редко, поскольку не позволяет гибко настраивать работу образа. Обычно используется второй вариант (так называемый exec режим) — массив строк, который может состоять из команды и её параметров. Среди аргументов инструкции CMD строка с командой может и отсутствовать, если эта инструкция идёт после инструкции ENTRYPOINT . В этом случае строки массива рассматриваются как аргументы по умолчанию для команды, обозначенной в ENTRYPOINT .

ENV . Переменные окружения

Переменные окружения задаются инструкцией ENV .

Через переменные окружения передают ключи и пароли к сервисам, режим работы, другие секретные и не очень значения. Например, запуск приложения Node.js для конечного пользователя обозначается дополнительной инструкцией:

WORKDIR . Рабочая папка проекта

Инструкция WORKDIR задаёт рабочую папку приложения. Все инструкции в Dockerfile будут выполняться относительно неё.

Устанавливать рабочую папку — хороший тон. Она позволяет явно указать место, где будет происходить вся работа. Добавим её в нашу конфигурацию:

USER . Запуск от имени пользователя

Если приложение нужно запускать от имени пользователя системы, то используйте инструкцию USER с именем пользователя. Например, если вы хотите запускать приложение от имени пользователя node_user , то конфигурационный файл будет выглядеть так:

EXPOSE . Проброска порта вовне

Проброска портов образов Docker для веб-приложений

EXPOSE незаменим, когда в образе находится база данных и нам нужен доступ к ней вне контейнера. Для этого используется инструкция EXPOSE :

ARG . Аргументы командной строки

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

Передавать данные можно с помощью аргументов команды docker build на этапе сборки образа. Во время сборки эти аргументы можно использовать как переменные, достаточно их определить инструкцией ARG . Можно задать и значения по умолчанию на тот случай, если пользователь не укажет нужные аргументы. Например, передать имя пользователя внутрь контейнера можно следующим образом:

В Dockerfile надо будет добавить соответствующие инструкции:

Важно, что так не следует передавать секретные данные, поскольку их можно будет увидеть в истории Docker:

Для безопасной передачи секретных данных лучше использовать тома Docker.

Многоступенчатая сборка образа

С точки зрения оптимизации сборки, уменьшения размера образа и ускорения приложения, образ можно собирать в несколько этапов. Например, с помощью платформы Node.js произвести сборку веб-приложения на первом этапе, а на втором — запустить готовый бандл с помощью веб-сервера. Операция копирования из первого промежуточного образа во второй целевой пройдёт совершенно незаметно. После сборки образ будет занимать мало дискового пространства, в нем будет все самое необходимое для работы веб-приложения:

Имя промежуточного образа build-stage служит для передачи результата работы первой стадии сборки.

Рекомендации

Для того чтобы использовать образы эффективнее, необходимо следовать рекомендациям от команды Docker:

  1. Нужно создавать образы так, чтобы жизненным циклом контейнера можно было удобно управлять. Образ не должен хранить внутреннее состояние. Данные внутрь образа можно передать на этапе сборки с помощью аргументов командной строки, а на этапе работы контейнера можно пользоваться томами Docker.
  2. Необходимо понимать контекст запуска веб-приложения: папка проекта, удалённый ресурс (remote source) или репозиторий.
  3. Надо понимать, что Dockerfile может запускаться вне контекста через стандартный поток ввода.
  4. Используйте файл .dockerignore для того, чтобы в образ попадали только нужные файлы и папки. От всего лишнего лучше избавиться на этапе сборки.
  5. Используйте сборку приложения в несколько стадий. Это позволит существенно уменьшить размер образа.
  6. Не устанавливайте то, что не будете использовать в образе.
  7. Необходимо разделять приложения на обособленные части, которые способны выполняться независимо. Этот процесс носит название декаплинга (Decoupling).
  8. Минимизируйте количество слоёв в образе. Это повышает производительность образа как при сборке, так и при работе контейнера.
  9. Если параметры инструкции записываются в несколько строк (с помощью символа переноса строки \ ) необходимо выстраивать аргументы в алфавитном порядке. Это повышает читаемость файла и упрощает отладку.
  10. Используйте кэш Docker только для тех слоёв, которые будут нужны для сборки других образов. Для этого достаточно добавить параметр --no-cache=true в команду сборки docker build .

Сборка образа

Образ Docker можно собрать тремя способами:

– указав путь к папке PATH ;
– указав путь к репозиторию URL ;
– используя стандартный поток ввода – .

Чаще всего используется первый способ с указанием пути. Самая простая команда для сборки образа:

С помощью этой команды собираться образ будет из текущей папки ( . в конце), в которой должен быть Dockerfile .

Использование нескольких Dockerfile

Иногда возникает необходимость использования нескольких вариантов сборок в одном проекте. В этом случае не обойтись без нескольких файлов с инструкциями. При сборке можно указать другое имя для файла конфигурации или относительный путь внутри PATH , нужно использовать флаг -f :

Точно так же можно указать относительный путь для проекта или репозитория по некоторому URL . Например, Docker может скачать не только репозиторий GitHub, но и произвольный архив с проектом, распаковать его и собрать образ:

Поддерживаются архивы форматов bzip2, gzip, xz.

Файлы и папки проекта, исполняемый файл приложения, архив или репозиторий Git составляют контекст образа. Но Docker позволяет собирать образы без контекста из стандартного потока ввода. Собрать такой образ можно командой:

Исключение файлов из сборки .dockerignore

Если вам не нужно включать в образ какие-то папки или файлы из контекста , добавьте в папку файл исключений .dockerignore . В этом файле перечисляются в отдельных строках все пути или маски путей, которые не должны быть помещены в образ. Пример файла:

– */temp позволяет не включать в образ файлы или папки, имена которых начинаются на temp , и которые находятся в любой папке первого уровня (например, /somedir/temporary.txt или /somedir/temp );
– */*/temp* — делает то же, но для папок второго уровня;
– temp? — позволяет не включать в образ файлы и папки из корневой папки образа, имена которых начинаются на temp и состоят из пяти символов, последний из которых может быть любым.

На практике

Игорь Коровченко

🛠 При сборке образа Docker ищет файл с исключениями, исходя из имени основного файла конфигурации. Например, команда docker build -f myapp.Dockerfile . будет в первую очередь искать файл исключений по пути myapp.Dockerfile.dockerignore . Если такого файла не найдётся, то при наличии будет использоваться .dockerignore .

🛠 Все объекты Docker обязательно имеют имя. Если оно не назначается пользователем, то в качестве имени используется хэш. Чтобы работать с образами было удобнее, лучше выбирать имя. Кроме имени можно также использовать теги. Обычно теги указывают на версию или особенности той или иной сборки образа. Совокупность образов с одним именем, но разными тегами, — это репозиторий образов. Например, можно собрать образ с указанием имени и тега командой:

Имя образа vieux/apache использует принятое в терминологии Docker соглашение. До слэша / указывается имя пользователя, после — имя образа или репозитория образов. В качестве имени пользователя чаще всего подразумевается имя пользователя в реестре репозиториев. Исторически первым и самым крупным является официальный реестр компании Docker — Docker Hub.

После двоеточия : можно указать тег. В примере этот тег обозначает версию сборки, но теги также могут указывать и на вариант образа, например, на основе Alpine Linux или Ubuntu. Вы можете указать с помощью тега, что версия базового образа должна быть последней, и в момент сборки именно она попадёт в образ.

🛠 Важно отслеживать размер образа, и пользоваться образами с умом. Вы можете загрузить к себе образ командой pull . Например, для образа Node.js:

Уже на этапе клонирования образа вы увидите его размер. После скачивания и установки также можно получить информацию об образе с помощью команды:

Читайте также: