Часть 1. Предпосылки и основы

Глава 4. Основы Docker

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

[Совет]Совет

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

 Архитектура Docker

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

На Рисунке 4-1 мы можем увидеть основные компоненты установки Docker:

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

  • Клиент Docker располагается слева и используется для общения с демоном Docker посредством HTTP. По умолчанию это происходит через сокет домена Unix (UDS или, иначе: IPC, сокет межпроцессного взаимодействия), но также может использоваться сокет TCP, делая возможными удаленные клиенты, или дескриптор файла для сокетов, управляемых sytemd. Поскольку все взаимодействие должно выполняться в HTTP, достаточно легко подключаться к удаленным демонам Docker и разрабатывать связывание программного языка, но это также имеет последствия для того, как реализуется функциональность, например требования контекста сборки для Dockerfile, как описано в разделе "Встроенный контекст". Используемый для взаимодействия с демоном API хорошо определен и документирован, что позволяет разработчикам писать программы, которые напрямую взаимодействуют с демоном без использования клиента Docker. Клиент Docker и демон распространяются в виде исполняемого (двоичного) файла.

  • Реестры Docker хранят и распространяют образы. Реестром по умолчанию является Docker Hub, который размещает тысячи общедоступных образов а также курирует "официальные" образы. Многие организации имеют собственные реестры, которые могут применяться для хранения коммерческих или критически важных образов а также избегать перегруженности необходимостью загрузки образов из интернета. Для информации о работе ваших собственных реестров смотрите раздел "Работа вашего собственного реестра". Демон Docker загружает образы определяемые запросами docker pull. Он также автоматически загружает образы определенные запросом docker run и в инструкции FROM Dockerfile когда они не доступны локально.

 

Рисунок 4-1. Обзор на высоком уровне основных компонентов Docker



 Технологии, лежащие в основе

Демон Docker использует "драйвер выполнения" для создания контейнера. По умолчанию это собственный драйвер Docker runc, однако также существует наследуемая поддержка для LXC. Runc очень тесно подогнан к следующей функциональности ядра:

  • cgroups, которые отвечают за управление используемыми контейнерами ресурсами (т.е. за использование ЦПУ и оперативной памяти). Они также отвечают за замораживание (freezing) и размораживание (unfreezing) контейнеров, которые используются в функциональности docker pause.

  • namespaces (пространство имен) ответственно за изоляцию контейнеров; гарантирующую что файловая система, имя хоста, сетевая среда и процессы контейнера отделены от остальной части вашей системы.

Libcontainer также поддерживает SElinux и AppArmor, которые могут быть разрешены для более плотной безопасности. За дополнительной информацией обращайтесь к Главе 13.

Другой лежащей в основе Docker главной технологией является файловая система UFS (Union File System), используемая для хранения уровней для контейнеров. UFS обеспечивается одним из нескольких драйверов хранения из AUFS, devicemapper, BTRFS или Overlay. Отсылаем к предыдущему обсуждению в "Образы, контейнеры и UFS".

 Окружающие технологии

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

Как описано в "Плагины и прокладка труб", Docker Inc. планирует построить полное коробочное решение которое включает в себя эту функциональность, но при этом позволяет пользователям легко выгружать установленные по умолчанию компоненты в замен разработанных третьими фирмами. Стратегия "заменяемых батарей" прежде всего относится к уровню API - позволяя компонентам прицепляться к движку Docker - но также могут рассматриваться как делающие возможной поддержку технологий Docker упакованных в виде независимого исполняемого (двоичного) кода способного легко заменяться эквивалентами третьих сторон.

Текущий список предоставляемых Docker поддерживаемых технологий включает:

Swarm
Кластерное решение Docker. Swarm может объединять в группы различные хосты Docker, позволяя пользователям представлять их как о едином ресурсе. За дополнительной информацией обращайтесь к Главе 12.
Compose
Docker Compose является инструментом для построения и выполнения приложений состоящих из множества контейнеров Docker. Изначально он применялся при разработке и тестировании, а не в промышленной эксплуатации. Для ознакомления с подробностей отсылаем вас к разделу "Автоматизация при помощи Compose".
Machine
Docker Machine устанавливает и настраивает хосты Docker на локальных и удаленных ресурсах. Machine также настраивает клиента Docker, делая его легко перемещаемым между окружениями. За примером обращайтесь к Главе 9.
Kitematic
Kitematic является графическим интерфейсом Mac OS и Windows для работы контейнеров Docker и управления ими
Docker Trusted Registry
(Доверенный реестр Docker) это решение в рамках Docker для хранения и управления образами Docker. Это эффективная локальная версия Docker Hub, которая может интегрироваться с существующей инфраструктурой безопасности и помогать организациям соблюдать правила относительно хранения и безопасности данных. Функциональность содержит метрики, управление доступом на основе ролей (RBAC, Role-Based Access Control), а также журналы, причем все управляется с консоли администратора. В настоящее время это единственный продукт Docker Inc, не имеющий открытого исходного кода.

Уже существует большой список служб и приложений третьих сторон, который встроен в Docker и работает с ним. Некоторые решения уже появились в следующих областях:

Сетевая среда
Создание охватывающих хосты сетей контейнеров является нетривиальной задачей, которая может быть решена различными способами. В этой области появилось несколько решений, включающих Weave и Проект Calico. Кроме того, Docker вскоре получит интегрированное сетевое решение с названием Overlay. Пользователи получат возможность выгружать драйвер Overlay для других решений, использующих сетевые подключаемые структуры Docker.
Обнаружение служб
При поступлении контейнера Docker, ему нужен некий способ нахождения прочих служб, с которыми ему следует взаимодействовать и которые обычно также работают в виде контейнеров. Поскольку контейнерам динамично назначаются IP адреса, это не является тривиальной задачей в больших системах. Решения в этой сфере включают Consul, Registrator, SkyDNS и etcd
Управление оркестровкой и кластеризацией
В больших реализациях контейнеров для мониторинга и управления системой существенен инструментарий для этих целей. Каждый новый контейнер нуждается в размещении на хосте, в мониторинге и обновлении. Система должна реагировать на отказы или изменения нагрузки посредством соответствующих перемещений, запусков или остановок контейнеров. Существует ряд конкурирующих решений в этой отрасли, включающих Kubernetes от Google, Marathon (конструктив для Mesos), CoreOS Fleet и собственный инструментарий Docker Swarm.

Все эти темы обсуждаются в больших подробностях в Части III. Стоит также отметить альтернативы Docker Trusted Registry, включающие CoreOS Enterprise Registry и JFrog Artifactory.

В добавление к упомянутым ранее подключаемым сетевым драйверам Docker также поддерживает подключаемые тома (volume plugin) для интеграции с прочими системами хранения. Достойные упоминания подключаемые тома включают Flocker, инструмент множества хостов управления и миграции данных, а также GlusterFS для распределенного хранилища. Дополнительная информация по подключаемым конструктивам может быть найдена на веб- сайте Docker.

Интересный побочный эффект от роста популярности контейнеров заключается в новом поколении операционных систем, предназначенных для их хостинга. Хотя Docker успешно работает в большинстве современных дистрибутивов Linux, подобных Ubuntu и Red Hat, существует ряд проектов в стадии реализации для создания минимальных и простых в сопровождении дистрибутивов, сосредоточенных исключительно на работе контейнеров (или контейнеров и виртуальных машин), особенно в контексте насыщения цетнра обработки данных или кластера. Примеры включают Проект Atomic, CoreOS и RancherOS.

 Docker хостинг

Мы обсудим хостинг Docker более подробно в Главе 9, но здесь стоит отметить некоторые из многих вариантов. Многие традиционные поставщики облачных решений, включающие Amazon, Google и Digital Ocean привнесли определенный уровень в продукцию Docker. Наиболее интересным из них, возможно, является Container Engine Google, поскольку он строится непосредственно поверх Kubernetes. Конечно, даже если поставщик облачных решений не имеет определенного предложения решений Docker, все еще стандартным будет предоставление виртуальных машин, которые могут выполнять контейнеры Docker.

