Продвинутые директивы Dockerfile

В этой статье мы рассмотрим директивы Dockerfile, которые можно использовать для создания более сложных образов Docker.

Например, с помощью директивы VOLUME можно привязать файловую систему хост-машины к контейнеру Docker. Это позволит нам сохранять данные, генерируемые и используемые контейнером Docker, локально.

Мы рассмотрим следующие директивы:

Директива ENV

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

Переменные окружения определяются в следующем формате:

ENV <key> <value>

Например, с помощью директивы ENV можно задать путь:

ENV PATH $PATH:/usr/local/app/bin/

Мы можем установить несколько переменных окружения в одной строке, разделяя их пробелами. Однако в этом случае ключ и значение должны быть разделены символом равенства (=):

ENV <key>=<value> <key=value> ...

Ниже мы задаем конфигурацию двух переменных окружения. Переменная PATH имеет значение $PATH:/usr/local/app/bin, а переменная VERSION — 1.0.0:

ENV PATH=$PATH:/usr/local/app/bin/ VERSION=1.0.0

Если переменная окружения задана директивой ENV в Dockerfile, она становится доступной во всех последующих слоях образа Docker. Она будет доступна даже в Docker-контейнерах, запускаемых из этого Docker-образа.

Директива ARG

Директива ARG в Dockerfile используется для определения переменных, которые пользователи могут передавать сборщику во время сборки с помощью команды docker build. Эти переменные ведут себя аналогично переменным окружения и могут использоваться во всем Dockerfile, но не сохраняются в конечном образе, если не объявлены явно с помощью директивы ENV.

Директива ARG имеет следующий формат:

ARG <varname>

Можно добавить и несколько директив ARG:

ARG USER
ARG VERSION

Эти аргументы также могут иметь необязательные значения по умолчанию, указанные в самом Dockerfile. Если в процессе сборки пользователь не указывает значение, Docker использует значение по умолчанию, определенное в директиве ARG:

ARG USER=TestUser
ARG VERSION=1.0.0

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

Использование директив ENV и ARG в Dockerfile

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

Создайте новый каталог с именем env-arg-example с помощью команды mkdir:

mkdir env-arg-example

Перейдите в только что созданный каталог env-arg-example с помощью команды cd:

cd env-arg-example

Теперь давайте создадим новый Dockerfile. Я использую VS Code, но вы можете использовать любой удобный для вас редактор:

code Dockerfile

Добавьте в Dockerfile следующее содержимое:

ARG TAG=latest
FROM ubuntu:$TAG
LABEL maintainer=ananalogguyinadigitalworld@example.com
ENV ENVIRONMENT=dev APP_DIR=/usr/local/app/bin
CMD ["env"]

Сохраните файл и выйдите из редактора.

Dockerfile начинается с определения аргумента TAG со значением по умолчанию latest. Этот аргумент затем используется для указания базового образа в директиве FROM, в результате чего выбирается образ Ubuntu с меткой latest.

Директива LABEL добавляет метаданные к образу, указывая адрес электронной почты мейнтейнера. Далее директива ENV устанавливает две переменные окружения: ENVIRONMENT со значением dev и APP_DIR, указывающую на /usr/local/app/bin. Приложения, запущенные внутри контейнера, могут использовать эти переменные для настройки поведения в зависимости от окружения и путей к каталогам.

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

Теперь давайте соберем образ Docker:

docker image build -t env-arg --build-arg TAG=23.10 .

Вывод должен выглядеть примерно так:

