Docker  —  платформа с открытым исходным кодом для создания, развертывания и управления контейнеризированными приложениями.

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

Содержание:

  1. Образы и контейнеры.
  2. Запуск первой программы в Docker.
  3. Основные команды контейнеров Docker.
  4. Командная строка Docker-контейнера.
  5. Пользовательские образы Docker.
  6. Запуск веб-приложения в Docker.
  7. Docker и сопоставление портов.
  8. Выводы.

Официальная документация по установке Docker для разных платформ: Linux, Windows, macOS.


1. Образы и контейнеры

Самые важные концепции Docker!

  • Что такое “образ” или “image”?

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

docker images
Образы Docker!
  • Что такое “контейнер”?

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

Количество контейнеров не ограничено, все они работают на общей инфраструктуре хоста и общей операционной системе. Посмотреть на список контейнеров можно с помощью команды: 

docker ps -a
Контейнеры Docker!

2. Запуск первой программы в Docker

Первым делом нужно вывести на экран фразу “Hello, world!”.

В Docker каждому контейнеру нужен образ, поэтому, чтобы запустить hello-world, введите в консоль или терминал команду:

docker run hello-world
  • Что делает docker run?

Попытка создания и запуска контейнера. Согласно документации API-клиента Docker, в установленном порядке выполняются следующие действия.

  1. Консоль: выполняет команду docker run hello-world.
  2. Docker client (CLI): получает команду и выполняет действия на ее основе.
  3. Сервер Docker: связывается с CLI, чтобы выдать клиенту из кэша образов (Image Cache) нужный образ с названием hello-world. Если такого образа нет, то сервер Docker связывается с хабом Docker, где скачивает образ с указанным именем.
  4. Docker Hub: хаб Docker получает запрос от сервера Docker на загрузку конкретного файла образа из общедоступного хранилища. 
  5. Сервер Docker: снова ищет образ в разделе “Image Cache”, затем создает контейнер  —  экземпляр образа hello-world. 
  6. Контейнер Docker: согласно первоначальным установкам из образа, в контейнере запускается простая программа hello-world. 
  7. Консоль: в результате успешного выполнения всех вышеизложенных этапов отобразит информацию со скриншота.
Ваше первое приложение в Docker!

3. Основные команды контейнеров Docker

Прочитайте перечень команд управления поведением контейнеров без изменения образов.

  • Удалить все неактивные контейнеры Docker:
docker system prune
  • Вывести на экран stderr и stdout от запущенных в контейнере программ, логирование контейнера Docker:
docker logs <container-id>
  • Индекс активных контейнеров:
docker ps
  • Индекс всех контейнеров, включая неактивные:
docker ps -a
  • Индекс образов, установленных в системе на данный момент:
docker images
  • Деактивировать Docker-контейнер по идентификатору:
docker stop <container-id>
  • Удалить неактивный контейнер по идентификатору:
docker rm <container-id>
  • Удалить конкретный образ по его названию:
docker rmi <image-name>

4. Командная строка Docker-контейнера

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

  • Как выполнить команду внутри контейнера Docker?
docker exec -it <container-id> <command>

Здесь exec позволяет выполнять команды в контейнере, а флаг -it разрешает прием ввода от пользователя к процессу, а также вывод в терминал как результата выполнения процесса, так и сообщений об ошибках.

  • Как получить доступ к командной строке контейнера Docker?

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

docker exec -it <container-id> sh

sh выдаст разрешение на ввод подсказок (prompt), и вы сможете выполнять внутри контейнера различные задачи, например:

Ввод с клавиатуры в контейнер Docker!
  • Как разрешить ввод при запуске контейнера из образа Docker?

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

Telegram-канал по теме
NOP::HumorИТ-юмор и мемы о боли разработчиков
Подписаться
docker run busybox

Теперь, чтобы ответить на вышеуказанный вопрос, выполните следующую команду:

docker run -it busybox sh
Разрешение ввода при запуске образа!

Теперь все знания о полезных командах из двух пунктов руководства помогут вам подготовиться к следующему шагу.


5. Пользовательские образы Docker

Как добавить файлы в контейнер и какую операционную систему выбрать для образа?

  • Dockerfile

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

  1. Базовый образ.
  2. Все зависимости и условия запуска программы.
  3. Команду для запуска программы при старте контейнера.
  • Docker Client

После создания dockerfile вы сразу попытаетесь собрать образ. Следовательно, Dockerfile отправляется клиенту Docker.

  • Docker Server

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

  • Как же создать образ Docker?
  1. Сначала напишите dockerfile.
  2. Затем выполните команду docker build.
  3. Теперь запустите образ командой docker run <image-id>.

Рассмотрим простой dockerfile, в котором установлен сервер базы данных Redis:

Dockerfile для установки Redis-сервера!

Теперь, глядя на Dockerfile, у вас наверняка возникли вопросы! Ответим на них сейчас:

  • Что такое базовый образ? 

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

  • Почему Alpine?

Alpine Linux  —  это как Windows и macOS, где можно установить почти все, что вам нужно. Alpine занимает мало памяти, что хорошо подходит для установки Redis. Базовый образ загружается через инструкцию FROM.

  • Как установить зависимости?

Посмотрите, в dockerfile написана инструкция ‘RUN’, которая выполняет команды внутри контейнера. APK означает менеджер пакетов Alpine Linux. Команды apk применяются в любой работающей системе на базе Alpine Linux для удаления, установки, обновления программного обеспечения.

  • Как указать команду для запуска приложения в контейнере?

Инструкцией CMD задается команда по умолчанию, которая будет выполняться только при запуске контейнера без указания команды. Приведенный выше пример запустит сервер Redis.

Сервер Redis в контейнере Docker

Теперь поговорим детальнее о команде docker build. Что происходит перед тем, как результат ее выполнения появляется на экране? 

  1. Загружается контейнер с образом alpine.
  2. Файловая система из образа alpine переносится во временный контейнер, в нем и выполняются инструкции по установке базы данных Redis. После завершения установки временный контейнер удаляется, а файловая система переносится обратно в образ alpine, тем самым обновляя его. Теперь в новом образе установлен Redis.
  3. По аналогии создается еще один временный контейнер для установки команды запуска сервера Redis при каждом запуске образа в контейнере. Следом временный контейнер удаляется, а обновленная файловая система устанавливается в конечном пользовательском образе.
  4. Наконец, для запуска контейнера по шаблону пользовательского образа выполняется команда docker run <container-id>.

Примечание: если вы обновите dockerfile образа и попытаетесь пересобрать его, то Docker получит кэш из предыдущего образа, чтобы пропустить тот же процесс. Он обновит только вновь добавленный раздел в Dockerfile. Порядок в Dockerfile также важен. Если вы измените порядок команд, то кэш обнулится!

  • Как установить специфическое имя для образа?

docker build -t <имя>/<репозиторий/имя проекта>:версия . 


6. Запуск веб-приложения в Docker

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

  • Шаг 1
    Напишите файл package.json, ведь Express.js  —  это бэкенд-фреймворк для веб-приложений на Node.js. Укажите в нем последнюю версию при помощи символа звездочки *, а затем укажите запуск по умолчанию для команды node index.js, где index.js  —  это основной веб-файл.
package.json
  • Шаг 2
    Напишите простой файл index.json. Планируется, что фреймворк Express.js через / получает запросы и отправляет обратно ответ. Чтобы получить запрос и ответ, необходимо установить порт для прослушивания.
index.js
  • Шаг 3
    Напишите dockerfile. Помните все ключевые шаги? Если забыли, то поднимитесь вверх по разделам и освежите знания. Тем не менее совершенно очевидно, что для запуска приложения понадобятся установленные, готовые к работе Node.js и NPM.
Dockerfile
  • Шаг 4
    Постройте пользовательский образ, присвойте ему теги.
Запуск образа в контейнере
  • Шаг 5
    Запустите контейнер с приложением, запомните прослушиваемый порт.
Веб-приложение успешно запущено и прослушивает порт 8080
  • Шаг 5
    Проверьте, можно ли получить доступ к приложению из браузера, действительно ли оно работает?
    О, нет! Что-то пошло не так? Пришло время выяснить. 
Ошибка, приложение недоступно

Возможно, у вас сейчас на уме один вопрос: зачем в dockerfile написана команда WORKDIR /usr/app?

Основная цель  —  разделение рабочих файлов, чтобы строго необходимые для работы приложения файлы не смешивались с другими директориями, а легко отделялись от остальных при необходимости, если возникнут проблемы. Следовательно, внутри контейнера файлы веб-приложения сохраняются в каталоге /usr/app.

SSH терминал внутри контейнера

7. Docker и сопоставление портов

Рассмотрим, как разобраться в настройках и правильно установить сопоставление портов!

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

Сопоставление портов позволит запросу на порт 8080 с локальной машины перенаправить запрос на порт 8080 Docker-контейнера, только для входящих запросов. 

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

  • В команде запуска контейнера первый порт  —  это порт хост-машины или локальной машины, а второй порт  —  это порт контейнера:
docker run -p 8080:8080 mahedi/simpleweb
Верно настроенное сопоставление портов

Выводы

Веб-приложение запущено и доступно при обращении к порту 8080 локальной машины.

Приложение работает внутри контейнера Docker!

Несмотря на успех, стоит упомянуть три распространенные ошибки, допускаемые в процессе работы с Docker Server и Docker Client.

  1. Неправильный выбор базового образа.
  2. Отсутствие в dockerfile команд ADD или COPY для переноса файлов хост-машины в контейнер.
  3. Неправильное сопоставление портов при создании контейнера.

Далее прилагаются скриншоты правильно запущенного в Docker веб-приложения Node.js, чтобы вы могли с ними свериться.

Запуск приложения на Node.js в контейнере Docker через собственный dockerfile

Самостоятельно ознакомьтесь с файлом dockerfile для построения пользовательского образа и запуска веб-приложения на Node.js.

Запуск приложения на Node.js в контейнере Docker

Проанализируйте изображенный на скриншоте файл index.js с простым примером веб-приложения на Node.js. Данный файл запускается внутри контейнера Docker при помощи соответствующей команды из dockerfile.

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

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


Перевод статьи Mahedi Hasan Jisan: Everything on Docker! (Part l)

Мы в Telegram — подписывайтесь
NOP::Nuances of ProgrammingСтатьи и переводы для разработчиков — каждый день
Подписаться
NOP::HumorИТ-юмор и мемы о боли разработчиков
Подписаться
NOP::Recruiter RemoteУдалённые ИТ-вакансии с вилками
Подписаться
Предыдущая статьяАрхитектура виртуальной машины Java: объяснение для начинающих
Следующая статьяПочему стоит использовать Pathlib в качестве альтернативы модуля OS