Команда docker build на windows

Обновлено: 01.07.2024

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

Docker-образы

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

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

Руководитель направления (Technical Product Manager)

Sportmaster Lab , Липецк, Санкт-Петербург, Москва , От 200 000 до 300 000 ₽

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

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

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

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

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

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

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

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

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

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

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

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

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

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

LABEL

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

WORKDIR

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

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

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

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

ENTRYPOINT

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

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

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

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

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

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

EXPOSE

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

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

VOLUME

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

Заключение

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

Docker — это технология, которая позволяет создавать и использовать приложения в «родном» окружении. В основе Docker лежит идея: если приложение работает у вас, то оно должно работать где угодно. Способ этого добиться очень простой — нужно упаковать настройки окружения вместе с приложением.

Docker чаще всего применяется для развёртывания серверных приложений, но может использоваться и в мире фронтенда для:

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

Как начать

  • Windows — Docker Desktop for Windows
  • macOS — Docker Desktop for Mac
  • Linux — в зависимости от версии: CentOS, Debian, Fedora, Raspbian, Ubuntu.

Запустите Docker и проверьте его работоспособность с помощью графического интерфейса Dashboard (для Mac или Windows) или команды в терминале (для всех операционных систем):

У создателей Docker есть готовая демка, которую можно запустить командой:

Как понять

Запуск готового веб-приложения — наиболее популярный сценарий использования. Демка Docker — самое простое, что можно сделать «из коробки». Вам не пришлось устанавливать и запускать веб-сервер, не пришлось разбираться с какими-либо настройками, вы не трудились устанавливать у себя Node.js и не столкнулись ни с какими сложностями. Представьте, что вы передали проект другому разработчику, и вам не приходится возиться с тем, чтобы проект запускался, не приходится говорить: «А у меня все работало 😞»

Без Docker вы, скорее всего, действовали бы так:

  1. Узнали операционную систему на компьютере разработчика.
  2. Сформировали сценарий или инструкцию настройки окружения.
  3. Протестировали, как развёртывается ваше приложение.
  4. Передали приложение разработчику и ждали результаты.

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

Docker упаковывает приложение так, что будет счастлив любой, кто его получит 😇

Давайте разберёмся, как это происходит. Что должен делать Docker с вашим приложением, какое окружение он должен подготовить?

Рассмотрим пример с демкой от создателей Docker. Когда вы выполнили команду docker run , произошло следующее:

  1. Docker нашёл и загрузил приложение с именем docker/getting-started из реестра приложений Docker Hub. Приложение уже было заботливо упаковано со всеми необходимыми ему утилитами и программами. Такая упаковка называется образ (Docker Image). Образ обычно содержит в себе операционную систему на базе Linux, стартовую конфигурацию для установки служб, утилит, приложений, зависимостей проекта — все это называется окружением приложения.
  2. Docker создал контейнер (Docker Container) на основе образа. Контейнер — это конкретный экземпляр образа на вашем компьютере. Отношение «образ — контейнер» примерно такое же, как у пары «класс — объект класса» в ООП.
  3. Docker запустил контейнер с веб-сервером Nginx внутри, и веб-приложение «Справка по Docker» заработало. Для вашей операционной системы запустить контейнер — это все равно что запустить любое приложение или сервис.

Вы просто начали использовать веб-приложение, никаких сложностей.

Модель стандартного применения Docker

Перед тем, как мы научимся готовить образ сами, необходимо разобраться с терминами. Лучше сделать это на берегу 😎

Важные службы

Движок Docker Engine — приложение для управления объектами Docker. Оно включает в себя три компонента:

  1. сервер (Docker Daemon);
  2. интерфейс (Docker API);
  3. консольный клиент (Docker CLI).

Ваш компьютер называется Docker Host. Все операции, которые мы выполняем в интерфейсе или через консоль, выполняются сервером через API движка.

Docker Desktop — пакет приложений с графическим интерфейсом, включающий специальную виртуальную машину для работы с движком, визуальный интерфейс (Dashboard), консольный клиент, инструменты для работы с реестром Docker Hub и пр.

Для платформы Mac и Windows невозможно использовать Docker Engine напрямую, необходимо запустить виртуальную машину. Docker Desktop содержит такую виртуальную машину. Все процессы в ней оптимизированы, контейнеры работают быстрее, но определённые ограничения все равно присутствуют.

Объекты Docker

Образ (Docker Image) — прототип будущего контейнера, содержащий операционную систему, приложение или проект для сборки приложения. Образы состоят из слоёв. Каждый новый слой — это надстройка над предыдущим. Слои должны надстраиваться поверх базового образа, формируя новый. Например, базовым образом может быть образ операционной системы.

Слои образа описываются в специальных файлах конфигурации. Как правило, для этого используется Dockerfile. Конфигурационный файл всегда начинается с указания базового образа, имя которого прописывается после директивы FROM . Дальше могут идти разные надстройки (новые слои) образа. Вы можете задать рабочую папку проекта с помощью директивы WORKDIR , скопировать файлы в эту рабочую папку директивой COPY , запустить выполнение команды или нескольких команд в терминале директивой RUN . Пример конфигурации:

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

Том (Docker Volume) — папка, которую можно подключить (говорят «примонтировать») к контейнерам. Папка может быть связана с конкретной папкой на вашем компьютере, а может быть как бы сетевой для контейнеров на вашем компьютере. Тома необходимы для хранения файлов конфигурации, критических с точки зрения безопасности, файлов баз данных, файлов, которые нельзя удалять после окончания работы приложения.

Сеть (Docker Network) — виртуальная локальная сеть, которая позволяет совместно использовать несколько запущенных контейнеров и соединять запущенный контейнер с вашим компьютером. В основном вы будете использовать три режима работы сетевой инфраструктуры Docker:

  1. bridge — когда контейнеры могут взаимодействовать между собой как веб-сервер и база данных.
  2. host — для доступа к локальному сетевому окружению на вашем компьютере.
  3. none — сеть для контейнеров полностью отключена.

Инструменты

Docker Hub (реестр) — официальный реестр образов.

Опубликованные образы хранятся в Docker Hub. Существуют и другие публичные реестры образов:

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

Docker CLI — консольный клиент, позволяющий управлять Docker через интерфейс командной строки.

Консольный клиент содержит команды для управления объектами Docker. Список основных команд:

Как пользоваться

Ключи командного интерфейса Docker CLI хорошо проработаны и похожи на консольные команды в bash. Например, дополнительный ключ prune позволяет удалять неиспользуемые объекты. Ключ rm служит для удаления, а ключ ls для просмотра объектов. Объекты Docker в обязательном порядке имеют уникальное имя. Если вы не именуете объект специально, то имя объекта формируется с помощью хэш-функции. Если вы попытаетесь создать объект одного и того же типа с уже использованным именем, в этом вам будет отказано. Как же пользоваться консольным клиентом?

Мониторинг запущенных контейнеров

  • docker ps — просмотр запущенных контейнеров.
  • docker ps -a — ключ -a выводит и запущенные, и остановленные контейнеры.
  • docker ps -s — ключ -s выводит дисковое пространство, используемое каждым запущенным контейнером.
  • docker ps -f name=hello — ключ -f фильтрует список контейнеров по имени, например, hello .

Полный список ключей для команды docker ps доступен в документации.

Запуск контейнеров

Для запуска контейнера, который доступен локально или на Docker Hub, выполните команду:

Ключ --name используется для установки имени запущенного контейнера. Ключи -i и -t указывают, что для запуска контейнера будет использоваться стандартный поток ввода и терминал TTY соответственно. Для того чтобы при запуске контейнера примонтировать том, который будет связан с папкой на вашем компьютере, а потом получить доступ к контейнеру через терминал, выполните команду:

Полный список ключей для команды docker run доступен в документации.

Управление образами

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

Ключи prune , rm действуют обычным способом, позволяя удалить неиспользуемые или конкретные образы соответственно. Для работы с реестром необходимо использовать следующие команды:

  • docker image pull hello — загрузка образа с именем hello из реестра;
  • docker image push hello — отправка образа с именем hello в реестр;
  • docker image inspect hello — полная информация о контейнере hello ;
  • docker image build — собрать контейнер из текущей папки с учётом Dockerfile.

Полный список ключей для команды docker image доступен в документации.

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

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

Команда для запуска контейнера:

Команда для перезапуска контейнера:

Команда для остановки контейнера:

Команда для постановки контейнера на паузу:

Полный список ключей для команды docker container доступен в документации.

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

  • docker volume ls — вывод всех томов.
  • docker volume ls -f name=hello — вывод всех томов с фильтрацией по имени, например, hello .
  • docker volume create hello — создание нового тома, например, hello .
  • docker volume inspect hello — исчерпывающая информация о томе.

Полный список ключей для команды docker volume доступен в документации.

На практике

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

Рассмотрим несколько примеров, когда Docker может пригодиться.

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

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

Попробовать движок сайта без установки

Иногда нам нужно посмотреть, как работает та или иная CMS (Content Management System). CMS — это веб-приложение, которое позволяет управлять содержимым сайта и внешним видом через веб-интерфейс. Чтобы такое приложение заработало, нужно установить базу данных, веб-сервер и интерпретатор языка, на котором написана CMS. Но можно и ничего не устанавливать! Docker позволяет запустить CMS одной командой. После запуска вы сможете работать с CMS через веб-интерфейс в своём браузере или через терминал, если понадобится доступ к файлам и ресурсам приложения.

Запускаем Wordpress одной командой:

Запускаем Drupal командой:

Попробовать новый фреймворк

Фронтенд-разработчику Docker даёт возможность попробовать разные технологии без траты времени на установку и настройку. Например, упаковать приложение на платформе Node.js в контейнер не составит большого труда. Добавьте в проект файл Dockerfile:

После этого выполните команду:

Точка в конце означает, что образ собирается из текущей папки. По умолчанию для сборки используется файл с именем Dockerfile. После ключа -t можно задать имя образа:

После сборки вы сможете запустить контейнер с приложением внутри него.

Вы можете начать проект на Angular, React или Vue, полностью переместив разработку внутрь контейнера. Популярные редакторы так или иначе поддерживают эту возможность. Такой подход позволит учитывать все особенности и тонкости настройки проекта не только вам, как автору, но и тем, кто будет работать с проектом в будущем.

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

Готовить картинки и другие ресурсы

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

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

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

Можно также заменить эту длинную команду алиасом в файле настроек терминала:

Предварительно надо написать соответствующий скрипт в файле

После этого вы сможете производить всякие манипуляции со шрифтами простой командой, используя параметры утилиты glyphhanger :

Первое знакомство с Docker - 1

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

Вступление

В данном небольшом обзоре хочется затронуть такую тему, как контейнеризация. И начать нужно с понимания того, что такое вообще контейнеризация. Согласно википедии "Контейнеризация" — это виртуализация на уровне операционной системы (то есть НЕ аппаратная), при которой ядро операционной системы поддерживает несколько изолированных экземпляров пространства пользователя вместо одного. "Пространство пользователя" — это адресное пространство виртуальной памяти операционной системы, отводимое для пользовательских программ. Экземпляры пространства пользователя (обычно называемые контейнерами) с точки зрения пользователя полностью идентичны отдельному экземпляру операционной системы. Ядро обеспечивает полную изолированность контейнеров, поэтому программы из разных контейнеров не могут воздействовать друг на друга. Получается, что контейнеризация — это программная виртуализация, то есть виртуализация на уровне операционной системы, за которую отвечает ядро операционной системы. Одной из характерных черт такого подхода является использование всеми контейнерами общего ядра, того же, что и у хостовой операционной системы (то есть той, в которой размещены контейнеры). Это позволяет избавиться от накладных расходов на эмуляцию виртуального оборудования и запуска полноценного экземпляра операционной системы. Можно сказать, что это "легковесная" виртуализация. Ядро (kernel) — центральная часть ОС, обеспечивающая приложениям координированный доступ к ресурсам компьютера, таким как процессорное время, память, внешнее аппаратное обеспечение, внешнее устройство ввода и вывода информации. Также обычно ядро предоставляет сервисы файловой системы и сетевых протоколов. В общем, это сердце всей системы. В качестве дополнительной информации может быть полезно ознакомиться с материалом "Общие сведения о контейнерах". И ещё пару слов, чтобы вступление было полным. У нас теперь есть понимание, что в операционной системе есть ядро. Оно обеспечивает изолированность экземпляров пространств пользователей. В этом контексте Вы можете встретить такой термин как "cgroups". Так называется как раз тот самый механизм ядра Linux, который позволяет этого добиться. Поэтому, можно сказать, что путь контейнеризации начался с Linux систем. Однако, начиная с Windows 10 тоже появилась поддержка контейнеризации. Для работы с виртуализацией необходимо в BIOS компьютера настроить поддержку виртуализации. Как это сделать зависит от компьютера. Например, это может выглядеть так:

Первое знакомство с Docker - 2

На Windows это можно проверить разными способами. Например, можно скачать специальную утилиту с сайта Microsoft: Hardware-Assisted Virtualization Detection Tool. Ну и стоит упоминуть ещё одно важное понятие — Гипервизор. Гипервизор (Hypervisor) — это монитор виртуальных машин, программа для обеспечения параллельного выполнения нескольких операционных система на одном и том же компьютере. Гипервизор обеспечивает изоляцию операционных систем друг от друга, разделяет между запущенными ОС ресурсы. Одним из таких гипервизоров является Oracle VirtualBox.

Первое знакомство с Docker - 3

Docker

Итак, что такое виртуализация — понятно. Но как этим пользоваться? И тут нам на помощь приходит Docker. Docker — программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации. Стоит начать с того, что Docker представлен таким понятием, как Docker Enginge. И начать стоит с официального сайта докера и раздела "Docker Overview".

Первое знакомство с Docker - 4

  • Докер-сервера, который называется Docker Daemon process (dockerd).
  • Интерфейс коммандной строки, он же CLI (docker).
  • REST API, который описывает то, каким образом программы могут "разговаривать" с deamon и давать ему указания, что делать.

Первое знакомство с Docker - 5

Docker Toolbox

Для установки Docker на старые, не подходящие под системные требования, машины. На сайте так и написано, "Legacy Desktop Solution". Перейдём на страницу "Docker Toolbox" и скачаем его. Весит такой набор около 211 мегабайт. Установим в комплектации по умолчанию, то есть просто будем безропотно соглашаться со всем, не переставляя флаги. После установки проверим, что всё хорошо. В дальнейшем нашим полем боя будет коммандная строка. Рекомендую не использовать коммандную строку Windows, потому что с ней могут быть неочевидные проблемы. Лучше использовать bash shell. На Windows самый рекомендуемый способ получения его - установить себе систему контроля версий git, всё равно она пригодится. Потому что "в комплекте" с ним будет и нужный нам bash. Для данного обзора я буду использовать именно git bash. Так же bash можно поставить вместе с CYGWIN. Запустим bash или git bash. Убедимся, что у нас установилась докер машина, она же Docker Machine: docker-machine -version Что такое эта Docker Machine? Docker Machine — это утилита для управления докеризированными хостами (это такие хосты, на которых установлен Docker Engine). Если мы выполним сразу же после установки Docket Toolbox просмотр докер-машин при помощи комманды docker-machine ls , то увидим пустой список:

Давайте создадим новую машину. Для этого нам понадобится выполнить комманду create: docker-machine create -- driver virtualbox javarush : Мы увидим лог создания докер машины:

Первое знакомство с Docker - 7

Тут интересно нам следующее. Что за Boot2Docker? Это минималистичный дистрибутив Linux для запуска Docker Engine (мы ведь поним, что Docker работает благодаря средствам виртуализации Linux, а в Windows необходимый механизм появился только начиная с Windows 10). Этот дистрибутив основан на дистрибутиве "Tiny Core Linux". Так же упоминается про VirtualBox VM. Это потому, что мы указали --driver virtualbox . Была создана новая виртуальная машина в VirtualBox из образа Boot2Docker. После создания мы можем запустить VirtualBox (т.к. VirtualBox установливаяется вместе с Docker Toolbox) и увидеть созданную виртуальную машину для докер машины:

После создания нам предложат выполнить комманду "docker-machine env", чтобы получить переменные среды, которые нужно настроить для подключения к докер машине:

Первое знакомство с Docker - 9

После выполнения этой комманды при помощи docker-machine мы подключаемся к удалённому докеризированному хосту (в данном случае виртуальному, размещённому на Virtual Box) и можем выполнять комманды docker у себя локально так, словно бы выполняли их на удалённом хосте. Для проверки можем выполнить комманду "docker info". В случае, если подключения к докер машине не установлено, мы получим ошибку. А если всё хорошо — информацию о докере на докер машине. Теперь самое время разобраться с тем, как вообще работает докер и как его использовать.

Первое знакомство с Docker - 10

Docker Containers

Итак, у нас есть докер. Что такое вообще этот докер? Понять это нам поможет документация Docker и раздел "Get started". В вводной части этого раздела рассказывается по концепцию докера (Docker Concepts). Там указано, что докер — это платформа для разработки, отладки и запуска приложений в контейнерах. Поэтому, главное для докера — это контейнеры. Даже если вы посмотрите на логотип докера - это кит, который держит на своей спине контейнеры. Но что такое контейнер? Далее в разделе "Images and Containers" говорится, что контейнер — это запущенный экземпляр Image. А Image — это выполняем "пакет", который содержит всё необходимое для приложения (код, окружение, библиотеки, настройки и т.д.). Теперь давайте попробуем это сами. На сайте Docker'а есть раздел "Docker samples", в котором есть "Docker for Beginners". Примеры отсюда мне кажутся более интересными. Итак, мы вдруг захотели ознакомиться с Alpine Linux и можем это сделать при помощи контейнеров докера. Чтобы получить образ, мы должны его "вытянуть" или "вытащить". Поэтому, выполняем комманду docker pull: docker pull apline

Первое знакомство с Docker - 12

Теперь, у нас есть образ apline. Так как контейнер — запущенный экземпляр image, то давайте запустим этот самый образ. Выполним запуск контейнера при помощи комманды docker run alpine . Как мы видим, ничего не произошло. Если мы выполним комманду docker ps для вывода всех активных контейнеров, то тоже ничего не получим. Но если мы выполним docker ps -a то увидим все контейнеры:

Первое знакомство с Docker - 13

Всё дело в том, что мы запустили докер не в интерактивном режиме. Поэтому, он выполнил комманду и остановился. Комманда была — открытие терминала. Давайте выполним тоже самое, но в интерактивном режиме (с флагом -it):

Первое знакомство с Docker - 14

Как видно, преодолев одну ошибку и воспользовавшись подсказкой мы попали на контейнер и можем в нём работать! Чтобы выйти из контейнера не прекращая его работу можно нажать Ctrl + p + q . Если выполнить теперь docker ps , то мы увидим один активный контейнер. Чтобы зайти на уже запущенный контейнер, выполним комманду docker exec:

Отличное описание того, как это всё происходит рекомендую прочитать в описании докер сэмпла: "1.0 Running your first container". Он мне нравится за то, что там всё написано очень доступно и понятно. Если кратко перефразировать, то мы подключены при помощи docker-machine к виртуальной машине, на которой запущен Docker Daemon. При помощи CLI по REST API мы просим запустить alpine образ. Докер его находит и поэтому не скачивает. Докер создаёт новый контейнер и запускает в этом контейнере указанную нами комманду. И всё это, конечно, хорошо. Но зачем нам это всё? И тут нам надо разобраться, как вообще докер создаёт image. А создаёт он их на основе докерфайла (dockerfile).

Первое знакомство с Docker - 16

Dockerfile

  • Откроем билд скрипт build.gradle и поправим его, согласно разделу: "Add a Gradle build file".
  • Добавим страницы в src/main/webapp, как указано в разделе "Add JSP pages to the demo application".
  • Добавим класс HelloServlet с содержимым из раздела "Add a servlet and metadata to the project".

Теперь, для проверки в build.gradle добавим плагин gretty, как указано в разделе "Add the gretty plugin and run the app": Интересно, что Gretty не видит ошибку в HelloServlet , которая описана выше. Это доказывает, что в разном окружении приложение себя может вести по-разному. Gretty может работать там, где обычный standalone сервер выдаст ошибку. Осталось проверить, что приложение работает правильно. Выполним: gradle appRun

Первое знакомство с Docker - 18

Если всё хорошо, то коммандой gradle war соберём архив с расширениеи war (web archive). По умолчанию gradle собирает его в каталоге \build\libs . Теперь, мы готовы написать наш докерфайл. Руководствуясь "Dockerfile reference" создадим докерфайл. Создадим файл с названием "Dockerfile" в корне нашего Java проекта (там же, где build скрипт). Откроем его на редактирование. У данного файла есть свой формат, описанный в разделе "Dockerfile reference : Format". Любой докерфайл начинается с инструкции FROM, указывая "базовый образ" (base image). Можно сказать, что это родительский образ, на основе которого мы делаем наш image. Родительский образ нам выбрать очень просто. Веб-приложению нужен веб-сервер. Например, мы можем использовать веб-сервер Tomcat. Заходим на официальный репозиторий докера, который называется docker hub. Ищем там, есть ли нужный нам image:

Первое знакомство с Docker - 19

Первое знакомство с Docker - 20

Как мы видим, разница огромна. Если мы будем строить наш образ на основе tomcata alpine, то мы начнём всего со 100 мегабайт, а не с 600. Соответственно, в ранее созданный докерфайл добавим следующее содержимое: И теперь выполним команду построения образа: docker build -t jrdocker . .

-t — это tag, то есть как назвать собранный образ. Точкой в конце мы обозначаем, что текущий каталог (каталог, где находится докерфайл и откуда мы запускали команду) добавляем в Build context . Build context — это контекст тех файлов, которые доступны при создании докерфайла. Как видно, мы смогли скопировать благодаря этому собранный war файл в наш образ, в каталог веб-сервера. Теперь запустим наш образ: docker run -d --rm -p 8888:8080 jrdocker

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

Первое знакомство с Docker - 23

Ну и не забываем, что мы по имени всегда можем зайти на запущенный контейнер командой: winpty docker exec -it ИмяКонтейнера sh Теперь осталось подключиться. Ранее мы указали EXPOSE, то есть изнутри контейнера разрешили доступ к порту 8080. Когда же мы запускали сам контейнер, мы указали тэг -p (incoming ports), тем самым соотнесли порт 8080 на контейнере (там ожидает подключения веб-сервер томкат) с портом 8888 на машине с докер демоном. Как мы помним, докер демон мы запустили не напрямую, а через docker-machine. Поэтому, ещё раз спросим данные по нашим докер машинам при помощи команды docker-machine ls и обратимся на сервер в контейнере:

Первое знакомство с Docker - 24

