Для взаимодействия с Docker-контейнером с хоста нужно настроить маппинг портов. Разберемся, почему это важно, и рассмотрим несколько способов добавления нового маппинга после запуска Docker-контейнера.
- Зачем нужен маппинг
- Как назначить маппинг работающему Docker-контейнеру
- Повторный запуск из docker commit
- Перенастройка Docker-контейнера без его удаления
Это адаптированный перевод статьи Assigning a Port Mapping to a Running Docker Container из блога образовательного проекта Baeldung.
Эта статья предназначена для разработчиков, которые знают Docker хотя бы на базовом уровне. Если вы еще не знакомы с этой технологией и вам интересно с ней разобраться, пройдите курс по Docker на Хекслете.
Зачем нужен маппинг
По умолчанию Docker запускает сервис изолированно — то есть все порты между хостом и Docker-контейнером закрыты. Для того, чтобы получить доступ к сервису с хоста или из внешней сети, нужно использовать сопоставление портов или маппинг.
Маппинг нужен для того, чтобы все запросы, проходящие через порт хоста, перенаправлялись в Docker-контейнер. Другими словами, сопоставление портов делает процессы внутри контейнера доступными извне.
При запуске нового Docker-контейнера с помощью команды docker run
можно сопоставить порты опцией --publish
или -p
:
docker run -d -p 81:80 --name httpd-container httpd
Эта команда запускает Docker-контейнер httpd (HTTP-сервер Apache) и маппинг 81 порта хоста с 80 портом внутри Docker-контейнера. Стоит отметить, что по умолчанию сервер httpd прослушивает порт 80.
Теперь доступ к приложению можно получить, используя порт 81 на хосте:
curl http://localhost:81
<html><body><h1>It works!</h1></body></html>
Важно отметить, что выполнять маппинг для всех Docker-контейнеров необязательно. Например, в случаях, когда нужно сохранить службы Docker-контейнера закрытыми или видимыми только родственным контейнерам в той же сети Docker.
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки
Как назначить маппинг работающему Docker-контейнеру
Рассмотрим ситуацию, в которой маппинг не был задан при запуске Docker-контейнера или был задан с ошибкой. Получить доступ к сервису через TCP/IP-соединение на хосте не получится, но есть три способа решить эту проблему:
- Остановить работающий Docker-контейнер, а затем создать и запустить новый c оригинальным
docker images
- Сделать
docker commit
работающего Docker-контейнера, создать новый и запустите его черезdocker images
, сохранив состояние - Добавить новый маппинг, используя файлы конфигурации Docker
Разберем каждый способ подробнее.
Освойте DevOps на интенсиве Хекслета Научитесь автоматизировать окружение, деплоить приложения одной кнопкой одновременно на любое количество машин и разворачивать облачный кластер на Digital Ocean или Yandex Cloud.
Перезапуск Docker-контейнера
Это самое технически простое решение: работающий Docker-контейнер удаляется, а вместо него создается новый, запущенный из образа. При создании Docker-контейнера сопоставляются порты.
Хотя это самый простой способ, он подходит не во всех ситуациях. Например, решение не подойдет в ситуации, когда внутри Docker-контейнера уже выполнены некоторые операции: установились зависимости, запустились процессы или обновились файлы. Если восстановить такой Docker-контейнер из образа, все эти изменения будут потеряны.
Стоит отметить, что важные данные лучше хранить в Docker volumes, чтобы упростить замену Docker-контейнеров.
Повторный запуск из docker commit
Этот подход предполагает создание нового образа на базе существующего Docker-контейнера. Затем образ можно использовать для запуска нового Docker-контейнера с открытыми нужными портами.
Поскольку мы фиксируем состояние существующего Docker-контейнера оно становится доступно в новом образе.
Попробуем реализовать этот способ. Сначала остановим Docker-контейнер и создадим его образ с помощью команды docker commit
:
# Останавливаем контейнер
docker stop httpd-container
# Команда напечатает на экране название остановленного контейнера
httpd-container
# Создаем образ на основе существующего контейнера
docker commit httpd-container httpd-image
# Хэш образа
sha256:33da33fcad051c90ac9b7dea9b2dbda442767e05ddebd8d6db8ac6893ef4ef40
Затем удалим Docker-контейнер и заново запустим его из образа. На этом этапе важно убедиться, что маппинг настроен верно:
# Удаляем контейнер
docker rm httpd-container
# Команда напечатает на экране название удалённого контейнера
httpd-container
# Запускаем контейнер
docker run -d -p 83:80 --name httpd-container httpd-image
# На экране выведится хеш запущенного контейнера
dd2535c477ad74e80b3642abca9055efacb89eaf14572b91f91bf20cd3f0cbf3
Перенастройка Docker-контейнера без его удаления
В подходах, которые обсуждались выше, речь шла об удалении существующего Docker-контейнера и создании нового. Хотя новый Docker-контейнер работает также, его метаданные полностью отличаются.
Рассмотрим способ, как настроить маппинг в уже существующем Docker-контейнере. Сначала запустим новый без сопоставления портов:
docker run -d --name httpd-container httpd
a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7
# Команда выведет запущенные контейнеры
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0ed1c9fc60c httpd "httpd-foreground" 1 second ago Up 1 second 80/tcp httpd-container
Команда docker run
возвращает полный идентификатор Docker длиной 64 символа. Другой способ получить его — команда docker inspect:
$ docker inspect --format="{{.Id}}" httpd-container
a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7
Идентификатор пригодится для поиска файла конфигурации Docker.
Остановка Docker-контейнера и службы Docker
Первый шаг по перенастройке работающего Docker-контейнера — его остановка. Выполнить ее можно командой docker stop
:
docker stop httpd-container
httpd-container
Для обновления конфигурационных файлов Docker-контейнера нужно остановить и службу Docker. Стоит отметить, что это действие приведет к отключению всех Docker-контейнеров до тех пор, пока процесс настройки не закончится.
# Останавливаем службу Docker
systemctl stop docker
Читайте также: Как сохранять фокус на протяжении всего обучения: советы от Хекслета
Как найти конфигурационные файлы
Все конфигурационные файлы, которые относятся к Docker-контейнерам, образам, томам и сетям Docker, можно найти в каталоге /var/lib/docker
. Стоит отметить, что на Windows и MacOS путь к каталогу отличается.
В данном случае интерес представляют два файла: hostconfig.json
и config.v2.json
. Найти их можно в следующем каталоге:
/var/lib/docker/containers/<ID>/
В данном случае ID — полный идентификатор Docker-контейнера, который мы получили ранее:
a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7
Конфигурационные файлы можно найти в следующем каталоге:
$ ls /var/lib/docker/containers/a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7/
a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7-json.log checkpoints config.v2.json hostconfig.json hostname hosts mounts resolv.conf resolv.conf.hash
Обновление конфигурационных файлов
В первую очередь стоит обновить файл hostconfig.json
. Для этого найдем ключ привязки портов в этом файле. Поскольку при запуске Docker-контейнера маппинг не был настроен, поле ключа PortBindings
Docker-контейнера будет пустым:
{
...
...
"PortBindings": {},
...
...
}
Следующий шаг — назначение 82 порта хоста 80 порту Docker-контейнера httpd-container
. Для этого обновим привязки портов в файле JSON:
{
...
...
"PortBindings": {"80/tcp":[{"HostIp":"","HostPort":"82"}]},
...
...
}
Как только маппинг выполнен, нужно открыть порт 80 Docker-контейнера в файле config.v2.json
. Для этого добавим поле открытых портов (если его еще нет) в ключ конфигурации:
{
...
"Config":
{
...
"ExposedPorts":
{
"80/tcp":{}
},
...
}
}
Таким образом мы сообщаем демону Docker, что Docker-контейнер прослушивает 80 порт в этом сетевом интерфейсе.
Можно открыть несколько портов, передав значения в виде пар ключ-значение, разделенных запятыми:
{
...
"Config":
{
...
"ExposedPorts":
{
"80/tcp":{},
"82/tcp":{},
"8080/tcp":{}
},
...
}
}
Проверка изменений
Проверка изменений состоит из нескольких шагов. Сначала запустим службу Docker:
systemctl start docker
Теперь запустим httpd-контейнер и проверим маппинг портов с помощью команды docker ps
:
docker start httpd-container
httpd-container
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0ed1c9fc60c httpd "httpd-foreground" 1 hours ago Up 1 seconds 0.0.0.0:82->80/tcp, :::82->80/tcp httpd-container
Из результата выполнения команды видно, что порты Docker-контейнера теперь сопоставлены с портами хоста. После этого доступ к службе httpd Docker-контейнера можно получить извне — через 82 порт:
curl http://localhost:82
<html><body><h1>It works!</h1></body></html>
При таком подходе идентификатор Docker-контейнера и все выполненные в нем настройки сохраняются, поскольку исходный контейнер не заменяется новым.
Изменить существующие маппинги любого Docker-контейнера можно используя процедуру, описанную выше. Единственное отличие будет заключаться в том, что ключ привязки портов в файле hostconfig.json
не будет пустым. В этом случае достаточно просто обновить номер используемого порта.
При обновлении TCP-порта Docker-контейнера в маппинге необходимо указать тот же порт в файле config.v2.json
.
Теперь все проверки прошли — можно запустить службу Docker и Docker-контейнер, чтобы изменения вступили в силу.
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки