Команда docker run

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

Мы уже умеем запускать контейнеризированный Redis командой docker run redis. В этом случае запустится Redis версии 8.0-M01. Но что если нужна другая версия? Скажем,  запустить Redis версии 5.0.

Для этого надо указать версию через разделитель — (:) двоеточие после имени образа. Это называется tag. В этом случае Docker скачает образ Redis версии 5.0 и запустит его. Если не указать тег, то Docker будет искать образ с тегом «latest». Тег latest обычно связывают с последней версией этого ПО и за его установку ответственны создатели продукта. Но как найти информацию какие версии доступны у приложения и какая из них последняя?

Поискать на https://hub.docker.com/. Найдем имя образа redis и список применимых к нему тегов, а также описания каждой версии для соответствующего тега. Каждая версия может иметь несколько коротких и длинных тегов, ссылающихся на нее.

Самое время разобраться с публикацией портов или как их еще называют пробросом портов в контейнер. Вернемся к примеру с нашим веб-сервером на 5000 порту, с которым мы познакомились в предыдущей главе. Запустим его на докер-хосте. Хост, на который установлен Docker в части запуска контейнеров, называется Docker host или Docker engine.

Когда мы запускаем контейнеризированное веб-приложение, оно начинает работать, и мы видим, что сервер запустился. Но как нам дать доступ пользователям к этому приложению? Приложение слушает на порту 5000, можно получить доступ через этот порт. Но какой IP использовать в своем браузере?

Тут есть два варианта.

Первый использовать IP докер-контейнера, т.к. у каждого контейнер есть свой собственный адрес, каждый докер-контейнер получает IP присвоенный по умолчанию. В данном случае 172.17.0.2. Но этот адрес внутренний и будет доступным только внутри докер-хоста, где контейнер выполняется. В общем, если запустить на своем докер-хосте браузер, ввести в нем http://172.17.0.2:5000, то получишь доступ. Но пользоваться этим сервисом смогут только внутренние пользователи этого хоста. Т.к. это внутренний IP внешние пользователи не смогут использовать этот URL.

Для внешних запросов необходимо использовать IP, по которому внешние пользователи ходят на наш хост, 10.0.0.13 в нашем случае. Но для того, чтобы это заработало, необходимо сопоставить порт внутри контейнера со свободным портом на докер-хосте. Допустим, я хочу, чтобы пользователи получили доступ к приложению на порту 80 докер-хоста. Тогда нужно сопоставить порт 80 localhost с портом 5000 в контейнере Docker.

Для этого используется параметр -p в команде docker run. И пользователи смогут получить доступ к приложению по URL http://10.0.0.13:80. Весь трафик, полученный на этот порт 80 будет маршрутизирован на порт 5000 внутри контейнера. Таким образом можно запускать много экземпляров разных приложений и сопоставлять их различным портам на докер-хосте.

Например, я развернул экземпляр mysql, который запустил БД и начал слушать на дефолтном порту mysql 3306. Также я запустил еще один инстанс базы, смаппив его порт 3306 на порт 8306 хоста. Итак, можно запустить столько приложений, сколько нужно и пробросить столько портов, сколько требуется. Разумеется есть ограничение в том, что ты не можешь назначить один порт докер-хоста несколько раз.

Теперь познакомимся с тем, как нам хранить постоянные данные при использовании контейнеров.

Допустим у нас запущен контейнер с mysql. Когда базы и таблицы будут созданы, физически они будут сохранены по по пути /var/lib/mysql в докер-контейнере. Запомни, что контейнер имеет свою собственную изолированную файловую систему и любые изменения происходят только в ней, они не имеют отношения к файловой системе хоста. Теперь мы зальем большой дамп данных в эту базу. Что произойдет если мы удалим этот mysql-контейнер?

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

С помощью специальной директории, размещенной на докер-хосте, данные в которой не будут относится непосредственно к контейнеру, а будут подключены как бы извне. Как будто внешний жесткий диск. Нам потребуется связать две директории: одну на хосте, а вторую в контейнере. В этом случае я создал директорию /opt/datadir и пробросил ее в контейнер по размещению /var/lib/mysql.

Для создания связи используется параметр -v, а далее пишется путь до директории на хосте, потом двоеточие-разделитель и папка внутри контейнера. Сначала откуда — с хоста, потом куда — в контейнер. Легко запомнить.

Таким образом, при запуске докер-контейнер неявно монтирует внешнюю директорию в свою внутреннюю. Теперь все данные спокойно лежат во внешнем томе в директории /opt/datadir докер-хоста и не зависят от жизни контейнера. Они останутся там, даже если контейнер будет удален.

Команда docker ps хорошо подходит для быстрого сбора основные деталей о контейнерах в нашей системе. Таких как имена, ID и т.д. Но периодически нам будет требоваться развернутая информация о каком-то контейнере. В подобных случаях нас выручит команда docker inspect, она запускается с именем или ID контейнера.

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

И наконец траблешутинг. Когда что-то идет не так, мы смотрим логи. Как их смотреть в контейнерах?

С помощью команды docker logs. Чтобы посмотреть эту команду давай запустим наше веб-приложение в фоновом режиме используя параметр -d. docker run -d rotorocloud/webapp запустит его в detached mode.

Теперь запустим команду docker logs, а дальше имя контейнера или его ID. Мы видим журнал, сформированный из stdout того контейнера.

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

docker run имя:версия — запустить контейнер нужной версии

docker run -it имя команда — запустить контейнер и вывести вывод в терминал

-i — связать стандартный ввод хоста со стандартным вводом контейнера

-t — связать стандартный вывод хоста со стандартным выводом контейнера

echo ‘qwe’ | docker run -i имя — передать на ввод контейнеру строку qwe

docker run -p 80:5000 имя — сопоставить порт 80 хоста порту 5000 в контейнере

docker run -v /opt/datadir/:/var/lib/mysql имя — смонтировать каталог /opt/datadir/ хоста в каталог /var/lib/mysql в контейнере

docker inspect имя — детальная информация о контейнере

docker logs имя — вывести стандартный вывод контейнера