Таким образом, мы с Вами только что запустили своё веб-приложение в докер контейнере! ) Ещё хотелось бы отметить следующее. В случае возникновения проблем с доступом следует помнить, что докер машина в первую очередь это виртуальная машина Virtual BOx. Возможно, проблемы в настройках сети виртуальной машины. Рабочая конфигурация VMBox может выглядеть следующим образом:

Первое знакомство с Docker - 25

Первое знакомство с Docker - 26

Слои (layers)

Мы с вами уже разобрались, что образы создаются из докерфайлов и что докерфайлы — это набор комманд. Ещё мы разобрались, что у докерфайла есть родительский. И что размер образов разный. Интересно, что можно посмотреть историю того, как собирался образ при помощи команды docker history. Например:

Первое знакомство с Docker - 27

Важно об этом сказать для понимание того, что по своей сути каждый образ - это набор образов. Каждое изменение образа (каждая новая команда в докерфайле) создаёт новый слой, который имеет свой ID. Подробнее про слои можно прочитать в документации "Docker: Images and Layers". Так же очень рекомендую к ознакомлению статью на хабре: "Образы и контейнеры Docker в картинках".


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

Наверняка многие из вас проводили по одному-два дня, пыт а ясь настроить кластер Docker или получая часть кода, которая продолжает проваливать загрузку контейнера Docker. Большинство разработчиков много времени затрачивают именно на конфигурирование — поиск багов становится делом, которое, как начинает казаться, перевешивает временные затраты на саму разработку нового функционала. Это особенно актуально, когда вы работаете в новой среде или среде, которая ещё не достигла своей “зрелости”.

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

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

Совет: каждая команда Docker имеет встроенную документацию, которую вам необходимо научится использовать. Напечатав docker run --help , вы увидите следующую вспомогательную документацию:


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

Это создаст образ Docker с опциональными аргументами сборки. Docker будет по умолчанию кэшировать результаты для первой сборки Dockerfile или последующих сборок, основанных на слоях, добавленных к образу через команду run в Dockerfile, что позволит этим сборкам работать быстрее. Если вам это не нужно, можете добавить аргумент “no-cache”, как это сделано в примере выше.

Заметка: команды Docker могут быть выполнены по имени или по ID контейнера. <CONTAINER> допускает подстановку либо ID контейнера, либо его имени.

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

Остановка существующего контейнера Docker.

Если у вас есть несколько запущенных контейнеров Docker, и вы хотите остановить их все, наберите docker stop и список ID этих контейнеров.

Выполнение команды оболочки внутри конкретного контейнера.

Существует чёткое различие между Docker run и start . run по сути делает две вещи: 1) создаёт новый контейнер образа и 2) выполняет этот контейнер. Если вам когда-нибудь понадобится повторно запустить давший сбой или совершивших выход контейнер, используйте команду docker start .

Это интересная команда, предназначенная для единовременного создания и запуска контейнера. Она также запускает команду внутри него и затем, после выполнения этой команды, удаляет контейнер.

Если вы хотите запустить команду docker run в отдельном состоянии — например, в качестве демона (фоновый процесс) в Linux, то можете добавить -d к этой команде(ам) run .

Приостановить все запущенные процессы внутри конкретного контейнера.

Эта команды выводит список всех образов Docker, запущенных ранее. Как только вы определили образ, который нужно запустить, выполните команду, приведённую ниже. Убедитесь, что изменили ID контейнера, чтобы он отображал результаты, показанные изначальной командой docker ps -a .

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

Если вам когда-нибудь придётся раскрывать порты Docker, то имейте в виду, что для проброса портов команда запуска получает аргумент -p . Там, где host_public_port — это порт вашей машины, вам нужно, чтобы Docker переадресовал container_port . Для дополнительных портов также добавляйте аргументы -p .

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

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

В случае с Docker образы создаются на верхушках слоёв, которые являются строительными элементами этих образов. Каждый контейнер состоит из образа с читаемым/записываемым слоем, который вы можете рассматривать как постоянное состояние или файл. Помимо этого, добавляются и другие слои, доступные только для чтения. Эти слои (также называемые промежуточными образами) генерируются, когда при выполнении команды build образа Docker выполняются команды в Dockerfile.

Если у вас есть директива from , run и/или copy в Dockerfile и затем вы build этот образ, то благодаря этой директиве run будет создан один слой со своим собственным ID образа. Этот образ/слой затем покажется в docker history с этим ID образа и датой его создания. Последующие директивы продолжат генерацию аналогичных записей. При этом колонка CREATED BY будет приблизительно соответствовать строке в Dockerfile, как это показано на следующем изображении:


Список всех образов, хранящихся в данный момент на машине.

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

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

  • ID контейнера и временную метку его создания.
  • Текущий статус (полезен при выяснении, остановлен ли контейнер и, если остановлен, то почему).
  • Информация образа Docker, информация о привязках к файловой системе и томе, а также о подключениях.
  • Переменные среды — например, параметры командной строки, переданные в контейнер.
  • Конфигурация сети: IP адрес и шлюз, а также второстепенные адреса для IPv4 и IPv6.

Отображение версии Docker, включая версию клиента и сервера, установленные на машине в данный момент.

Да, вы всё правильно поняли. Docker — это клиент-серверное приложение. Демон (продолжительно выполняемая фоновая служба Linux) — это сервер, а CLI — это один из многих клиентов. Демон Docker раскрывает REST API, посредством которого с ним могут взаимодействовать различные инструменты.


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

Честно говоря, причиной тому может быть многое, включая: 1) проблемы кода, например, было выброшено не перехваченное исключение, и контейнер Docker не запустился, 2) вам не хватает пространства на жёстком диске, если вы используете кластер ECS в экземплярах EC2 и при этом для размещения ECS не используете Fargate, 3) ваш действующий контейнер Docker исчерпал доступную EC2 память.

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

Здесь пояснения не требуются.

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

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

Убить выполняющийся контейнер.

Убить все выполняющиеся контейнеры.

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

Удалить все контейнеры, незапущенные в данный момент.

Получить доступ к журналам контейнера (полезно при отладке).

Docker Hub — это служба Docker для нахождения и совместного использования образов контейнеров.

Если вы хотите извлечь оттуда образы для локального реестра, то это так же просто, как выполнение команды run , сопровождаемой путём образа. Нижеприведённая команда демонстрирует извлечение и запуск стабильной версии образа R Rocker.

Docker сперва проверит, доступен ли этот образ на вашей локальной машине. Если нет, он приступит к его загрузке с репозитория Docker Hub. Такое поведение предусмотрено изначально.

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

Для входа на Docker Hub вы можете запустить вышеприведённую команду, которая предложит ввести пароль.

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

/.docker/config.json для изменения деталей авторизации.

Реестр Elastic-контейнеров (ECS) — это полноценно поддерживаемый реестр контейнеров Docker, позволяющий разработчикам хранить, поддерживать и разворачивать образы контейнеров Docker. Amazon ECS отлично работает с Amazon ECR. Если вам вдруг понадобится извлечь образы из реестра ECR, следуйте следующим инструкциям.

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

Amazon ECR требует, чтобы ключи пользователя IAM имели разрешения ( ecr:GetAuthrizationToken ) через политику IAM, только тогда вы сможете авторизоваться и извлечь образы. В качестве альтернативы вы можете использовать утилиту Amazon ECR Docker Credential Helper. Ниже представлен подход, предполагающий использование вами AWS CLI и корректную настройку всех разрешений.

Команда get-login генерирует длинную команду входа Docker. Скопируйте её и выполните. Авторизация необходима, чтобы получить возможность извлекать образы из AWS ECR.

Если вам понадобится экспортировать образ Docker на диск и загрузить обратно, вышеуказанная команда это осуществит.

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

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