Я пытаюсь создать контейнер Docker, который действует как полноценная виртуальная машина. Я знаю, что могу использовать инструкцию EXPOSE внутри Dockerfile, чтобы выставить порт, и я могу использовать -p
флаг с, docker run
чтобы назначить порты, но как только контейнер действительно запущен, есть ли команда, чтобы открыть / отобразить дополнительные порты?
Например, допустим, у меня есть контейнер Docker, на котором запущен sshd. Кто-то еще использует контейнер ssh и устанавливает httpd. Есть ли способ выставить порт 80 на контейнере и сопоставить его с портом 8080 на хосте, чтобы люди могли посещать веб-сервер, работающий в контейнере, без перезапуска?
Ответы:
Вы не можете сделать это через Docker, но вы можете получить доступ к незакрытому порту контейнера с хост-машины.
если у вас есть контейнер, который работает с портом 8000, вы можете запустить
Чтобы получить IP-адрес контейнера, выполните 2 команды:
Внутренне Docker выдает вызов iptables при запуске образа, так что, возможно, сработают некоторые варианты.
выставить порт контейнера 8000 на ваш локальный порт 8001:
Один из способов решить эту проблему - настроить другой контейнер с желаемым отображением портов и сравнить выходные данные команды iptables-save (хотя мне пришлось удалить некоторые другие параметры, которые заставляют трафик проходить через докер прокси).
ПРИМЕЧАНИЕ: это подрывной докер, поэтому следует делать с осознанием того, что он может хорошо создавать синий дым
ИЛИ
Другой альтернативой является поиск опции (new? Post 0.6.6?) -P, которая будет использовать произвольные порты хоста, а затем подключать их.
ИЛИ
с 0.6.5, вы могли бы использовать функцию LINKs, чтобы вызвать новый контейнер, который общается с существующим, с некоторыми дополнительными ответами на флаги -p этого контейнера? (Я еще не использовал ССЫЛКИ)
ИЛИ
с докером 0,11? Вы можете использовать его
docker run --net host ..
для непосредственного присоединения вашего контейнера к сетевым интерфейсам хоста (т. е. net не является пространством имен) и, таким образом, все порты, которые вы открываете в контейнере, открыты.источник
CONTAINER_IP=$(docker inspect container_name | jq .[0].NetworkSettings.IPAddress | sed -r 's/\"([^\"]+)\"/\1/''])'); iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination ${CONTAINER_IP}:8000
jq
иsed
вы можете использовать-f
опциюdocker inspect
:CONTAINER_IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' container_name)
jshon -e 0 -e NetworkSettings -e Networks -e bridge -e IPAddress -u
Вот что я бы сделал:
источник
sudo docker
а не толькоdocker
?docker commit
я был готов снова протестировать приложение, а не тратить часы на переустановку всего.Хотя вы не можете открыть новый порт существующего контейнера, вы можете запустить новый контейнер в той же сети Docker и заставить его перенаправлять трафик в исходный контейнер.
Работал Пример
Запустите веб-сервис, который прослушивает порт 80, но не открывает его внутренний порт 80 (упс!):
Найдите свой IP-адрес сети Docker:
Запустите
verb/socat
с открытым портом 8080 и заставьте его перенаправлять трафик TCP на порт 80 этого IP:Теперь вы можете получить доступ к pastebin по адресу http: // localhost: 8080 / , и ваши запросы направляются туда,
socat:1234
куда он направляетсяpastebin:80
, и ответ проходит по тому же пути в обратном направлении.источник
verb/socat:alpine
, так как его изображение занимает 5% занимаемой площади (если только вы не столкнулись с несовместимостью с libc или DNS ).alpine/socat
--net myfoldername_default
к моейverb/socat
команде запуска, так как я запустил неэкспонированный контейнер в составе докера, который создает сеть.Взломы IPtables не работают, по крайней мере, на Docker 1.4.1.
Лучший способ - запустить другой контейнер с открытым портом и ретранслировать с помощью socat. Вот что я сделал, чтобы (временно) подключиться к базе данных с помощью SQLPlus:
Dockerfile:
источник
FROM
Для эффективного использования ресурсов стоит порекомендовать использовать тот же базовый образ, что и ваш контейнер БД.Вот еще одна идея. Используйте SSH для переадресации портов; это также дает преимущество работы в OS X (и, вероятно, в Windows), когда ваш хост Docker является виртуальной машиной.
источник
Мне пришлось иметь дело с этой же проблемой, и я смог ее решить, не останавливая ни один из моих работающих контейнеров. Это актуальное решение по состоянию на февраль 2016 года с использованием Docker 1.9.1. В любом случае, этот ответ является подробной версией ответа @ ricardo-branco, но более подробно для новых пользователей.
В моем сценарии я хотел временно подключиться к MySQL, работающему в контейнере, и, поскольку к нему привязаны другие контейнеры приложений, остановка, перенастройка и повторный запуск контейнера базы данных не были начальными.
Поскольку я хотел бы получить доступ к базе данных MySQL извне (из Sequel Pro через SSH-туннелирование), я собираюсь использовать порт
33306
на хост-машине. (Нет3306
, на случай, если запущен внешний экземпляр MySQL.)Около часа настройки iptables оказались бесплодными, хотя:
Шаг за шагом вот что я сделал:
Отредактируйте
dockerfile
, разместив это внутри:Затем создайте изображение:
Затем запустите его, ссылаясь на ваш работающий контейнер. (Используйте
-d
вместо того,-rm
чтобы держать его в фоновом режиме, пока явно не остановите и не удалите. В этом случае я хочу, чтобы он работал только временно.)источник
Чтобы добавить к принятому
iptables
решению ответа , мне нужно было запустить еще две команды на хосте, чтобы открыть его для внешнего мира.Примечание. Я открывал порт https (443), внутренний IP-адрес докера был
172.17.0.2
Примечание 2: Эти правила временны и будут действовать только до перезапуска контейнера.
источник
Вы можете использовать SSH, чтобы создать туннель и выставить свой контейнер на хосте.
Вы можете сделать это обоими способами, от контейнера к хосту и от хоста к контейнеру. Но вам нужен SSH инструмент, такой как OpenSSH в обоих (клиент в одном и сервер в другом).
Например, в контейнере вы можете сделать
Вы можете найти IP-адрес контейнера из этой строки (в контейнере):
Затем на хосте вы можете просто сделать:
источник
Если у кого-то нет ответа - проверьте, работает ли целевой контейнер в Docker-сети:
Сохраните его на потом в переменной
$NET_NAME
:Если да, вы должны запустить прокси-контейнер в той же сети.
Затем найдите псевдоним для контейнера:
Сохраните его на потом в переменной
$ALIAS
:Теперь запустите
socat
контейнер в сети,$NET_NAME
чтобы подключиться к$ALIAS
открытому (но не опубликованному) порту контейнера ed:источник
Вы можете использовать оверлейную сеть, такую как Weave Net , которая будет назначать уникальный IP-адрес каждому контейнеру и неявно выставлять все порты каждому контейнеру в сети.
Weave также обеспечивает интеграцию с хост-сетью . По умолчанию он отключен, но если вы хотите также получить доступ к IP-адресам контейнера (и всем его портам) с хоста, вы можете просто запустить
weave expose
.Полное раскрытие: я работаю в Weaveworks.
источник
Есть удобная оболочка HAProxy.
Это создает HAProxy для целевого контейнера. очень просто.
источник
Вот несколько решений:
https://forums.docker.com/t/how-to-expose-port-on-running-container/3252/12
источник
Сначала прочитайте ответ Рикардо . Это сработало для меня.
Однако существует сценарий, в котором это не будет работать, если запущенный контейнер был запущен с помощью docker-compose. Это потому, что docker-compose (я использую docker 1.17) создает новую сеть. Способ решения этого сценария будет
docker network ls
Затем добавьте следующее
docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name
источник
Невозможно выполнить прямое сопоставление портов, но есть несколько способов дать контейнеру Docker то, что равносильно реальному интерфейсу, который будет иметь виртуальная машина.
Интерфейсы Macvlan
Docker теперь включает сетевой драйвер Macvlan . Это присоединяет сеть Docker к интерфейсу «реального мира» и позволяет назначать адреса этих сетей непосредственно контейнеру (как в режиме моста виртуальных машин).
pipework
Можно также отобразить реальный интерфейс в контейнер или настроить подчиненный интерфейс в более старых версиях Docker.Маршрутизация IP
Если у вас есть контроль над сетью, вы можете направить дополнительные сети на хост Docker для использования в контейнерах.
Затем вы назначаете эту сеть контейнерам и настраиваете свой хост Docker для маршрутизации пакетов через сеть Docker.
Общий хост-интерфейс
--net host
Опция позволяет хост - интерфейс для совместного использования в контейнер , но это, вероятно , не очень хорошая установка для запуска нескольких контейнеров на одном хосте из - за общего характера.источник