Joyent также выходит в свет со своим собственным предложением контейнеров под названием Triton, построенным поверх SmartOS. Реализовав API Docker в своих собственных контейнере и технологии эмуляции Linux, Joуent смог создать общедоступное облако, которое взаимодействует со стандартным клиентом Docker. Важно отметить, что Joyent полагает, что его реализация контейнера достаточно безопасна чтобы работать непосредственно на голом железе вместо размещения его в виртуальные машины, что может повлечь значительную экономию эффективности, в особенности в плане операций ввода/ вывода.

Существуют также различные проекты построения платформ PaaS поверх Docker, в том числе Deis, Flynn и Paz.

 Как выполняется построение образов

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

 Контекст сборки

Команде docker build необходимы Dockerfile и контекст сборки (build context, который может быть пустым). Контекст сборки является набором локальных файлов и каталогов, на которые можно ссылаться в инструкциях ADD и COPY в Dockerfile и обычно определяются в виде пути и каталога. Например, в разделе "Построение образов из Dockerfile" мы применяем команду построения docker build -t test/cowsay-dockerfile ., которая устанавливает контекст в '.', текущий рабочий каталог. Все файлы и каталоги в пути формируют контекст сборки и будут отосланы демону Docker как часть процесса построения.

В случаях когда контекст не описан - если в Dockfile передается только URL или содержимое Dockfile передаётся в конвейере через STDIN - контекст сборки рассматривается как пустой.

[Предостережение]Предостережение

Не используйте +/+ в качестве контекста сборки

После того как контекст сборки накоплен в tarball и отослан демону Docker, вы на самом деле не хотите использовать каталог с уже имеющимся большим числом файлов. Например, использование /home/user, Downloads или / приведет к длительной задержке на время упаковки всего и отправки демону.

Если задан URL, начинающийся с http или https, то он предполагается прямой ссылкой на Dockerfile. Вряд ли будет полезно не связывать никакой контекст с Dockerfile (и не принимать ссылки на архивы).

Репозиторий git также может быть определен в качестве контекста сборки. В таком случае клиент Docker клонирует репозиторий и все подмодули во временный каталог, который далее отсылается демону Docker в качестве контекста сборки. Docker воспринимает ваш контекст как репозиторий git если путь начинается с github.com/, _git@ или _git://. В общем случае я хотел бы предложить избегать такого метода и вместо этого проверять репозитории вручную, что является более гибким и оставляет меньше шансов для путаницы.

Клиент Docker также может получать входные данные через STDIN, задавая "-" в качестве аргумента на месте контекста сборки. Входные данные также могут быть Dockerfile-ом без какого бы то ни было контекста (т.е. docker build - < context.tar.gz). Файлы архива могут быть в формате tar.gz, xz или bzip2.

Местонахождение Dockerfile внутри контекста может быть определено аргументом -f, (т.е. docker build -f dockerfiles/Dockerfile.debug). Если он не определен явно, Docker будет искать файл с названием Dockerfile в корне контекста.

[Совет]Совет

Использование файла .dockerignore

Чтобы удалить не нужные файлы из контекста сборки, вы можете воспользоваться файлом .dockerignore. Этот файл должен содержать имена подлежащих исключению файлов, разделенные символами новой строки. Допускаются символы подстановки * и ?. Например, у нас имеется следующий файл .dockerignore:

.git1
*/.git2
*/*/.git3
*.sw?4
	   
1
Будет игнорировать файл или каталог .git в корне контекста сборки, однако будет допускать его в любом подкаталоге (т.е. .git игнорируется, а dir1/.git нет).
2
Будет игнорировать файл или каталог .git ровно на один каталог ниже корня контекста сборки (т.е. dir1/.git игнорируется, а dir1/dir2/.git нет).
3
Будет игнорировать файл или каталог .git ровно на два каталога ниже корня контекста сборки (т.е. dir1/dir2/.git игнорируется, а .git и dir1/.git нет).
4
Будет игнорировать test.swp, test.swo и bla.swp, но не dir1/test.swp.

Отсутствует полная поддержка регулярных выражений наподобие [A-Z]*

На момент написания книги не существовало способа отметки соответствия файлов по всем каталогам (т.е. вы не можете игнорировать и test.tmp, и dir1/test.tmpв одном выражении).

 Уровни образа

Новые пользователи Docker часто бросают как бы между прочим построенные образы. Каждая инструкция в Dockerfile имеет результатом новый уровень образа, который может быть использован для запуска контейнера. Новый уровень создается запуском контейнера, применяющего образ предыдущего уровня, выполнением инструкции Dockerfile и сохранением нового образа. После успешного завершения инструкции Dockerfile промежуточный контейнер будет удален, если не был задан аргумент --rm=false (Не отчаивайтесь если я вас потерял в данном месте. Все встанет на свои места после просмотра вывода docker build в нашем отладочном примере). Поскольку результат каждой инструкции состоит в статичном образе - по существу лишь файловая система и некие метаданные - все выполняемые в инструкции процессы будут остановлены. Это означает, что хотя вы можете запускать в инструкции RUN процессы с длительным временем жизни, например базы данных или демоны SSH, они уже не будут исполняться при обработке следующей инструкции или запуске контейнера. Если вы хотите стартовать с контейнером службу или процесс, они должны запускаться из инструкции ENTRYPOINT или CMD.

Вы можете посмотреть полный набор создавших образ уровней выполнив команду docker history. Например:

$ docker history mongo:latest
IMAGE CREATED CREATED BY ...
278372cb22b2 4 days ago /bin/sh -c #(nop) CMD ["mongod"]
341d04fd3d27 4 days ago /bin/sh -c #(nop) EXPOSE 27017/tcp
ebd34b5e9c37 4 days ago /bin/sh -c #(nop) ENTRYPOINT &{["/entrypoint.
f3b2b8cf226c 4 days ago /bin/sh -c #(nop) COPY file:ef2883b33ed7ba0cc
ba53e9f50f18 4 days ago /bin/sh -c #(nop) VOLUME [/data/db]
c537910de5cc 4 days ago /bin/sh -c mkdir -p /data/db && chown -R mong
f48ad436057a 4 days ago /bin/sh -c set -x
df59596772ab 4 days ago /bin/sh -c echo "deb http://repo.mongodb.org/
96de83c82d4b 4 days ago /bin/sh -c #(nop) ENV MONGO_VERSION=3.0.6
0dab801053d9 4 days ago /bin/sh -c #(nop) ENV MONGO_MAJOR=3.0
5e7b428dddf7 4 days ago /bin/sh -c apt-key adv --keyserver ha.pool.sk
e81ad85ddfce 4 days ago /bin/sh -c curl -o /usr/local/bin/gosu -SL "h
7328803ca452 4 days ago /bin/sh -c gpg --keyserver ha.pool.sks-keyser
ec5be38a3c65 4 days ago /bin/sh -c apt-get update
430e6598f55b 4 days ago /bin/sh -c groupadd -r mongodb && useradd -r
19de96c112fc 6 days ago /bin/sh -c #(nop) CMD ["/bin/bash"]
ba249489d0b6 6 days ago /bin/sh -c #(nop) ADD file:b908886c97e2b96665
	   

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

FROM busybox:latest

RUN echo "This should work"
RUN /bin/bash -c echo "This won't"
	   

и попытка его построения:

$ docker build -t echotest .
Sending build context to Docker daemon 2.048 kB
Step 0 : FROM busybox:latest
---> 4986bf8c1536
Step 1 : RUN echo "This should work"
---> Running in f63045cc086b1
This should work
---> 85b49a851fcc2
Removing intermediate container f63045cc086b3
Step 2 : RUN /bin/bash -c echo "This won't"
---> Running in e4b31d0550cd
/bin/sh: /bin/bash: not found
The command '/bin/sh -c /bin/bash -c echo "This won't"' returned a non-zero
code: 127
	   
1
Идентификатор временного контейнера, запускаемого Docker-ом для выполнения нашей инструкции.
2
Идентификатор образа, созданного из контейнера.
3
Теперь временный контейнер удаляется.

Хотя в данном случае проблема совершенно очевидна из сообщения об ошибке, мы можем выполнить образ созданный на последнем успешном уровне для отладки данной инструкции. Отметим, что мы используем здесь последний идентификатор образа (85b49a851fcc), а не идентификатор последнего контейнера (e4b31d0550cd):

$ docker run -it 7831e2ca1809
/ # /bin/bash -c "echo hmm"
/bin/sh: /bin/bash: not found
/ # /bin/sh -c "echo ahh!"
ahh!
/ #
	   

И проблема становится даже ещё более очевидной: образ busybox не содержит оболочку bush.

 Кэширование

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

  • Предыдущая инструкция была найдена в кэше И

  • в кэше существует уровень, который имеет в точности те же инструкцию и родительский уровень (даже несущественные пробелы сделают кэш недействительным)

Помимо этого в случае инструкций ADD и COPY кэш будет недействительным если были изменены контрольная сумма или метаданные для любого из файлов в кэше.

Это означает, что инструкция RUN, которая не гарантирует получение одного и того же результата при множестве исполнений все еще будет кэширована. Будьте особенно внимательны к этому обстоятельству если вы загружаете файлы, запускает обновление apt-get или клонируете источник репозитория.

Если вам нужно отказать в кэшировании, вы можете выполнить docker build с аргументом --no-cache. Вы также можете добавлять или изменять инструкцию перед точкой, в которой вы хотите отвергнуть кэш; и по этой причине вы можете увидеть Dockerfile со строками наподобие:

ENV UPDATED_ON "14:12 17 February 2015"
RUN git clone....
	   

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

 Базовые образы

При создании собственных образов вам придется определиться с какого базового образа начинать. Существует множество вариантов выбора и стоит потратить определенное время чтобы понять различные преимущества и недостатки каждого.

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

Если вам требуется образ для хостинга вашего собственного приложения, вначале окиньте взглядом: существует ли образ на официальной основе для поддержки используемого вами языка или инфраструктуры (например, Go или Ruby on Rails). Зачастую вы можете воспользоваться отдельными образами для построения и распространения вашего программного обеспечения (например, вы можете применять образ java:jdk для построения приложения Java, однако затем распространять полученный в результате файл JAR с применением более скромного в размерах образа java:jre, который избавлен от ненужного инструментария построения). Аналогично, некоторые официальные образы (например, node) имеют специальные "тонкие" построения, в которых удалено множество средств разработки и заголовков.

Иногда на практике вам нужен небольшой, но полный дистрибутив Linux. Если я собираюсь следовать истинному минимализму, я буду применять образ alpine, который требует размеров всего лишь в 5МБ, но все таки имеет значительный менеджер пакетов для простой установки пакетов и инструментов. Если мне нужен более полный образ, я обычно применяю один из образов debian, который намного меньше чем также общеупотребимые образы ubuntu, но имеет доступ к тем же пакетам. Если ваша организация связана с определенным дистрибутивом Linux, вам также следует найти для него образ Docker. Это может иметь больше смысла, чем переход на новый дистрибутив, который ваша организация не поддерживает или с которым у нее нет опыта работы.

Большую часть времени не существует необходимости сильно беспокоиться о максимально возможном сокращении объёма образа. Помните, что базовые образы совместно используются различными образами, поэтому если вы уже имеете образ ubuntu:14.04, и извлекаете из хаба (Hub) основанный на нем образ, вместо всего образа целиком вы вытащите только нужные вам изменения. Тем не менее, минимизированные образы несомненно являются большим плюсом когда нам необходимо быстрое развертывание и простое распространение.

Можно брать с собой сверхминимизированные образы и поставлять их исключительно в двоичном виде. Чтобы сделать это следует написать Dockerfile который наследуется из образа специальной рабочей области (полностью очищенная файловая система) с простой копией вашего исполняемого кода и установить соответствующую инструкцию CMD. Ваш исполняемый код должен содержать все необходимые библиотеки (никаких динамических связываний) и не должен иметь возможности вызова внешних команд. Кроме того помните, что двоичный код должен быть скомпилирован под архитектуру вашего контейнера, которая может отличаться от архитектуры машины, выполняющей клиента Docker. (На самом деле можно продвинуть эту концепцию минимальности вычислений ещё дальше, отказавшись от Docker и полного ядра Linux в пользу подхода микроядер - unikernel. В архитектуре микроядра приложение объединяется с ядром, содержащим только ту функциональность, которая нужна этому приложению и далее непосредственно запускается гипервизором. Это позволяет избавляться от ряда ненужных уровней кода и неиспользуемых драйверов, получая в результате намного меньшее и более быстрое приложение - микроядра обычно загружаются в пределах секунд, т.е. они могут запускаться в качестве непосредственного ответа на пользовательские запросы. Если вы хотите узнать больше об этом обратите внимание на Unikernels: Rise of the Virtual Library Operating System Anil Madhavapeddy и David J. Scott, а также на MirageOs.)

Хотя минималистский подход может быть очень заманчивым, обратите внимание на то, что он может поставить вас в сложную ситуацию когда дело доходит до отладки и сопровождения - busybox не будет иметь большого числа инструментов для работы с ним, а если вы применяете рабочий образ (scratch), у вас даже не будет оболочки.

[Замечание]Ответ Phusion

Другим интересным выбором основного образа является phusion/baseimage-docker. Разработчики Phusion создали этот базовый образ как ответ на официальный образ Ubuntu, который по их утверждению упустил ряд существенных служб. Некоторые разработчики ядра Docker не согласны с точкой зрения Phusion, что повлекло к различным обменам мнениями в блогах, IRC и Твиттере. Основными спорными моментами являются:

Потребность в службе инициализации
Точка зрения Docker состоит в том, что контейнер должен выполнять только отдельное приложение, а в идеале отдельный процесс. Если у вас имеется только один процесс, нет потребности для службы инициализации. Главный аргумент, выдвигаемый Phusion состоит в том, что отсутствие службы инициализации может приводить к контейнерам, заполненными процессами зомби - процессами, которые не были корректно уничтожены породившими их процессами или собранными процессом супервизора. Хотя этот аргумент и верен, в случае ошибки в коде приложения является единственным способом возникновения процессов зомби; подавляющее большинство пользователей не должно сталкиваться с этой проблемой, а если уж это происходит, то лучшим решением будет исправление кода.
Работа демона crone
Большинство образов ubuntu и debian не запускают по умолчанию демон crone, а образ phusion запускает. Phusion приводит аргументацию, что многие приложения зависят от crone, следовательно он существенен для их выполнения. Точка зрения Docker - с которой я склонен соглашаться - заключается в том, что crone должен запускаться только если ваше приложение зависит от него.
Демон SSH
Образы по умолчанию не устанавливают и не выполняют демон SSH. Обычный способ получения оболочки заключается в применении команды docker exec (см. раздел "Управление контейнерами"), которая позволяет избегать проблем с работой ненужного процесса в контейнере. Phusion кажется принял это и отключил демон SSH по умолчанию, но их образ все еще значительно раздут за счет включения этого демона и его библиотек.

Что касается меня лично, я рекомендовали бы применять базовый образ Phusion только если у вас имеется потребность выполнять множество процессов, crone и ssh внутри вашего контейнера. В противном случае я бы придерживался образов из официальных репозиториев Docker, например ubuntu:14.04 или debian:wheezy.

[Предостережение]Предостережение

Реконструкция образов

Отметим, что при выполнении docker build Docker просмотрит инструкцию FROM и попытается извлечь образ если он не присутствует локально. Если он существует, Docker воспользуется этим образом без проверки существует ли доступная более новая версия. Это означает, что простого выполнение docker build не достаточно для уверенности в том, что ваши образы точно самые новые, вам придется либо в явном виде выполнить docker pull всех образов- предков или удалить их чтобы принудить команду построения к загрузке самых последних версий.

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

 Инструкции Dockerfile

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

[Замечание]Сопоставление форматов exec и shell

Некоторые инструкции (RUN, CMD и ENTRYPOINT) принимают оба формата: и shell, и exec. Формат exec принимает вид массива JSON (т.е. ["executable", "param1", "param2"]), что предполагает, что первый элемент является исполняемым именем, которое выполняется с остальными элементами в качестве параметров. Формат shell является строкой произвольной формы, которая будет интерпретироваться путем передачи в /bin/sh -c. Применяйте формат exec во избежание умышленной порчи строк или в случаях, когда в образе нет /bin/sh

В Dockerfile доступны следующие инструкции:

ADD
Копирует файлы из контекста сборки или с удаленного URL в образ. Если файлы архива добавляются из локального пути, они будут автоматически распаковываться. Поскольку диапазон функциональности, покрываемый ADD достаточно большой, обычно лучше предпочесть более простую команду COPY для копирования файлов и каталогов в контексте сборки и инструкции RUN c curl или wget для загрузки удаленных ресурсов (что оставляет возможность обработки и удаления загруженного в той же самой инструкции).
CMD
Выполняет данную инструкцию при запуске контейнера. Если была определена ENTRYPOINT, данная инструкция будет интерпретироваться как аргумент для ENTRYPOINT (в этом случае убедитесь, что вы используете формат exec). Инструкция CMD перекрывается любыми аргументами в docker runпосле имени данного образа. Эффект имеет только последняя инструкция CMD, а все предыдущие инструкции перекрываются (включая присутствующие в базовых образах).
COPY
Применяется для копирования файлов из контекста сборки в ваш образ. Она имеет две формы, COPY src dest_ и COPY ["src", "dest"], причем обе копируют файлы или каталоги src в dest внутри контейнера. Формат массива JSON требуется если пути имеют внутри пробелы. Для определения множества файлов или каталогов могут использоваться символы подстановки. Отметим, что вы не можете определять пути src вне вашего контекста сборки (т.е., ../another_dir/myfile не будет работать).
ENTRYPOINT
Устанавливает исполняемый код (и аргументы по умолчанию), которые должны быть выполнены при запуске контейнера. Все инструкции CMD или параметры для docker run после имени данного образа будут передаваться в качестве параметров для ее исполнения. Инструкции ENTRYPOINT часто применяются для обеспечения "запускающих" сценариев, которые инициализируют переменные и службы до интерпретации всех заданных аргументов.
ENV
Устанавливает переменные окружения внутри образа. Она может служить ссылкой в последующих инструкциях. Например:
...
ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION
...
	   
Эти переменные также будут доступны внутри образа.
EXPOSE
Указывает Docker, что данный контейнер будет иметь процесс, прослушивающий заданный порт или порты. Данная информация используется Docker при соединении контейнеров (см. Связывание контейнеров) или публикуйте порты предоставляя параметр -P в docker run; сама по себе инструкция EXPOSE не имеет влияния на сетевую среду.
FROM
Устанавливает базовый образ для Dockerfile; последующие инструкции выполняют построение поверх данного образа. Базовый образ определяется как IMAGE:TAG (например, debian:wheezy). Если тег опущен, предполагается, что он будет lastest, но я настоятельно рекомендую вам всегда устанавливать этот тег на определенную версию во избежание неожиданностей. Должна быть самой первой инструкцией в Dockerfile.
MAINTAINER
Устанавливает в вашем образе метаданные "Author" в значение данной строки. Вы можете извлекать его при помощи span class="term">docker inspect -f {{.Author}} IMAGE. Обычно используется подробностей имен и контактных данных специалиста по сопровождению данного образа.
ONBUILD
Определяет инструкцию, которая должна быть выполнена позже, когда данный образ применяется в качестве базового уровня для другого образа. Это может быть полезным для обработки данных, которые будут добавлены в дочернем образе (т.е. эта инструкция может копировать в код из выбранного каталога и выполнять на текущих данных сценарий сборки).
RUN
Выполняет заданную инструкцию внутри контейнера и фиксирует результат.
USER
Устанавливает пользователя (через имя или UID) для использования во всех последующих инструкциях RUN, CMD или ENTRYPOINT. Отметим, что UID одни и те же и в хосте, и в контейнере, однако имена пользователей могут быть назначены для различных UID, что может сделать вещи мудрёными при установке разрешений.
VOLUME
Определяет описываемый файл иликаталог в качестве тома. Если этот файл или каталог уже существуют в вашем образе, они будут скопированы в том после запуска контейнера. Если задано множество параметров, они интерпретируются как множество определений томов. Вы не можете определять каталог хоста для тома внутри Dockerfile по причинам переносимости и безопасности. Для получения дополнительной информации ознакомьтесь с разделом "Управление данными томами и контейнерами данных".
WORKDIR
Устанавливает рабочий каталог для всех последующих инструкций RUN, CMD, ENTRYPOINT и ADD, COPY. Может применяться многократно. Могут быть использованы относительные пути, причем они разрешаются относительно предыдущего WORKDIR.

 Соединение контейнеров с миром

Допустим вы выполняете внутри контейнера веб сервер. Как вы обеспечите доступ во внешний мир? Ответ заключается в "публикации" с командами -p или -P. Эти команды переадресовывают порты хоста в контейнер. Например:

$ docker run -d -p 8000:80 nginx
af9038e18360002ef3f3658f16094dadd4928c4b3e88e347c9a746b131db5444
$ curl localhost:8000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
	   

Параметр -p 8000:80 предпишет Docker переадресовать порт хоста 8000 в порт 80 контейнера. В качестве альтернативы параметр -P может использоваться для сообщения Docker о необходимости автоматического выбора свободного порта для переадресации в хосте. Например:

$ ID=$(docker run -d -P nginx)
$ docker port $ID 80
0.0.0.0:32771
$ curl localhost:32771
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
	   

Основное преимущество команды -P состоит в том, что вы больше не отвечаете за отслеживание выделения портов, что становится важным если у вас есть различные порты публикации контейнеров. В этих случаях вы можете применять команду docker port для изучения выделения портов Docker.

 Связывание контейнеров

Связи (link) Docker являются простейшим способом сделать возможным общение контейнеров на одном и том же хосте. При использовании сетевой модели Docker по умолчанию взаимодействие между контейнерами будет осуществляться через внутреннюю сетевую среду Docker, что означает, что взаимодействие не выходит за пределы сетевой среды вашего хоста.

[Замечание]Изменения сетевой среды Docker

В последующих версиях Docker (вероятно, 1.9 и далее), идиомами средств сетевой среды контейнеров станут "службы публикации", (publish service), а не связи контейнеров. Тем не менее, поддержка связей будет продолжена в обозримом будущем и примеры из данной книги должны работать без изменений.

С более подробной информацией о грядущих изменениях в сетевой среде можно ознакомится в разделе "Новая сетевая среда Docker".

Связи инициализируются путем задания аргумента --link CONTAINER:ALIAS to docker run, где CONTAINER является именем вашего связанного контейнера (в данном обсуждении и на протяжении всей этой книги я буду ссылаться на подсоединяемый контейнер как на связанный контейнер -link container, а запускавший связь контейнер как главный контейнер -master container- поскольку последний ответственен за инициацию связи), а ALIAS является локальным именем, используемым внутри главного контейнера для ссылки на вашу связь контейнера.

Использование связей Docker также добавит псевдоним (алиас) и идентификатор связанного контейнера в /etc/hosts в вашем главном контейнере, делая возможной адресацию связанного контейнера по имени из главного контейнера.

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

$ docker run -d --name myredis redis
c9148dee046a6fefac48806cd8ec0ce85492b71f25e97aae9a1a75027b1c8423
$ docker run --link myredis:redis debian env
ATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=f015d58d53b5
REDIS_PORT=tcp://172.17.0.22:6379
REDIS_PORT_6379_TCP=tcp://172.17.0.22:6379
REDIS_PORT_6379_TCP_ADDR=172.17.0.22
REDIS_PORT_6379_TCP_PORT=6379
REDIS_PORT_6379_TCP_PROTO=tcp
REDIS_NAME=/distracted_rosalind/redis
REDIS_ENV_REDIS_VERSION=3.0.3
REDIS_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.0.3.tar.gz
REDIS_ENV_REDIS_DOWNLOAD_SHA1=0e2d7707327986ae652df717059354b358b83358
HOME=/root
	   

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

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

По умолчанию контейнеры будут способны общаться друг с другом вне зависимости от того, связаны ли они в явном виде или нет. Если вы хотите избежать взаимодействия контейнеров, которые не были связаны, применяйте параметры --icc=false и --iptables при запуске демона Docker. Теперь, когда контейнеры связаны, Docker установит правила Iptalles для разрешения взаимодействия контейнеров по всем портам, которые были объявлены как незащищенные (expose).

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

Для получения дополнительной информации по сетевым контейнерам отсылаем вас к Главе 11.

 Управление данными томами и контейнерами данных

Напомним, что тома Docker являются каталогами (технически каталогами или файлами, поскольку том может быть отдельным файлом), которые не являются частью UFS контейнера (подробнее: "Образы, контейнеры и UFS") - это просто находящиеся на хосте каталоги, которые закреплённо смонтированы (bind mount Закреплённое монтирование) в контейнер.

Существует три (хорошо, два с половиной, все зависит от способа подсчета) различных способа инициализации томов и важно понимать разницу между этими методами. При первом мы можем объявить том во время выполнения при помощи флага -v:

$ docker run -it --name container-test -h CONTAINER -v /data debian /bin/bash
root@CONTAINER:/# ls /data
root@CONTAINER:/#
	   

Это создаст каталог /data внутри контейнера в томе. Все расположенные в каталоге /data файлы будут скопированы в том. Мы можем найти место расположения тома на вашем хосте путём выполнения на этом хосте docker inspect из новой оболочки:

$ docker inspect -f {{.Mounts}} container-test
[{5cad... /mnt/sda1/var/lib/docker/volumes/5cad.../_data /data local true}]
	   

В этом случае том /data/ в контейнере это просто ссылка на каталог хоста /var/lib/docker/volumes/5cad…/_data. Чтобы удостовериться в этом, мы можем добавить файл в каталог на нашем хосте (если вы связаны с удаленным демоном Docker, вам придется выполнить данную команду на удаленном хосте через SSH. Если вы используете машину Docker - что будет действительно так, если вы устанавливали Docker с помощью Docker Toolbox, вы можете сделать это с помощью docker-machine ssh default):

$ sudo touch /var/lib/docker/volumes/5cad.../_data/test-file
	   

И вы должны сразу увидеть внутри контейнера:

$ root@CONTAINER:/# ls /data
test-file
	   

Второй способ установить том заключается в применении инструкции VOLUME в Dockerfile:

FROM debian:wheezy
VOLUME /data
	   

Это имеет в точности тот же эффект, что и определение -v /data в docker run.

[Замечание]Установка полномочий в Dockerfile

Часто вам необходимо устанавливать полномочия и владельцев на какой-то том или инициализировать некий том с какими-то определенными по умолчанию данными или файлами настройки. Здесь ключевым моментом, который вы должны знать, является то, что все инструкции в Dockerfile после инструкции VOLUME не способны вносить изменения в этот том. Например, следующий Dockerfile не будет работать ожидаемым образом:

FROM debian:wheezy
RUN useradd foo
VOLUME /data
RUN touch /data/x
RUN chown -R foo:foo /data
	   

Мы хотим выполнить команды touch и chown в файловой системе образа, однако на самом деле они выполняются внутри тома временного контейнера, используемого для создания данного уровня (отсылаем назад к "Как выполняется построение образов" за дополнительными подробностями). Этот том будет удален после выполнения команды, что лишает смысла данной инструкции.

Следующий Dockerfile будет работать:

FROM debian:wheezy
RUN useradd foo
RUN mkdir /data && touch /data/x
RUN chown -R foo:foo /data
VOLUME /data
	   

Когда в этом образе запускается контейнер, Docker скопирует все файлы из каталога тома в образ внутри тома контейнера. Этого не случится если вы опишите каталог хоста для данного тома (таким образом эти файлы хоста не будут случайно перезаписаны).

Если по некоторой причине вы не можете установить полномочия и владельца в инструкции RUN, вы должны сделать это с применением сценария CMD или ENTRYPOINT, который выполнится после создания контейнера.

Третий (Эквивалентный второму?) способ заключается в расширении параметра -v для docker run с явным закреплением каталога в хосте с применением формата -v HOST_DIR:CONTAINER_DIR. Это можно сделать в Dockerfile (что будет не портируемым и к тому же не безопасным). Например:

$ docker run -v /home/adrian/data:/data debian ls /data
	   

Это смонтирует каталог /home/adrian/data на данном хосте в качестве /data внутри вашего контейнера. Всё уже существующее в каталоге /home/adrian/data будет доступно внутри данного контейнера. Если каталог /data уже существует в этом контейнере, его содержимое будет скрыто данным томом. В отличие от прочих вызовов никакие файлы из рассматриваемого образа не будут копироваться в данный том, а том не будет удален Docker-ом (то есть docker rm -v не удалит том, который смонтирован в выбранном пользователем каталоге).

[Замечание]Закреплённое монтирование

Когда в каком-то томе используется определенный каталог хоста (синтаксис -v HOST_DIR:CONTAINER_DIR), на это обычно ссылаются как на закрепленное монтирование (bind mounting). Хотя это и вводит слегка в заблуждение, поскольку все тома технически монтируются с прикреплением - разница состоит в том, что точка монтирования делается в явном виде в отличие от скрытого определения при каталоге, принадлежащем Docker.

 Совместное использование данных

Синтаксис -v HOST_DIR:CONTAINER_DIR очень полезен при совместном использовании файлов хостом и одним или более контейнеров. Например, файлы настройки могут сохраняться на хосте и монтироваться в контейнер из общих образов.

Мы также совместно используем данные в контейнерах при помощи параметра --volumes-from CONTAINER в docker run. Например, мы можем создать новый контейнер, который имеет доступ к вашим томам из контейнера в нашем предыдущем примере примерно так:

$ docker run -it -h NEWCONTAINER --volumes-from container-test debian /bin/bash
root@NEWCONTAINER:/# ls /data
test-file
root@NEWCONTAINER:/#
	   

Важно отметить, что это работает вне зависимости от того, содержит или нет контейнер работающие в настоящий момент тома (в данном случае container-test). Пока существует по крайней мере одна связь с неким томом, он не может быть удален.

 Контейнеры данных

Общая практика состоит в создании контейнеров данных (data container) - контейнеров, чья основная роль заключается в предоставлении совместного использования другим контейнерам. Главное преимущество такого подхода заключается в том, что он поддерживает удобное пространство имен для томов которые легко могут загружаться с применением команды --volumes-from.

Например, мы можем создать контейнер данных для базы данных PostgerSQL с помощью следующей команды:

$ docker run --name dbdata postgres echo "Data-only container for postgres"
	   

Это создаст контейнер из образа postgres и проведет инициализацию всех томов определенных в данном образе до выполнения команды echo и выхода (Мы могли бы применить любую команду, которая выйдет непосредственно здесь, однако сообщение echo будет служить нам напоминанием о цели данного контейнера при выполнении docker ps -a. Другим вариантом будет не запускать контейнер вообще, воспользовавшись командой docker create вместо docker run). Нет необходимости оставлять контейнеры данных исполняемыми, поскольку это будет пустой тратой ресурсов.

Затем мы можем использовать этот том из других контейнеров при помощи параметра --volumes-from. Например:

$ docker run -d --volumes-from dbdata --name db1 postgres
	   
[Замечание]Образы для контейнеров данных

Обычно не существует потребности применять "минимальный образ" подобный busy box или scratch для контейнера данных. Просто используйте тот же образ, который применяется для контейнера, потребляющего эти данные. Например, примените образ postgres для создания контейнера, который будет использоваться с базой данных Potgres.

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

 Удаление томов

Тома могут быть удалены только если:

  • контейнер был удалён при помощи docker rm -v или

  • В docker run был обеспечен флаг --rm

И

  • не существует связей контейнеров к данному тому

  • никакой каталог хоста не определено для этого тома (не применялся синтаксис -v HOST_DIR:CONTAINER_DIR)

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

 Общие команды Docker

Данный раздел предоставляет короткий (по крайней мере в сравнении с официальной документацией) и не исчерпывающий обзор различных команд Docker, в основном сосредотачиваясь на повседневно используемых командах. Поскольку Docker быстро меняется и эволюционирует, отсылаем вас к официальной документации на веб- сайте Docker за исчерпывающими и современными подробностями по данным командам. Я не описываю в подробностях параметры и синтаксис различных приводимых команд за исключением docker run. За этим отсылаю ко встроенному помощнику, к к торому можно получить доступ задав параметр --help в любой команде или посредством команды docker help.

[Замечание]Булевы флаги Docker

В большинстве инструментов командной строки Unix вы найдете флаги, которые не принимают значение, например, -l в ls -l. Поскольку эти флаги являются либо установленными, либо нет, Docker рассматривает их рассматривает их как булевы (boolean) и - в отличие от большинства прочего инструментария - поддерживает явное определение булева значения флага (т.е. он будет принимать оба варианта, -f=true и -f. Кроме того, использоваться с базой данных Potgres.

Применение того же самого образа не потребует дополнительного пространства - вы уже должны иметь загруженный или созданный образ для вашего потребителя. Это также дает вашему образу возможность наполнить ваш контейнер некими начальными данными и гарантировать, что полномочия установлены корректно. Кроме того (и это то место, где все становится запутанным) вы можете иметь флаги, установленные по умолчанию как в истину, так и в ложь. В отличие от установки по умолчанию в значение ложь, установка по умолчанию в истину считается принятой при отсутствии определения в явном виде. Указание флага без аргумента имеет тот же эффект, что и установка его в значение истина - сброс значения истины флага по умолчанию не задается аргументом со значением; единственным способом сброса истинного значения флага по умолчанию может быть явное его определение в значение ложь (т.е. -f=false).

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

$ docker logs --help
...
-f, --follow=false Follow log output
--help=false Print usage
-t, --timestamps=false Show timestamps
...
	   

показывает, что аргументы -f, --help и -t по умолчанию имеют значение ложь.

Чтобы дать пару конкретных примеров, рассмотрим истинное значение по умолчанию --sig-proxy для docker run. Единственный способ выключить этот параметр заключается в его явной установке в значение ложь. Например:

$ docker run --sig-proxy=false ...
	   

Всё последующее эквивалентно:

$ docker run --sig-proxy=true ...
$ docker run --sig-proxy ...
$ docker run ...
	   

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

$ docker run --read-only=true
$ docker run --read-only
	   

Оставление его неописанным или явная установка в значение ложь эквивалентны. Это также приводит к некоторому причудливому обращению с флагами, которые обычно накоротко замыкают логику (например, docker ps --help=false) будет работать как обычная команда без выдачи сообщения подсказки).

 Команда run

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

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

-a, --attach

Подключает определяемый поток (STDOUT и т.п.) к вашему терминалу. Если не определен, подключаются и stdout, и stderr. В случае когда параметр не задан и контейнер запускается в интерактивном режиме (-i), также подключается stdin.

Несовместим с -d.

-d, --dettach

Выполняет контейнер в "отключённом режиме". Команда будет выполнять контейнер в фоновом режиме и вернёт идентификатор контейнера.

-i, --interactive

Оставляет открытым stdin (даже когда он не подключен). Обычно используется совместно с -t для запуска интерактивного сеанса контейнера. Например:

$ docker run -it debian /bin/bash
root@bd0f26f928bb:/# ls
...snip...
	   
--restart

Определяет когда Docker попытается перезапустить исчезнувший контейнер. Параметр no никогда не будет пытаться повторно запускать какой бы то ни было контейнер, а always будет пытаться осуществлять повторный запуск вне зависимости от состояния выхода. Параметр on-failure будет пытаться осуществлять повторный запуск контейнера, который вышел с ненулевым состоянием и может получать необязательный параметр, определяющий число попыток повторного запуска до прекращения (если не задан, будет пытаться без ограничений). Например, docker run --restart onfailure:10 postgres будет запускать контейнер postgres и попытается повторно запустить его 10 раз, если он будет выходить с ненулевым кодом.

--rm

Автоматически удаляет контейнер, если он существует. Не может применяться вместе с -d.

-t, --tty

Выделяет псевдо- TTY. Обычно применяется совместно с -i для запуска интерактивного контейнера

Следующие параметры выполняют установку имен и переменных контейнера:

-e, --env

Устанавливает переменные внутри контейнера. Например:

$ docker run -e var1=val -e var2="val 2" debian env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=b15f833d65d8
var1=val
var2=val 2
HOME=/root
	   

Также отметим параметр --env-file для передачи параметров через некий файл.

-h, --hostname

Устанавливает unix имя хоста контейнера в значение NAME. Например:

$ docker run -h "myhost" debian hostname
myhost
	   
--name NAME

Назначает контейнеру имя NAME. Это имя затем может применяться для адресации контейнера в других командах Docker.

Следующие параметры позволяют пользователю настраивать тома. (за подробностями обращайтесь к "Управление данными томами и контейнерами данных"):

-v, --volume

Существует две формы параметров для настройки тома (файла или каталога внутри контейнера, который является частью собственной файловой системы хоста, а не UFS контейнера). Первая форма только определяет каталог в пределах контейнера и будет закрепляться (bind) за каталогом хоста по выбору Docker. Вторая форма определяет каталог хоста для закрепления (bind).

--volumes-from

Монтирует том из определяемого контейнера. Часто применяется в ассоциации с контейнерами данных (см. "Контейнеры данных").

Существует также ряд параметров, влияющих на сетевую среду. Основные команды, которые вы можете предполагать для обычного применения:

--expose

Эквивалентна EXPOSE инструкции Dockerfile. Устанавливает порт или диапазон портов для применения в контейнере, однако не открывает порт. Имеет смысл только совместно с -P и при связанных контейнерах.

--link

Устанавливает частный сетевой интерфейс для определенного контейнера. Для дополнительной информации обращайтесь к "Связывание контейнеров".

-p, --publish

"Публикует" порт контейнера, делая его доступным в хосте. Если порт хоста не определен, выбирается случайный порт с большим значением, который может быть обнаружен посредством команды docker port. Также может быть определен интерфейс хоста, на который проецируется данный порт.

-P, --publish-all

Публикует все выставленные (expose) в контейнере для хоста порты. Для каждого выставляемого порта будет выбираться случайный порт с большим числовым значением. Команда docker port может применяться для просмотра соответствий.

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

Команда docker run также имеет большой набор параметров для управления правами и возможностями контейнеров. За их подробностями обращайтесь к Главе 13.

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

--entrypoint

Устанавливает точку входа для вашего контейнера на задаваемый параметр, перезаписывает любую инструкцию ENTRYPOINT в Dockerfile.

-u, --user

Устанавливает пользователя, от имени которого выполняется данная команда. Может определяться как именем пользователя, так и его UID. Перезаписывает инструкцию USER в Dockerfile.

-w, --workdir

Устанавливает рабочий каталог в контейнере в значение предоставляемого пути. Перекрывает любое значение из Dockerfile.

 Управление контейнерами

Помимо docker run в процессе жизненного цикла контейнеров следующие команды docker применяются для управления ими:

docker attach [OPTIONS] CONTAINER

Команда attach позволяет пользователю наблюдать за главным процессом в вашем контейнере или взаимодействовать с ним. Например:

$ ID=$(docker run -d debian sh -c "while true; do echo 'tick'; sleep 1; done;")
$ docker attach $ID
tick
tick
tick
tick
	   

Отметим, что применение CTRL-C для выхода завершит главный процесс и вызовет завершение работы контейнера.

docker create

Создает контейнер из некого образа, но не запускает его. Получает большинство параметров аналогичных docker run. Чтобы запустить созданный контейнер воспользуйтесь docker start.

docker cp

Копирует файлы и каталоги между контейнером и хостом.

docker exec

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

Например:

$ ID=$(docker run -d debian sh -c "while true; do sleep 1; done;")
$ docker exec $ID echo "Hello"
Hello
$ docker exec -it $ID /bin/bash
root@5c6c32041d68:/# ls
bin dev home lib64 mnt proc run selinux sys usr
boot etc lib media opt root sbin srv tmp var
root@5c6c32041d68:/# exit
exit
	   
docker kill

Отправляет сигнал главному процессу (PID 1) контейнера. По умолчанию отправляет SIGKILL, который вызывает немедленный выход из контейнера. В качестве альтернативы может быть определен другой сигнал при помощи параметра -s. Возвращается идентификатор контейнера.

Например:

$ ID=$(docker run -d debian bash -c \
"trap 'echo caught' SIGTRAP; while true; do sleep 1; done;")
$ docker kill -s SIGTRAP $ID
e33da73c275b56e734a4bbbefc0b41f6ba84967d09ba08314edd860ebd2da86c
$ docker logs $ID
caught
$ docker kill $ID
e33da73c275b56e734a4bbbefc0b41f6ba84967d09ba08314edd860ebd2da86c
	   
docker pause

Приостанавливает все процессы в данном контейнере. Процессы не получают никакие сигналы, поскольку они были приостановлены и, следовательно, не могут быть выключены или вычищены. Процесс может быть запущен повторно при помощи docker unpause. docker pause использует внутреннюю функциональность cgroup freezer Linux. Данная команда противопоставляется docker stop, которая останавливает процесс и посылает сигналы, наблюдаемые процессами.

docker restart

Повторно запускает один или более контейнеров. Примерно эквивалентна вызову docker stop с последующим docker start в контейнерах. Принимает необязательный параметр -t, который определяет промежуток времени для ожидания перед закрытием контейнера перед его уничтожением отправкой сигнала SIGTERM.

docker rm

Удаляет один или более контейнеров. Возвращает имена или идентификаторы успешно удаленных контейнеров. По умолчанию docker rm не удаляет никакие тома. Параметр -f может применяться для удаления выполняемого контейнера, а параметр -v удалит созданные контейнером тома (только если они не были закреплённо смонтированы или не используются другим контейнером).

Например, чтобы удалить все остановленные контейнеры:

$ docker rm $(docker ps -aq)
b7a4e94253b3
e33da73c275b
f47074b60757
	   
docker start

Запускает остановленный контейнер (или контейнеры). Может использоваться для повторного как запуска для контейнера, который завершил свою работу, так и для контейнера, который был создан при помощи docker create, но ещё никогда не запускался.

docker stop

Останавливает (но не удаляет) один или более контейнеров. После вызова в контейнере docker stop, он перейдёт в состояние "выходящего". Принимает необязательный параметр -t, который определяет промежуток времени для ожидания перед закрытием контейнера перед его уничтожением отправкой сигнала SIGTERM.

docker unpause

Повторно запускает контейнер, приостановленный перед этим при помощи docker pause.

[Совет]Отсоединение от контейнеров

При подсоединении к контейнеру Docker, будь это результатом запуска его в интерактивном режиме или присоединение к нему при помощи docker attach, вы остановите запущенный контейнер если попытаетесь отсоединиться от него посредством CTRL-C. Вместо этого, если вы примените CTRL-P CTRL-Q, вы сможете отсоединиться от контейнера без его остановки.

Данный код работает только когда вы присоединены в интерактивном режиме с TTY (т.е. с применением обоих флагов, и -i, и -t).

 Информация Docker

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

docker info

Выводит различную информацию о системе Docker и хосте.

docker help

Выводит информацию о применении и справочные сведения по определенной подкоманде. Идентична выполнению команды с флагом --help.

docker info

Выдаёт информацию о версии Docker для клиента и сервера а также версию использовавшегося для компиляции Go.

 Информация контейнера

Следующие команды предоставляют дополнительную информацию по запущенным и остановленным контейнерам.

docker diff

Отображает изменения, внесенные в файловую систему контейнеров по сравнению с образом, из которого он был запущен. Например:

$ ID=$(docker run -d debian touch /NEW-FILE)
$ docker diff $ID
A /NEW-FILE
	   
docker events

Выводит события демона в реальном масштабе времени. Для выход используется CTRL-C. Для дополнительных сведений по этой теме обращайтесь к Главе 10.

docker inspect

Предоставляет детализированную информацию по определенным контейнерам или образам. Информация содержит большую часть информации о настройках и охватывает сетевые установки, а также соответствия томов. Команда может принимать один параметр, -f, который применяется для поддержки шаблона Go, который может быть использован для форматирования и фильтрации вывода.

docker logs

Выводит "журналы" контейнера. Это просто все, что было записано в STDERR и STDOUT внутри контейнера. За дополнительной информацией о регистрации обращайтесь к Главе 10.

docker port

Выводит список соответствий раскрытых портов для данного контейнера. Опционально может определяться для поиска внутренним портом контейнера и протоколом. Часто применяется после docker run -P <image> для обнаружения назначенных портов.

Например:

$ ID=$(docker run -P -d redis)
$ docker port $ID
6379/tcp -> 0.0.0.0:32768
$ docker port $ID 6379
0.0.0.0:32768
$ docker port $ID 6379/tcp
0.0.0.0:32768
	   
docker ps

Предоставляет информацию верхнего уровня по текущим контейнерам, например, имя, идентификатор и состояние. Принимает большое число дополнительных параметров, особенно отметим -a для получения всех контейнеров, а не только запущенных. Также отметим параметр -q, который возвращает только идентификаторы контейнеров, что очень полезно в качестве входной информации для других команд, подобных docker rm.

docker top

Предоставляет информацию по выполняемым процессам в пределах заданного контейнера. На самом деле, данная команда выполняет на данном хосте утилиту Unix ps и фильтрует процессы для данного контейнера. Эта команда может быть определена с теми же параметрами, что и утилита ps, а по умолчанию установлены -ef (однако проверяйте, что поле идентификатора процесса, PID, все ещё сохраняется в выводе).

Например:

$ ID=$(docker run -d redis)
$ docker top $ID
UID PID PPID C STIME TTY TIME CMD
999 9243 1836 0 15:44 ? 00:00:00 redis-server *:6379
$ ps -f -u 999
UID PID PPID C STIME TTY TIME CMD
999 9243 1836 0 15:44 ? 00:00:00 redis-server *:6379
$ docker top $ID -axZ
LABEL PID TTY STAT TIME COMMAND
docker-default 9243 ? Ssl 0:00 redis-server *:6379
	   

 Обращение с образами

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

docker build

Строит образ из Dockerfile. За подробностями обращайтесь к разделам "Построение образов из Dockerfile" и "Как выполняется построение образов".

docker commit

Создаёт образ из заданного контейнера. Хотя docker commit может быть полезной, обычно предпочтительнее создавать образы с применением docker build, которая легче повторяется. По умолчанию контейнеры приостанавливаются перед commit, однако это может быть выключено при помощи параметра --pause=false. Принимает параметры -a и -m для установки метаданных.

Например:

$ ID=$(docker run -d redis touch /new-file)
$ docker commit -a "Joe Bloggs" -m "Comment" $ID commit:test
ac479108b0fa9a02a7fb290a22dacd5e20c867ec512d6813ed42e3517711a0cf
$ docker images commit
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
commit test ac479108b0fa About a minute ago 111 MB
$ docker run commit:test ls /new-file
/new-file
	   
docker export

Экспортирует содержимое файловой системы контейнера в виде архива tar в STDOUT. Получающийся в результате архив может загружаться при помощи docker import. Отметим, что экспортируется только файловая система; все метаданные, такие как раскрытые порты, установки CMD и ENTRYPOINT будут утрачены. Также отметим, что никакие тома не включаются в этот экспорт. Противопоставляется docker save.

docker history

Выводит информацию по каждому уровню в образе.

docker images

Предоставляет список локальных образов, включая информацию подобную имени репозитория, имени тэга и размеру. По умолчанию промежуточные образы (используемые при создании образов верхнего уровня) не отображаются. VIRTUAL SIZE является общим размером образа, включающим все лежащие в его основе уровни. Поскольку эти уровни могут использоваться совместно с другими образами, простое сложение всех этих размеров не обеспечивает точную оценку использования диска. Кроме того, образы могут появляться много раз если они имеют более одного тэга; различные образы могут распознаваться по сравнению их идентификаторов. Принимает различные параметры; в частности, отметим -q, возвращающий только идентификаторы образов, что очень полезно в качестве входной информации для прочих команд, например, docker rmi.

Например:

$ docker images | head -4
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
identidock_identidock latest 9fc66b46a2e6 26 hours ago 839.8 MB
redis latest 868be653dea3 6 days ago 110.8 MB
containersol/pres-base latest 13919d434c95 2 weeks ago 401.8 MB
	   

Чтобы удалить все подвисшие образы:

$ docker rmi $(docker images -q -f dangling=true)
Deleted: a9979d5ace9af55a562b8436ba66a1538357bc2e0e43765b406f2cf0388fe062
	   
docker import

Создает образ из файла архива, содержащего файловую систему, например, из созданного docker export. Архив может задаваться путем к файлу, или URL, или получаться из потока через STDIN (при использовании флага -). Возвращает идентификатор вновь созданного образа. Образ может быть помечен поддержкой репозитория и именем тэга. Отметим, что образ построенный из import будет состоять только из одного уровня и потеряет все установки настрое Docker такие как раскрытые порты и значения CMD. Противопоставляется docker load

Пример "выровненного" посредством экспорта и импорта образа:

$ docker export 35d171091d78 | docker import - flatten:test
5a9bc529af25e2cf6411c6d87442e0805c066b96e561fbd1935122f988086009
$ docker history flatten:test
IMAGE CREATED CREATED BY SIZE COMMENT
981804b0c2b2 59 seconds ago 317.7 MB Imported from -
	   
docker load

Загружает репозиторий из архива tar, передаваемого через STDIN. Этот репозиторий может содержать различные образы и тэги. В отличие от docker import, данные образы будут содержать историю и метаданные. Продходящие файлы архива создаются командой docker save, делая save и load жизнеспособной альтернативой реестру для распространения образов и поддеживая резервные копирования. В качестве примера посмотрите docker save.

docker rmi

Удаляет заданный образ или образы. Образы определяются идентификатором или именами репозитория или тэга. Если предоставляется имя репозитория без имени тэга, значение тэга предполагается установленным в latest. Чтобы удалить образы, которые существуют во множестве репозиториев, определите такой образ идентификатором и примените параметр -f. Вам придется выполнить это по разу для каждого репозитория.

docker save

Сохраняет поименованные образы или репозитории в архив tar, который передаётся в поток STDOT (для записи в файл используйте -o). Образы могут определяться идентификатором или в виде repository:tag. Если задано только имя репозитория, в таком репозитории будут сохранены все образы, а не только помеченные тэгом latest. Может быть использован совместно с docker load для распространения образов или их резервного копирования.

Например:

$ docker save -o /tmp/redis.tar redis:latest
$ docker rmi redis:latest
Untagged: redis:latest
Deleted: 868be653dea3ff6082b043c0f34b95bb180cc82ab14a18d9d6b8e27b7929762c
...
$ docker load -i /tmp/redis.tar
$ docker images redis
REPOSITORY          TAG            IMAGE ID            CREATED
VIRTUAL SIZE
redis               latest         0f3059144681        3 months ago
111 MB
	   
docker tag

Связывает имя репозитория и тэга с образом. Образ может определяться идентификатором или репозиторием и тэгом (если никакой не определен, предполагается тэг latest). Если никакой тэг не задан для нового имени, предполагается latest.

Например:

$ docker tag faa2b75ce09a newname1
$ docker tag newname:latest amouat/newname2
$ docker tag newname:latest amouat/newname:newtag3
$ docker tag newname:latest myregistry.com:5000/newname:newtag4
	   
1

Добавляет образ с идентификатором faa2b75ce09a в репозиторий newname, используя тэг latest, поскольку никакой другой не определён.

2

Добавляет образ newname:latest в репозиторий amouat/newname, опять применяется тэг latest. Эта метка присутствует в формате удобном для размещения в Docker Hub в предположении, что пользователем является amouat.

3

Аналогично предыдущему, за исключением замены тэга latest на newtag.

4

Добавляет новый образ newname:latest в репозиторий amouat/newname с тэгом newtag. Эта метка представляется в формате, удобном для размещения по адресу http://myregistry.com:5000.(((range="endofrange",startref="ix_04_docker_fundamentals-asciidoc23")))(((range="endofrange",startref="ix_04_docker_fundamentals-asciidoc22"))).

 Использование реестра

Следующие команды относятся к использованию реестра, включая Docking Hub. Убедитесь что Docker сохраняет мандаты в файл .dockercfg в вашем домашнем каталоге:

docker login

Регистрируется или входит на заданный сервер реестра. Если не определён никакой сервер, предполагается, что им будет Docker Hub. По мере необходимости процесс будет запрашивать подробности, либо они могут быть определены в качестве параметров.

docker logout

Выходит из реестра Docker. Если не определен никакой сервер, предполагается что это Docker Hub.

docker pull

Загружает заданные образы из реестра. Реестр определяется по имени образа и по умолчанию предполагается Docker Hub. Если не указано имя тэга, будет загружаться образ помеченный тэгом latest (если доступен). Для загрузки всех образов из репозитория применяйте параметр -a.

docker push

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

docker search

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

 Заключение

В данной главе мы предоставили много информации! Даже если вы только пробежались по основным моментам, вы должны получить достаточно широкое понимание того как работает Docker и его основных команд. В Части 2 мы увидим как применять эти знания в проектах программных продуктов, причем начиная с их разработки до производства. Вы можете найти материалы данной главы более понятными после их рассмотрения на практике.