Начало работы с Docker. Часть вторая

19.03.2020

Теги: CLIDockerLinuxUbuntuВиртуализацияКомандаНастройкаПроцессУстановка

Создание 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 с краткими комментариями, а потом разберем их подробнее:

  1. FROM — задаёт базовый (родительский) образ
  2. LABEL — описывает метаданные (например, кто создал образ)
  3. ENV — устанавливает постоянные переменные среды
  4. RUN — выполняет команду и создаёт слой образа
  5. COPY — копирует в контейнер файлы и директории
  6. ADD — копирует файлы и папки в контейнер, может распаковывать .tar-файлы
  7. CMD — описывает команду с аргументами, которая выполняется при запуске контейнера
  8. WORKDIR — задаёт рабочую директорию для следующей инструкции
  9. ARG — задаёт переменные для передачи Docker во время сборки образа
  10. ENTRYPOINT — задает команду с аргументами для вызова во время выполнения контейнера
  11. EXPOSE — указывает на необходимость открыть порт
  12. 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

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.