hub - Предоставление порта в реальном контейнере Docker





registry search (12)


Если ни один ответ не работает для кого-то - проверьте, что ваш целевой контейнер уже запущен в сети докеров:

docker inspect my-target-container | grep NetworkMode
        "NetworkMode": "my-network-name",

Если да, вы должны запустить контейнер прокси в той же сети.

docker inspect my-target-container | grep -A2 Aliases
                "Aliases": [
                    "my-alias",
                    "23ea4ea42e34a"

Конечная команда:

docker run --net my-network-name --name my-new-proxy \
-d -p 8080:1234 alpine/socat TCP-LISTEN:1234,fork TCP-CONNECT:my-alias:80

Я пытаюсь создать контейнер Docker, который действует как полнофункциональная виртуальная машина. Я знаю, что я могу использовать инструкцию EXPOSE внутри файла Docker, чтобы открыть порт, и я могу использовать флаг -p с docker run для назначения портов, но как только контейнер фактически запущен, есть команда открывать / отображать дополнительные порты в реальном времени ?

Например, допустим, у меня есть контейнер Docker, который запускает sshd. Кто-то еще использует контейнер ssh и устанавливает httpd. Есть ли способ открыть порт 80 на контейнере и отобразить его на порт 8080 на хосте, чтобы пользователи могли посещать веб-сервер, работающий в контейнере, без перезапуска?




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

HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https

Примечание. Я открывал порт https (443), внутренний IP-адрес докера - 172.17.0.2

Примечание 2: Эти правила и временные значения сохраняются только до тех пор, пока контейнер не будет перезапущен




Я должен был решить эту проблему и смог ее решить, не останавливая ни один из моих запущенных контейнеров. Это решение обновлено по состоянию на февраль 2016 года, используя Docker 1.9.1. В любом случае, этот ответ представляет собой подробную версию ответа @ ricardo-branco, но более подробно для новых пользователей.

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

Поскольку я хотел бы получить доступ к базе данных MySQL извне (из Sequel Pro через SSH-туннелирование), я собираюсь использовать порт 33306 на главной машине. (Не 3306 , на случай, если работает внешний экземпляр MySQL).

Примерно за час чистки iptables оказалось бесплодным, хотя:

Шаг за шагом, вот что я сделал:

mkdir db-expose-33306
cd db-expose-33306
vim Dockerfile

Измените dockerfile , разместив его внутри:

# Exposes port 3306 on linked "db" container, to be accessible at host:33306
FROM ubuntu:latest # (Recommended to use the same base as the DB container)

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody
EXPOSE 33306

CMD socat -dddd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306

Затем создайте изображение:

docker build -t your-namespace/db-expose-33306 .

Затем запустите его, привязав к вашему запущенному контейнеру. (Используйте -d вместо -rm чтобы сохранить его в фоновом режиме, пока явным образом не остановится и не удаляется. В этом случае я хочу, чтобы он выполнялся временно).

docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306  your-namespace/db-expose-33306



Пакеты IPtables не работают, по крайней мере, на Docker 1.4.1.

Лучшим способом было бы запустить другой контейнер с открытым портом и реле с помощью socat. Это то, что я сделал (временно) для подключения к базе данных с помощью SQLPlus:

docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus

Dockerfile:

FROM debian:7

RUN apt-get update && \
    apt-get -y install socat && \
    apt-get clean

USER nobody

CMD socat -dddd TCP-LISTEN:1521,reuseaddr,fork TCP:db:1521



Вы можете использовать оверлейную сеть, такую ​​как Weave Net , которая назначит уникальный IP-адрес для каждого контейнера и неявно выставляет все порты каждой контейнерной части сети.

Weave также обеспечивает интеграцию с хост-сетью . По умолчанию он отключен, но если вы хотите также получить доступ к IP-адресам контейнера (и всем его портам) с хоста, вы можете запустить просто запустить weave expose .

Полное раскрытие: я работаю в Weaveworks.




Существует удобная оболочка HAProxy.

docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_HOST=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy

Это создает HAProxy для целевого контейнера. очень просто.




Вы не можете сделать это через Docker, но вы можете получить доступ к незащищенному порту контейнера с главной машины.

если у вас есть контейнер, который с чем-то работает на своем порту 8000, вы можете запустить

wget http://container_ip:8000

Чтобы получить IP-адрес контейнера, выполните две команды:

docker ps

docker inspect container_name | grep IPAddress

Внутренне Docker запускает вызов iptables при запуске изображения, поэтому, возможно, некоторые изменения будут работать.

чтобы открыть порт контейнера 8000 на вашем порту localhosts 8001:

 iptables -t nat -A  DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000

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

ПРИМЕЧАНИЕ: это подрывный докер, поэтому следует сделать это с осознанием того, что он может создать синий дым

ИЛИ ЖЕ

Другой альтернативой является просмотр опции (new? Post 0.6.6?) -P, которая будет использовать произвольные хост-порты, а затем подключить их.

ИЛИ ЖЕ

с 0.6.5, вы можете использовать функцию LINKs, чтобы открыть новый контейнер, который говорит с существующим, с некоторой дополнительной ретрансляцией на флаги -p этого контейнера? (Я еще не использовал LINK)

ИЛИ ЖЕ

с докером 0.11? вы можете использовать docker run --net host .. для прикрепления вашего контейнера непосредственно к сетевым интерфейсам хоста (т. е. сеть не разнесена по имени), и поэтому открыты все порты, открываемые в контейнере.




Вот еще одна идея. Используйте SSH для пересылки портов; это также полезно для OS X (и, возможно, Windows), когда ваш хост Docker является виртуальной машиной.

docker exec -it <containterid> ssh -R5432:localhost:5432 <user>@<hostip>



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

Интерфейсы Macvlan

Теперь Docker включает сетевой драйвер Macvlan . Это придает сети Docker интерфейс «реального мира» и позволяет назначать адреса сетей непосредственно в контейнере (например, в режиме мостов с виртуальными машинами).

docker network create \
    -d macvlan \
    --subnet=172.16.86.0/24 \
    --gateway=172.16.86.1  \
    -o parent=eth0 pub_net

pipework также может отображать реальный интерфейс в контейнер или настраивать дополнительный интерфейс в более старых версиях Docker.

Маршрутизация IP-адресов

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

Затем вы назначаете эту сеть контейнерам и настраиваете хост Docker для маршрутизации пакетов через сеть докеров.

Общий интерфейс хоста

Параметр --net host позволяет --net host -интерфейсом в контейнере, но это, вероятно, не очень хорошая настройка для запуска нескольких контейнеров на одном хосте из-за общей природы.




Сначала прочитайте ответ Ricardo . Это сработало для меня.

Тем не менее, существует сценарий, когда это не будет работать, если запущенный контейнер будет запущен с помощью компоновки докеров. Это связано с тем, что docker-compose (я запускаю docker 1.17) создает новую сеть. Способ решения этого сценария будет

docker network ls

Затем добавьте следующий docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name




Вы можете использовать SSH для создания туннеля и выставить свой контейнер на своем хосте.

Вы можете сделать это в обоих направлениях: от контейнера до хоста и от хоста к контейнеру. Но вам нужен SSH-инструмент, такой как OpenSSH, как (клиент на одном, так и сервер в другом).

Например, в контейнере вы можете сделать

$ yum install -y openssh openssh-server.x86_64
service sshd restart
Stopping sshd:                                             [FAILED]
Generating SSH2 RSA host key:                              [  OK  ]
Generating SSH1 RSA host key:                              [  OK  ]
Generating SSH2 DSA host key:                              [  OK  ]
Starting sshd:                                             [  OK  ]
$ passwd # You need to set a root password..

IP-адрес контейнера можно найти в этой строке (в контейнере):

$ ifconfig eth0 | grep "inet addr" | sed 's/^[^:]*:\([^ ]*\).*/\1/g'
172.17.0.2

Затем в хосте вы можете просто сделать:

sudo ssh -NfL 80:0.0.0.0:80 [email protected]



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

Удалить запущенные контейнеры

docker rm $(docker stop -t=1 $(docker ps -q))

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

Примечание. При попытке остановить контейнер вы получите сообщение об ошибке:

Ошибка: Невозможно удалить запущенный контейнер, сначала остановите его.

Удалить все контейнеры

docker rm $(docker ps -a -q)




docker