[+] Building 34.9s (6/6) FINISHED                                                                                                            docker:default
 => [internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 189B                                                                                                                   0.0s
 => [internal] load metadata for docker.io/library/ubuntu:23.10                                                                                        3.3s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                                                          0.0s
 => [1/1] FROM docker.io/library/ubuntu:23.10@sha256:fd7fe639db24c4e005643921beea92bc449aac4f4d40d60cd9ad9ab6456aec01                                 31.6s
 => => resolve docker.io/library/ubuntu:23.10@sha256:fd7fe639db24c4e005643921beea92bc449aac4f4d40d60cd9ad9ab6456aec01                                  0.0s
 => => sha256:fd7fe639db24c4e005643921beea92bc449aac4f4d40d60cd9ad9ab6456aec01 1.13kB / 1.13kB                                                         0.0s
 => => sha256:c57e8a329cd805f341ed7ee7fcc010761b29b9b8771b02a4f74fc794f1d7eac5 424B / 424B                                                             0.0s
 => => sha256:77081d4f1e7217ffd2b55df73979d33fd493ad941b3c1f67f1e2364b9ee7672f 2.30kB / 2.30kB                                                         0.0s
 => => sha256:cd0bff360addc3363f9442a3e0b72ff44a74ccc0120d0fc49dfe793035242642 27.23MB / 27.23MB                                                      30.3s
 => => extracting sha256:cd0bff360addc3363f9442a3e0b72ff44a74ccc0120d0fc49dfe793035242642                                                              1.1s
 => exporting to image                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                0.0s
 => => writing image sha256:86b2f4c440c71f37c3f29f5dd5fe79beac30f5a6ce878bd14dc17f439bd2377d                                                           0.0s
 => => naming to docker.io/library/env-arg                                                                                                             0.0s

Теперь выполните команду docker container run, чтобы запустить новый контейнер из только что созданного нами образа Docker:

docker container run env-arg

В результате должно получиться что-то похожее на следующее:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=d6020a144f39
ENVIRONMENT=dev
APP_DIR=/usr/local/app/bin
HOME=/root

Директива WORKDIR

Директива WORKDIR в Dockerfile используется для задания текущего рабочего каталога для всех последующих инструкций в Dockerfile. Она помогает определить, где в контейнере будут выполняться такие команды, как ADD, CMD, COPY, ENTRYPOINT и RUN.

Формат директивы WORKDIR следующий:

WORKDIR /path/to/workdir

Если в образе нет указанной директории, Docker создаст ее в процессе сборки. Также директива WORKDIR эффективно сочетает в себе функциональность команд mkdir и cd в Unix-подобной системе. Она создает каталог, если он не существует, и меняет текущий каталог на указанный путь.

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

Например:

WORKDIR /one
WORKDIR two
WORKDIR three
WORKDIR drink

WORKDIR /one установит /one в качестве начального рабочего каталога. WORKDIR two затем изменит каталог на /one/two. WORKDIR three изменит его на /one/two/three. Наконец, WORKDIR drink изменит его на окончательный вариант /one/two/three/drink.

Директива COPY

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

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

COPY <source> <destination>

В <source> указывается путь к файлу или директории в вашей локальной файловой системе относительно контекста сборки. В <destination> указывается путь к файлу или каталогу, который должен быть скопирован в файловую систему образа Docker.

В следующем примере мы используем директиву COPY для копирования файла index.html из локальной файловой системы в каталог /var/www/html/ образа Docker:

COPY index.html /var/www/html/index.html

Мы также можем использовать знаки подстановки для копирования всех файлов, соответствующих заданному шаблону. Ниже мы скопируем все файлы с расширением .html из текущего каталога в каталог /var/www/html/ образа Docker:

COPY *.html /var/www/html/

При использовании директивы COPY в Dockerfile для переноса файлов из локальной файловой системы в образ Docker мы также можем указать флаг --chown. Этот флаг позволяет установить права пользователя и группы на скопированные файлы в образе Docker.

COPY --chown=myuser:mygroup *.html /var/www/html/

В этом примере --chown=myuser:mygroup указывает, что все файлы .html, копируемые из локальной директории в /var/www/html/ в образе Docker, должны принадлежать пользователю myuser и группе mygroup.

Директива ADD

Директива ADD в Dockerfile функционирует аналогично COPY, но с дополнительными возможностями.

ADD <source> <destination>

В <source> указывается путь или URL к файлу или каталогу в локальной файловой системе или удаленном URL. В <destination> снова указывается путь, по которому файл или каталог должен быть скопирован в файловую систему образа Docker.

Давайте применим ADD для копирования файла из локальной файловой системы:

ADD index.html /var/www/html/index.html

Здесь Docker скопирует файл index.html из локальной файловой системы (относительно контекста сборки Docker) в /var/www/html/index.html внутри образа Docker.

В примере ниже мы используем ADD для копирования файла с удаленного URL:

ADD http://example.com/test-data.csv /tmp/test-data.csv

В отличие от COPY, директива ADD позволяет указать URL (в данном случае http://example.com/test-data.csv) в качестве параметра <source>. Docker загрузит файл с URL и скопирует его в /tmp/test-data.csv внутри образа Docker.

Директива ADD не только копирует файлы из локальной файловой системы или загружает их с URL-адресов, но и включает возможность автоматического извлечения из некоторых архивов. Если <source> представляет собой сжатый архивный файл (например, .tar, .tar.gz, .tgz, .bz2, .tbz2, .txz, .zip), Docker автоматически извлечет его содержимое в <destination> в файловой системе образа Docker.

Например:

ADD myapp.tar.gz /opt/myapp/

В этом примере myapp.tar.gz — это сжатый архивный файл. Docker автоматически извлечет содержимое myapp.tar.gz в /opt/myapp/ внутри образа Docker.

Лучшие практики применения COPY и ADD в Dockerfile

При написании Dockerfile выбор между директивами COPY и ADD имеет решающее значение для обеспечения ясности, безопасности и надежности процесса сборки образа.

Четкость и ясность намерения

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

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

Безопасность и предсказуемость

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

Соответствие философии Docker

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

Использование директив WORKDIR, COPY и ADD в Dockerfile

В этом примере мы собираемся развернуть пользовательский HTML-файл на веб-сервере Apache. В качестве базового образа мы будем использовать Ubuntu, а поверх него установим Apache. Затем мы скопируем пользовательский файл index.html в образ Docker и загрузим логотип Docker.

Создайте новый каталог с именем workdir-copy-add-example и перейдите в него:

mkdir workdir-copy-add-example
cd .\workdir-copy-add-example\

В каталоге workdir-copy-add-example создайте файл с именем index.html. Этот файл будет скопирован в образ Docker во время сборки.

code index.html

Добавьте следующее содержимое в файл index.html, сохраните его и закройте редактор.

<html>
    <body>
        <h1>
            Welcome to Docker!
        </h1>
        <img src="logo.png" height="350" width="500"/>
    </body>
</html>

Этот HTML-код создает простую веб-страницу, которая приветствует посетителей большим заголовком «Welcome to Docker!». Под этим заголовком выводится изображение (с помощью тега <img> с атрибутом src="logo.png"). Эта картинка должна иметь размер 350 px в высоту и 500 px в ширину (height="350" и width="500").

Теперь давайте создадим в этой директории Dockerfile:

code Dockerfile

Добавьте в Dockerfile следующее содержимое, сохраните его и выйдите из редактора:

FROM ubuntu:latest
RUN apt-get update && apt-get upgrade
RUN apt-get install apache2 -y
WORKDIR /var/www/html/
COPY index.html .
ADD https://upload.wikimedia.org/wikipedia/commons/4/4e/Docker_%28container_engine%29_logo.svg ./logo.png
CMD ["ls"]

Этот Dockerfile начинается с FROM ubuntu:latest, что указывает на то, что образ будет строиться на основе последнего доступного базового образа Ubuntu. Последующие команды RUN apt-get update && apt-get upgrade обновляют списки пакетов внутри контейнера. После этого команда apt-get install apache2 -y устанавливает веб-сервер Apache с помощью менеджера пакетов. Директива WORKDIR устанавливает в качестве рабочего каталога /var/www/html/ — это обычное место для обслуживания веб-контента в Apache.

В этом каталоге команда COPY index.html . копирует локальный файл index.html с хост-машины в контейнер. Кроме того, ADD https://upload.wikimedia.org/wikipedia/commons/4/4e/Docker_%28container_engine%29_logo.svg ./logo.png извлекает файл SVG-изображения из URL и сохраняет его локально под именем logo.png в том же каталоге.

И наконец, CMD [«ls»] указывает, что при запуске контейнера будет выполняться команда ls, отображающая список файлов и каталогов в директории /var/www/html/.

Теперь создайте образ Docker с тегом workdir-copy-add:

docker build -t workdir-copy-add .

Вы должны увидеть следующий результат:

[+] Building 4.0s (13/13) FINISHED                                                                       docker:default
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 290B                                                                               0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                   3.6s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                      0.0s
 => [1/6] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc4362  0.0s
 => => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc4362  0.0s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 32B                                                                                   0.0s
 => https://upload.wikimedia.org/wikipedia/commons/4/4e/Docker_%28container_engine%29_logo.svg                     0.3s
 => CACHED [2/6] RUN apt-get update && apt-get upgrade                                                             0.0s
 => CACHED [3/6] RUN apt-get install apache2 -y                                                                    0.0s
 => CACHED [4/6] WORKDIR /var/www/html/                                                                            0.0s
 => CACHED [5/6] COPY index.html .                                                                                 0.0s
 => CACHED [6/6] ADD https://upload.wikimedia.org/wikipedia/commons/4/4e/Docker_%28container_engine%29_logo.svg .  0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:646864d79dc576f862a980ef6ddab550ef9801790d2c91967c3c9596cf85b81a                       0.0s
 => => naming to docker.io/library/workdir-copy-add                                                                0.0s

Выполните команду docker container run, чтобы запустить новый контейнер из созданного нами образа Docker:

docker run workdir-copy-add

Как видите, и index.html, и logo.png доступны в каталоге /var/www/html/:

index.html
logo.png

Директива USER

В Docker по умолчанию контейнеры запускаются с пользователем root, который обладает широкими привилегиями в контейнерной среде. Чтобы снизить риски безопасности, Docker позволяет нам указать пользователя, не являющегося root, с помощью директивы USER в Dockerfile. Эта директива задает пользователя по умолчанию для контейнера, и все последующие команды, указанные в Dockerfile, такие как RUN, CMD и ENTRYPOINT, будут выполняться в контексте этого пользователя.

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

Директива USER имеет следующий формат:

USER <user>

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

USER <user>:<group>

Нужно следить за тем, чтобы значения <user> и <group> были валидными именами пользователя и группы. В противном случае демон Docker выдаст ошибку при попытке запустить контейнер.

Использование директивы USER в Dockerfile

В этом примере мы будем использовать директиву USER в Dockerfile для установки пользователя по умолчанию. Мы установим веб-сервер Apache и изменим пользователя на www-data. Наконец, мы выполним команду whoami для проверки текущего пользователя.

Создайте новую директорию с именем user-example и перейдите в нее.

mkdir user-example
cd .\user-example\

В каталоге user-example создайте новый Dockerfile.

code Dockerfile

Добавьте следующее содержимое в свой Dockerfile, сохраните его и закройте редактор:

FROM ubuntu:latest
RUN apt-get update && apt-get upgrade
RUN apt-get install apache2 -y
USER www-data
CMD ["whoami"]

Этот Dockerfile начинается с указания последнего базового образа Ubuntu. Затем идут инструкции обновления системных пакетов перед установкой веб-сервера Apache (apache2). Далее мы повышаем безопасность, переключаясь на пользователя www-data, обычно используемого для веб-серверов, чтобы минимизировать потенциальные уязвимости. Благодаря директиве CMD [«whoami»] при запуске контейнера будет отображаться текущий пользователь (www-data).

Соберите образ Docker:

docker build -t user .

Вы должны увидеть следующий результат:

[+] Building 5.0s (8/8) FINISHED                                                                                                             docker:default
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 157B                                                                                                                   0.0s
 => [internal] load .dockerignore                                                                                                                      0.1s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                                                       4.8s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                                                          0.0s
 => [1/3] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30                                 0.0s
 => => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30                                 0.0s
 => CACHED [2/3] RUN apt-get update && apt-get upgrade                                                                                                 0.0s
 => CACHED [3/3] RUN apt-get install apache2 -y                                                                                                        0.0s
 => exporting to image                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                0.0s
 => => writing image sha256:ce1de597471f741f4fcae898215cfcb0d847aacf7c201690c5d4e95289476768                                                           0.0s
 => => naming to docker.io/library/user                                                                                                                0.0s

Теперь выполните команду docker container run user, чтобы запустить новый контейнер из созданного нами образа Docker. В выводе должен появиться www-data (текущий пользователь, связанный с контейнером Docker).

Директива VOLUME

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

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

Когда вы определяете том в Dockerfile с помощью директивы VOLUME, Docker создает управляемый каталог в файловой системе контейнера. Этот каталог служит точкой монтирования тома. Очень важно, что Docker также создает соответствующий каталог на хост-машине, где хранятся фактические данные тома. Такое сопоставление гарантирует, что любые изменения, внесенные в файлы тома из контейнера, будут немедленно синхронизированы с сопоставленным каталогом на хост-машине, и наоборот.

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

Директива VOLUME обычно принимает в качестве параметра массив JSON:

VOLUME ["path/to/volume"]

Или мы можем указать простую строку с несколькими путями:

VOLUME /path/to/volume1 /path/to/volume2

Для просмотра томов, доступных в контейнере, можно использовать команду docker container inspect <container>. В выходном JSON команды docker container inspect будет выведена информация о томах:

[
   {
      "CreatedAt":"2024-06-21T22:52:52+03:00",
      "Driver":"local",
      "Labels":null,
      "Mountpoint":"/var/lib/docker/volumes/f46f82ea6310d0db3a13897a0c3ab45e659ff3255eaeead680b48bca37cc0166/_data",
      "Name":"f46f82ea6310d0db3a13897a0c3ab45e659ff3255eaeead680b48bca37cc0166",
      "Options":null,
      "Scope":"local"
   }
]

Использование директивы VOLUME в Dockerfile

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

Создайте новый каталог с именем volume-example и перейдите в него.

mkdir volume-example
cd volume-example

Внутри каталога volume-example создайте новый Dockerfile.

code Dockerfile

Добавьте в Dockerfile следующее содержимое, сохраните его и выйдите из редактора.

FROM ubuntu:latest
RUN apt-get update && apt-get upgrade
RUN apt-get install apache2 -y
VOLUME ["/var/log/apache2"]

Этот Dockerfile начинается с использования последней версии Ubuntu в качестве базового образа. Далее обеспечивается ее обновление — запуск apt-get update и apt-get upgrade для обновления всех установленных пакетов. Затем устанавливается Apache HTTP Server (apache2) с помощью apt-get install apache2 -y. Директива VOLUME ["/var/log/apache2"] определяет том Docker по адресу /var/log/apache2, где Apache обычно хранит свои файлы логов.

Теперь давайте соберем образ Docker:

docker build -t volume .

На выходе должно получиться следующее:

[+] Building 3.6s (8/8) FINISHED                                                                                                             docker:default
 => [internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 155B                                                                                                                   0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                                                       3.5s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                                                          0.0s
 => [1/3] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30                                 0.0s
 => => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30                                 0.0s
 => CACHED [2/3] RUN apt-get update && apt-get upgrade                                                                                                 0.0s
 => CACHED [3/3] RUN apt-get install apache2 -y                                                                                                        0.0s
 => exporting to image                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                0.0s
 => => writing image sha256:9c7a81e379553444e0b4f3bbf45bdd17880aea251db8f8b75669e13964b9c30f                                                           0.0s
 => => naming to docker.io/library/volume  

Выполните команду docker container run, чтобы запустить новый контейнер из ранее созданного образа. Обратите внимание: чтобы выполнять команды из оболочки bash контейнера, вам также необходимо использовать флаги --interactive и --tty для открытия интерактивной сессии bash. Еще нужно использовать флаг --name, чтобы определить имя контейнера как volume-container.

docker container run --interactive --tty --name volume-container volume /bin/bash

Откроется ваша оболочка bash:

root@8aa0f5fb8a6d:/#

Перейдите в каталог /var/log/apache2.

root@8aa0f5fb8a6d:/# cd /var/log/apache2/

Это приведет к следующему результату:

root@8aa0f5fb8a6d:/var/log/apache2#

Теперь выведите список доступных файлов в каталоге:

root@8aa0f5fb8a6d:/var/log/apache2# ls -l

Результат должен быть следующим:

total 0
-rw-r----- 1 root adm 0 Jun 20 13:42 access.log
-rw-r----- 1 root adm 0 Jun 20 13:42 error.log
-rw-r----- 1 root adm 0 Jun 20 13:42 other_vhosts_access.log

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

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

root@8aa0f5fb8a6d:/var/log/apache2# exit

Просмотрите информацию о монтировании:

docker container inspect volume-container

Под ключом Mounts вы сможете увидеть информацию, относящуюся к монтированию.

"Mounts":[
    {
         "Type":"volume",
         "Name":"50d3a5abf34535fbd3a347cbd6c74acf87a7aa533494360e661c73bbdf34b3e8",
         "Source":"/var/lib/docker/volumes/50d3a5abf34535fbd3a347cbd6c74acf87a7aa533494360e661c73bbdf34b3e8/_data",
         "Destination":"/var/log/apache2",
         "Driver":"local",
         "Mode":"",
         "RW":true,
         "Propagation":""
    }
]

Проверьте том с помощью команды docker volume inspect <volume_name>. Имя <volume_name> можно найти в поле Name предыдущего вывода.

docker volume inspect 50d3a5abf34535fbd3a347cbd6c74acf87a7aa533494360e661c73bbdf34b3e8

Вы должны получить результат, аналогичный следующему:

[{
   "CreatedAt":"2024-06-21T11:02:32Z",
   "Driver":"local",
   "Labels":{
      "com.docker.volume.anonymous":""
   },
   "Mountpoint":"/var/lib/docker/volumes/50d3a5abf34535fbd3a347cbd6c74acf87a7aa533494360e661c73bbdf34b3e8/_data",
   "Name":"50d3a5abf34535fbd3a347cbd6c74acf87a7aa533494360e661c73bbdf34b3e8",
   "Options":null,
   "Scope":"local"
}]

Выведите список файлов, доступных по указанному пути на хосте. Этот путь можно найти в поле Mountpoint в предыдущем выводе.

ls -l /var/lib/docker/volumes/50d3a5abf34535fbd3a347cbd6c74acf87a7aa533494360e661c73bbdf34b3e8/_data

Директива EXPOSE

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

Директива EXPOSE поддерживает протоколы TCP и UDP, что позволяет гибко подходить к открытию портов для различных сетевых нужд. Эта директива является предшественницей опций -p или -P, используемых во время выполнения контейнера для сопоставления этих открытых портов с портами на хост-машине, обеспечивая внешний доступ, если это необходимо.

Директива EXPOSE имеет следующий формат:

EXPOSE <port>

Директива HEALTHCHECK

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

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

В Dockerfile может быть только одна директива HEALTHCHECK. Если директив HEALTHCHECK несколько, то в силу вступит только последняя.

Например, мы можем использовать следующую директиву, чтобы убедиться, что контейнер может принимать трафик на конечной точке http://localhost/:

HEALTHCHECK CMD curl -f http://localhost/ || exit 1

Код выхода в конце предыдущей команды используется для определения состояния здоровья контейнера, допустимые значения — 0 и 1. 0 означает работоспособный контейнер, 1 — неработоспособный.

При использовании директивы HEALTHCHECK в Docker можно настроить дополнительные параметры, выходящие за рамки основной команды, чтобы изменить способ проверки:

  • --interval. Указывает частоту выполнения проверок работоспособности. По умолчанию интервал составляет 30 секунд.
  • --timeout. Определяет максимальное время, в течение которого команда проверки работоспособности должна успешно завершиться. Если в течение этого времени не будет получено успешного ответа, проверка будет помечена как неудачная. Таймаут по умолчанию также установлен на 30 секунд.
  • --start-period. Указывает начальную задержку перед тем, как Docker начнет выполнять первую проверку работоспособности. Этот параметр дает контейнеру некоторое время на инициализацию перед началом проверки, по умолчанию — 0 секунд.
  • --retries. Определяет количество последовательных неудачных проверок работоспособности, после которых Docker будет считать контейнер неработоспособным. По умолчанию Docker разрешает до 3 повторных проверок.

В следующем примере значения HEALTHCHECK по умолчанию отменяются путем предоставления пользовательских значений:

HEALTHCHECK \
    --interval=1m \
    --timeout=2s \
    --start-period=2m \
    --retries=3 \
    CMD curl -f http://localhost/ || exit 1

Использование директив EXPOSE и HEALTHCHECK в Dockerfile

Мы собираемся докеризировать веб-сервер Apache, чтобы получить доступ к домашней странице Apache через браузер. Кроме того, мы настроим проверку для определения работоспособности веб-сервера Apache.

Создайте новую директорию с именем expose-heathcheck-example и перейдите в нее.

mkdir expose-healthcheck-example
cd .\expose-healthcheck-example\

Создайте Dockerfile и добавьте в него следующее содержимое:

FROM ubuntu:latest

RUN apt-get update && apt-get upgrade

RUN apt-get install apache2 curl -y

HEALTHCHECK CMD curl -f http://localhost/ || exit 1

EXPOSE 80

ENTRYPOINT ["apache2ctl", "-D", "FOREGROUND"]

Этот Dockerfile начинается с извлечения последнего базового образа Ubuntu и его обновления. Затем он устанавливает веб-сервер Apache и curl с помощью apt-get. Директива HEALTHCHECK устанавливается для запуска команды curl -f http://localhost/ || exit 1, проверяющей работоспособность контейнера относительно подключения к localhost. Порт 80 открыт, чтобы разрешить внешний доступ к Apache. Наконец, с помощью ENTRYPOINT [«apache2ctl», «-D», «FOREGROUND»] контейнер настроен на запуск Apache в режиме переднего плана. Это обеспечивает его активность и отзывчивость в качестве основного процесса. Такая настройка позволяет разместить веб-сервер, доступный через порт 80, в среде Docker.

Соберите образ.

docker image build -t expose-healthcheck-example .

Вы должны получить результат, похожий на следующий:

[+] Building 29.0s (8/8) FINISHED                                                                                                            docker:default
 => [internal] load build definition from Dockerfile                                                                                                   0.0s
 => => transferring dockerfile: 244B                                                                                                                   0.0s
 => [internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                                                       3.4s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                                                          0.0s
 => [1/3] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30                                 0.0s
 => => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30                                 0.0s
 => CACHED [2/3] RUN apt-get update && apt-get upgrade                                                                                                 0.0s
 => [3/3] RUN apt-get install apache2 curl -y                                                                                                         24.8s
 => exporting to image                                                                                                                                 0.6s
 => => exporting layers                                                                                                                                0.6s
 => => writing image sha256:3323e865b3888a4e45852c6a8c163cb820739735716f8783a0d126b43d810f1e                                                           0.0s
 => => naming to docker.io/library/expose-healthcheck-example                                                                                          0.0s

Выполните команду docker container run, чтобы запустить новый контейнер. Используйте флаги:

  • -p, чтобы перенаправить порт 80 хоста на порт 8080 контейнера,
  • --name, чтобы указать имя контейнера как expose-healthcheck-container,
  • -d, чтобы запустить контейнер в режиме отсоединения.
docker container run -p 8080:80 --name expose-healthcheck-container -d expose-healthcheck-example

Выведите список запущенных контейнеров с помощью команды docker container list.

В выводе вы увидите, что STATUS контейнера expose-healthcheck-container — healthy («здоров»).

CONTAINER ID   IMAGE                        COMMAND                  CREATED              STATUS                        PORTS                            NAMES
3ff16b11275c   expose-healthcheck-example   "apache2ctl -D FOREG…"   About a minute ago   Up About a minute (healthy)   80/tcp, 0.0.0.0:8080->8080/tcp   expose-healthcheck-container

Теперь вы должны иметь возможность просматривать домашнюю страницу Apache. Перейдите на конечную точку http://127.0.0.1:8080 из браузера.

Директива ONBUILD

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

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

Директива ONBUILD имеет следующий формат:

ONBUILD <instruction>

Для примера представим, что в Dockerfile пользовательского базового образа есть следующая инструкция ONBUILD:

ONBUILD ENTRYPOINT ["echo", "Running an ONBUILD Directive"]

Значение «Running an ONBUILD Directive» не будет выведено, если мы создадим Docker-контейнер из нашего пользовательского базового образа. Но оно выведется, если мы используем этот образ в качестве основы для другого образа Docker.

Использование директивы ONBUILD в Dockerfile

В этом примере мы соберем родительский образ с веб-сервером Apache и используем директиву ONBUILD для копирования HTML-файлов.

Создайте новую директорию с именем onbuild-parent-example и перейдите в нее:

mkdir onbuild-parent-example
cd .\onbuild-parent-example\

Создайте новый Dockerfile и добавьте в него следующее содержимое:

FROM ubuntu:latest

RUN apt-get update && apt-get upgrade

RUN apt-get install apache2 -y

ONBUILD COPY *.html /var/www/html

EXPOSE 80

ENTRYPOINT ["apache2ctl", "-D", "FOREGROUND"]

Этот Dockerfile начинается с использования последнего базового образа Ubuntu. Он обновляет и модернизирует системные пакеты, а затем устанавливает веб-сервер Apache. Директива ONBUILD указывает, что все дочерние образы, созданные на основе этого Dockerfile, будут автоматически копировать все HTML-файлы из контекста сборки в каталог /var/www/html внутри контейнера. Порт 80 открыт, чтобы разрешить входящий трафик на сервер Apache. Наконец, команда ENTRYPOINT настраивает контейнер на запуск Apache в режиме переднего плана, обеспечивая его активность и отзывчивость в качестве основного процесса. Эта настройка позволяет контейнеру обслуживать веб-контент через Apache на порту 80.

Теперь соберите образ Docker:

docker image build -t onbuild-parent-example .

Результат должен быть следующим:

[+] Building 3.5s (8/8) FINISHED                                                                         docker:default
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 221B                                                                               0.0s
 => [internal] load .dockerignore                                                                                  0.1s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                   3.3s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                      0.0s
 => [1/3] FROM docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc4362  0.0s
 => => resolve docker.io/library/ubuntu:latest@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc4362  0.0s
 => CACHED [2/3] RUN apt-get update && apt-get upgrade                                                             0.0s
 => CACHED [3/3] RUN apt-get install apache2 -y                                                                    0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:4a6360882fb65415cdd7326392de35c2336a8599c2c4b8b7a1e4d962d81df7e4                       0.0s
 => => naming to docker.io/library/onbuild-parent-example                                                          0.0s

Выполните команду docker container run, чтобы запустить новый контейнер из только что собранного образа Docker:

docker container run -p 8080:80 --name onbuild-parent-container -d onbuild-parent-example

Если вы перейдете на конечную точку http://127.0.0.1:8080/, вы увидите домашнюю страницу Apache.

Удалите контейнер, чтобы он не мешал работе портов:

docker container stop onbuild-parent-container
docker container rm onbuild-parent-container

Теперь создадим еще один образ Docker, используя onbuild-parent-container в качестве базового образа, для развертывания HTML-кода пользовательской домашней страницы. Для этого создадим новую директорию с именем onbuild-child-example.

cd ..
mkdir onbuild-child-example

Создайте новую html-страницу со следующим содержимым:

<html>

    <body>

        <h1>Demonstrating Docker ONBUILD Directive</h1>

    </body>

</html>

В том же каталоге создайте Dockerfile:

FROM onbuild-parent-example

Этот Dockerfile содержит единственную директиву. Благодаря директиве FROM в качестве базового образа будет использован образ Docker onbuild-parent-example, который мы создали ранее.

Теперь соберите образ Docker:

docker image build -t onbuild-child-example .

На выходе должно получиться что-то вроде следующего:

[+] Building 0.3s (7/7) FINISHED                                                                         docker:default
 => [internal] load .dockerignore                                                                                  0.1s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load build definition from Dockerfile                                                               0.1s
 => => transferring dockerfile: 64B                                                                                0.0s
 => [internal] load metadata for docker.io/library/onbuild-parent-example:latest                                   0.0s
 => [internal] load build context                                                                                  0.1s
 => => transferring context: 134B                                                                                  0.0s
 => [1/1] FROM docker.io/library/onbuild-parent-example                                                            0.1s
 => [2/1] COPY *.html /var/www/html                                                                                0.0s
 => exporting to image                                                                                             0.1s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:9fb3629a292e2536300724db933eb59a6fb918f9d01e46a01aff18fe1ad6fe69                       0.0s
 => => naming to docker.io/library/onbuild-child-example                                                           0.0s

Выполните команду docker container run, чтобы запустить новый контейнер из только что собранного образа Docker:

docker container run -p 8080:80 --name onbuild-child-container -d onbuild-child-example

Теперь вы должны иметь возможность просматривать нашу пользовательскую страницу index.html, перейдя на конечную точку http://127.0.0.1:8080/.

Резюме

В этой статье мы сосредоточились на создании образов Docker. Мы обсудили такие продвинутые директивы Dockerfile, как ENV, ARG, WORKDIR, COPY, ADD, USER, VOLUME, EXPOSE, HEALTHCHECK и ONBUILD.

Перевод статьи «Advanced Dockerfile Directives».

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх