Docker — платформа с открытым исходным кодом для создания, развертывания и управления контейнеризированными приложениями.
Представьте, как вы устанавливаете программное обеспечение, требующее установку всех его зависимостей. Придется столкнуться со множеством ошибок, вручную выяснить и устранить все их причины. Каждый раз — попытки запустить всю систему заново, чтобы наконец-то правильно завершить установку… Именно в этот момент на помощь приходит Docker, пытаясь серьезно облегчить жизнь.
Содержание:
- Образы и контейнеры.
- Запуск первой программы в Docker.
- Основные команды контейнеров Docker.
- Командная строка Docker-контейнера.
- Пользовательские образы Docker.
- Запуск веб-приложения в Docker.
- Docker и сопоставление портов.
- Выводы.
Официальная документация по установке Docker для разных платформ: Linux, Windows, macOS.
1. Образы и контейнеры
Самые важные концепции Docker!
- Что такое “образ” или “image”?
Образ — это файл, хранящий всю конфигурацию запуска программы в контейнере Docker. Посмотреть на список образов, созданных в системе, можно при помощи следующей команды:
docker images
- Что такое “контейнер”?
Контейнер — это экземпляр образа. Docker-контейнер действует как виртуальная машина, но у него нет отдельной операционной системы. Каждый контейнер устанавливает приложения или программное обеспечение, следуя инструкциям, записанным в файлах образа.
Количество контейнеров не ограничено, все они работают на общей инфраструктуре хоста и общей операционной системе. Посмотреть на список контейнеров можно с помощью команды:
docker ps -a
2. Запуск первой программы в Docker
Первым делом нужно вывести на экран фразу “Hello, world!”.
В Docker каждому контейнеру нужен образ, поэтому, чтобы запустить hello-world
, введите в консоль или терминал команду:
docker run hello-world
- Что делает
docker run
?
Попытка создания и запуска контейнера. Согласно документации API-клиента Docker, в установленном порядке выполняются следующие действия.
- Консоль: выполняет команду
docker run hello-world
. - Docker client (CLI): получает команду и выполняет действия на ее основе.
- Сервер Docker: связывается с CLI, чтобы выдать клиенту из кэша образов (Image Cache) нужный образ с названием
hello-world
. Если такого образа нет, то сервер Docker связывается с хабом Docker, где скачивает образ с указанным именем. - Docker Hub: хаб Docker получает запрос от сервера Docker на загрузку конкретного файла образа из общедоступного хранилища.
- Сервер Docker: снова ищет образ в разделе “Image Cache”, затем создает контейнер — экземпляр образа
hello-world
. - Контейнер Docker: согласно первоначальным установкам из образа, в контейнере запускается простая программа
hello-world
. - Консоль: в результате успешного выполнения всех вышеизложенных этапов отобразит информацию со скриншота.
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 запустить образ под названием busybox
. Что вы сделаете?
docker run busybox
Теперь, чтобы ответить на вышеуказанный вопрос, выполните следующую команду:
docker run -it busybox sh
Теперь все знания о полезных командах из двух пунктов руководства помогут вам подготовиться к следующему шагу.
5. Пользовательские образы Docker
Как добавить файлы в контейнер и какую операционную систему выбрать для образа?
- Dockerfile
Основной файл, хранящий все инструкции. Каждый dockerfile
одинаково структурирован. Чтобы создать dockerfile
для пользовательского образа необходимо указать:
- Базовый образ.
- Все зависимости и условия запуска программы.
- Команду для запуска программы при старте контейнера.
- Docker Client
После создания dockerfile
вы сразу попытаетесь собрать образ. Следовательно, Dockerfile отправляется клиенту Docker.
- Docker Server
Далее клиент Docker передает все инструкции серверу Docker, который, в свою очередь, выполняет всю грязную работу, а именно все команды внутри dockerfile
, и создает образ. Затем образ запускается, в результате чего создается контейнер, экземпляр образа.
- Как же создать образ Docker?
- Сначала напишите
dockerfile
. - Затем выполните команду
docker build
. - Теперь запустите образ командой
docker run <image-id>
.
Рассмотрим простой dockerfile
, в котором установлен сервер базы данных Redis
:
Теперь, глядя на Dockerfile, у вас наверняка возникли вопросы! Ответим на них сейчас:
- Что такое базовый образ?
Ни у одного контейнера нет собственной операционной системы. Если вы хотите создать контейнер, то ему нужна отправная точка или базовый образ, с которого он может начать работу.
- Почему Alpine?
Alpine Linux — это как Windows и macOS, где можно установить почти все, что вам нужно. Alpine занимает мало памяти, что хорошо подходит для установки Redis. Базовый образ загружается через инструкцию FROM
.
- Как установить зависимости?
Посмотрите, в dockerfile
написана инструкция ‘RUN’, которая выполняет команды внутри контейнера. APK означает менеджер пакетов Alpine Linux
. Команды apk
применяются в любой работающей системе на базе Alpine Linux
для удаления, установки, обновления программного обеспечения.
- Как указать команду для запуска приложения в контейнере?
Инструкцией CMD
задается команда по умолчанию, которая будет выполняться только при запуске контейнера без указания команды. Приведенный выше пример запустит сервер Redis.
Теперь поговорим детальнее о команде docker build
. Что происходит перед тем, как результат ее выполнения появляется на экране?
- Загружается контейнер с образом
alpine
. - Файловая система из образа
alpine
переносится во временный контейнер, в нем и выполняются инструкции по установке базы данных Redis. После завершения установки временный контейнер удаляется, а файловая система переносится обратно в образalpine
, тем самым обновляя его. Теперь в новом образе установлен Redis. - По аналогии создается еще один временный контейнер для установки команды запуска сервера Redis при каждом запуске образа в контейнере. Следом временный контейнер удаляется, а обновленная файловая система устанавливается в конечном пользовательском образе.
- Наконец, для запуска контейнера по шаблону пользовательского образа выполняется команда
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
— это основной веб-файл.
- Шаг 2
Напишите простой файлindex.json
. Планируется, что фреймворк Express.js через/
получает запросы и отправляет обратно ответ. Чтобы получить запрос и ответ, необходимо установить порт для прослушивания.
- Шаг 3
Напишитеdockerfile
. Помните все ключевые шаги? Если забыли, то поднимитесь вверх по разделам и освежите знания. Тем не менее совершенно очевидно, что для запуска приложения понадобятся установленные, готовые к работе Node.js и NPM.
- Шаг 4
Постройте пользовательский образ, присвойте ему теги.
- Шаг 5
Запустите контейнер с приложением, запомните прослушиваемый порт.
- Шаг 5
Проверьте, можно ли получить доступ к приложению из браузера, действительно ли оно работает?
О, нет! Что-то пошло не так? Пришло время выяснить.
Возможно, у вас сейчас на уме один вопрос: зачем в dockerfile
написана команда WORKDIR /usr/app
?
Основная цель — разделение рабочих файлов, чтобы строго необходимые для работы приложения файлы не смешивались с другими директориями, а легко отделялись от остальных при необходимости, если возникнут проблемы. Следовательно, внутри контейнера файлы веб-приложения сохраняются в каталоге /usr/app
.
7. Docker и сопоставление портов
Рассмотрим, как разобраться в настройках и правильно установить сопоставление портов!
При отправке запроса на порт 8080 вашей локальной машины, он не перенаправляется автоматически на контейнер, так как у контейнера собственное сетевое отображение.
Сопоставление портов позволит запросу на порт 8080 с локальной машины перенаправить запрос на порт 8080 Docker-контейнера, только для входящих запросов.
Однако по умолчанию Docker также позволяет исходящие запросы. Интересно, как это сделать? Проверьте зависимости в dockerfile
, где NPM из контейнера напрямую обращается к интернету.
- В команде запуска контейнера первый порт — это порт хост-машины или локальной машины, а второй порт — это порт контейнера:
docker run -p 8080:8080 mahedi/simpleweb
Выводы
Веб-приложение запущено и доступно при обращении к порту 8080 локальной машины.
Несмотря на успех, стоит упомянуть три распространенные ошибки, допускаемые в процессе работы с Docker Server и Docker Client.
- Неправильный выбор базового образа.
- Отсутствие в
dockerfile
командADD
илиCOPY
для переноса файлов хост-машины в контейнер. - Неправильное сопоставление портов при создании контейнера.
Далее прилагаются скриншоты правильно запущенного в Docker веб-приложения Node.js, чтобы вы могли с ними свериться.
Самостоятельно ознакомьтесь с файлом dockerfile
для построения пользовательского образа и запуска веб-приложения на Node.js.
Проанализируйте изображенный на скриншоте файл index.js
с простым примером веб-приложения на Node.js. Данный файл запускается внутри контейнера Docker при помощи соответствующей команды из dockerfile
.
На сегодня все! В следующей части руководства пойдет речь о последовательном создании нескольких контейнеров и докеризации сложных веб-систем со множеством зависимостей.
Читайте также:
- Среда разработки Entity Framework в Docker
- Перенос сценариев CI в docker build
- Тенденции в области программного обеспечения в 2022 году: 22 прогноза
Читайте нас в Telegram, VK и Дзен
Перевод статьи Mahedi Hasan Jisan: Everything on Docker! (Part l)