Начало работы с Docker. Часть вторая
19.03.2020
Теги: CLI • Docker • Linux • Ubuntu • Виртуализация • Команда • Настройка • Процесс • Установка
Создание Dockerfile
Dockerfile
— конфигурационный файл, описывающий пошаговое создание среды для работы приложения. В этом файле подробно описывается какие образы задействованы, какие команды будут выполнены и какие настройки будут применены. А движок Docker-а при запуске уже прочитает этот файл и создаст соответствующий образ.
Создадим директорию app
в домашнем каталоге и разместим в нем два файла — script.php
и Dockerfile
:
$ cd ~ $ mkdir app $ cd app
$ nano script.php
<?php $n = $i = 5; while ($i--) { echo str_repeat(' ', $i).str_repeat('* ', $n - $i)."\n"; }
$ nano Dockerfile
FROM php:7.2-cli COPY script.php /script.php RUN chmod +x /script.php CMD php /script.php
Эти инструкции означают:
FROM
— использовать образ с предустановленнымphp:7.2-cli
(имя:тег
)COPY
— копировать файлscript.php
из основной системы внутрь контейнераRUN
— выполнить shell-команду в терминале контейнера (сделать скрипт исполняемым)CMD
— выполнять эту shell-команду каждый раз при запуске контейнера
Теперь создадим образ из Dockerfile
:
$ docker build . --tag php-cli-script
Эта команда создает образы из Dockerfile
и «контекста». Контекст сборки — это набор файлов, расположенных по указанному пути или URL. Процесс создания образа может ссылаться на любой из файлов в контексте. Например, инструкция COPY
будет искать файл по указанному пути. Мы используем точку, чтобы сообщить, что все файлы расположены в текущей директории. А опция --tag
позволяет задать имя образа (можно задать в виде имя:тег
).
Посмотрим список образов, сохраненных локально:
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE -------------------------------------------------------------------------------------------- php-cli-script latest 5e72190ee0b4 10 minutes ago 398MB tokmakov/apache2_ubuntu latest 18073a80c28b 23 hours ago 191MB php 7.2-cli 555ec78042a1 3 weeks ago 398MB ubuntu latest 72300a873c2c 3 weeks ago 64.2MB hello-world latest fce289e99eb9 14 months ago 1.84kB
Теперь все готово к запуску нового контейнера:
$ docker run php-cli-script * * * * * * * * * * * * * * *
При запуске контейнера можно указать дополнительные опции, например
$ docker run --rm ИмяОбраза # удалить контейнер при завершении $ docker run --name ИмяКонтейнера ИмяОбраза # присвоить контенеру имя
Наш php-скрипт был успешно скопирован, и выполнен благодаря указанной в Dockerfile
инструкции CMD
. Давайте проверим, что скрипт действительно был скопирован внутрь контейнера:
$ docker run php-cli-script ls bin ..... sbin script.php srv ..... var
Однако, сейчас этот контейнер недостаточно гибкий. Хотелось бы иметь возможность передать нашему скрипту аргументы, чтобы можно было изменять размер пирамиды.
$ nano script.php
<?php $n = $i = empty($argv[1]) ? 5 : $argv[1]; while ($i--) { echo str_repeat(' ', $i).str_repeat('* ', $n - $i)."\n"; }
$ docker build . --tag php-cli-script
$ docker run php-cli-script php /script.php 7 # переопределяем инструкцию CMD * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Но, было бы неплохо передавать этот аргумент самому контейнеру, вместо переписывания всей команды.
$ nano Dockerfile
FROM php:7.2-cli COPY script.php /script.php RUN chmod +x /script.php ENTRYPOINT ["php", "/script.php"] CMD ["10"]
Теперь аргументы инструкции CMD
будут добавлены к аргументам инструкции ENTRYPOINT
и получится
$ php /script.php 10 # интерпретатор php выполняет php-скрипт script.php, которому передается аргумент 10
Соберем образ заново, запустим контейнер и предадим ему аргумент:
$ docker build . --tag php-cli-script
$ docker run php-cli-script 8 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Основные инструкции Dockerfile
Для начала посмотрим на список инструкций Dockerfile
с краткими комментариями, а потом разберем их подробнее:
FROM
— задаёт базовый (родительский) образLABEL
— описывает метаданные (например, кто создал образ)ENV
— устанавливает постоянные переменные средыRUN
— выполняет команду и создаёт слой образаCOPY
— копирует в контейнер файлы и директорииADD
— копирует файлы и папки в контейнер, может распаковывать .tar-файлыCMD
— описывает команду с аргументами, которая выполняется при запуске контейнераWORKDIR
— задаёт рабочую директорию для следующей инструкцииARG
— задаёт переменные для передачи Docker во время сборки образаENTRYPOINT
— задает команду с аргументами для вызова во время выполнения контейнераEXPOSE
— указывает на необходимость открыть портVOLUME
— создаёт точку монтирования для работы с постоянным хранилищем
1. Инструкция FROM
сообщает Docker о том, чтобы при сборке образа использовался базовый образ, который соответствует предоставленному имени и тегу. Базовый образ, кроме того, ещё называют родительским образом.
FROM ubuntu:18.04
2. Инструкция LABEL
(метка) позволяет добавлять в образ метаданные. Как правило, она включает в себя контактные сведения создателя образа.
LABEL maintainer="somebody@somewhere.com"
3. Инструкция ENV
позволяет задавать постоянные переменные среды, которые будут доступны в контейнере во время его выполнения. Хорошо подходит для задания констант. Если некое значение используется несколько раз, имеет смысл записать его в константу.
ENV ADMIN="somebody"
Dockerfile
часто существуют разные способы решения одних и тех же задач. Например, инструкции RUN
, CMD
и ENTRYPOINT
служат разным целям, но все они используются для выполнения команд.
4. Инструкция RUN
позволяет создать слой во время сборки образа. После её выполнения в образ добавляется новый слой, его состояние фиксируется. Инструкция RUN
часто используется для установки в образы дополнительных пакетов.
# обновить пакеты RUN apt-get update && apt-get -y upgrade # создать директорию RUN ["mkdir", "/app"]
Инструкция RUN
и схожие с ней инструкции (CMD
и ENTRYPOINT
), могут быть использованы либо в exec-форме, либо в shell-форме. Exec-форма использует синтаксис, напоминающий описание JSON-массива:
# запустить exec-file с аргументами first и second
RUN ["exec-file", "first", "second"]
5. Инструкция COPY
позволяет копировать в образ файлы и директории. Если целевая директория не существует, она будет создана. Например, сообщим Docker о том, что нужно взять файлы и папки из локального контекста сборки и добавить их в рабочую директорию образа.
COPY . ./bin
6. Инструкция ADD
позволяет решать те же задачи, что и COPY
, но с ней связана ещё пара вариантов использования. Так, с помощью этой инструкции можно добавлять в контейнер файлы, загруженные из удалённых источников, а также распаковывать локальные tar-файлы.
7. Инструкция CMD
предоставляет Docker команду, которую нужно выполнить при запуске контейнера. Результаты выполнения этой команды не добавляются в образ во время его сборки. В одном файле Dockerfile
может присутствовать лишь одна инструкция CMD
.
Инструкция CMD
может иметь exec-форму. Если в эту инструкцию не входит упоминание исполняемого файла, тогда в файле должна присутствовать инструкция ENTRYPOINT
. В таком случае обе эти инструкции должны быть представлены в формате JSON.
docker run
, переопределяют аргументы, предоставленные инструкции CMD
в Dockerfile.
8. Инструкция WORKDIR
позволяет установить рабочую директорию, откуда будут запускаться команды ENTRYPOINT
и CMD
. Инструкция автоматически создаёт директорию в том случае, если она не существует. Кроме того, с помощью инструкции WORDDIR
можно создать контекст для инструкции COPY
:
WORKDIR /app COPY . .
9. Инструкция ARG
позволяет задать переменную, значение которой можно передать из командной строки в образ во время его сборки. Значение для переменной по умолчанию можно представить в Dockerfile
.
В отличие от ENV
-переменных, ARG
-переменные недоступны во время выполнения контейнера. Однако ARG
-переменные можно использовать для задания значений по умолчанию для ENV
-переменных из командной строки в процессе сборки образа. А ENV
-переменные уже будут доступны в контейнере во время его выполнения.
10. Инструкция ENTRYPOINT
позволяет задавать команду с аргументами, которая должна выполняться при запуске контейнера. Она похожа на команду CMD
, но параметры, задаваемые в ENTRYPOINT
, не перезаписываются в том случае, если контейнер запускают с параметрами командной строки. Вместо этого аргументы командной строки, передаваемые в конструкции вида docker run image param
, добавляются к аргументам, задаваемым инструкцией ENTRYPOINT
.
# Задаём значение по умолчанию для переменной ARG data="some value" # Команда будет запущена при запуске контейнера ENTRYPOINT ["php", "./app/script.php", "data"]
11. Инструкция EXPOSE
указывает на то, какие порты нужно открыть для того, чтобы можно было связаться с работающим контейнером. Обратите внимание, что эта инструкция не открывает порты. Для того, чтобы открыть порт (или порты) и настроить перенаправление, нужно выполнить команду docker run
с опцией -p
. Если использовать ключ в виде -P
(с заглавной буквой P
), то открыты будут все порты, указанные в инструкции EXPOSE
.
12. Инструкция VOLUME
устарела и использовать ее не рекомендуется.
Хранение данных в Docker
Данные в Docker могут храниться либо временно, либо постоянно.
1. Временное хранение данных
По умолчанию файлы, создаваемые приложением, работающим в контейнере, сохраняются в верхнем слое контейнера, поддерживающем запись. Для того чтобы этот механизм работал, ничего специально настраивать не нужно. Получается дёшево и сердито — приложению достаточно просто сохранить данные и продолжить заниматься своими делами. Однако после того как контейнер перестанет существовать, исчезнут и данные, сохранённые таким вот нехитрым способом.
2. Постоянное хранение данных
Самый простой способ — монтирование директории основной системы в Docker контейнер прямо при запуске:
$ docker run -v /path/to/outer-dir:/path/to/inner-dir image-name
Давайте запустим в работу контейнер с Ubuntu и смонтируем директорию ~/share
в директорию контейнера /mnt/share
:
$ mkdir ~/share $ docker run -it -v ~/share:/mnt/share ubuntu:18.10 /bin/bash # cd /mnt/share # переходим в директорию # touch test.txt # и создаем в ней файл # exit
Теперь в основной системе, в директории ~/share
мы увидим файл test.txt
. При удалении контейнера, все данные, которые он записывал в директорию /mnt/share
останутся в директории ~/share
основной системы.
Второй способ постоянного хранения данных — использование Docker Volumes.
Поиск: CLI • Linux • Ubuntu • Виртуализация • Команда • Настройка • Процесс • Установка • Контейнер • Образ • Docker