Доступ к контейнеру докеров со случайными портами с IP-адреса хоста

Сценарий такой:

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

Теперь я хочу получить доступ к этому приложению на ноутбуке Mac. Этот ноутбук Mac может пинговать ip-адрес машины Linux.

Один из способов, которым я сейчас занимаюсь, - это сопоставление всех портов из контейнера докеров с машиной Linux, после чего я могу получить доступ с Mac, используя IP-адрес машины Linux.

Но этот метод не масштабируется при присоединении большего количества сервисов. Мне интересно, видел ли кто-нибудь такую ​​же проблему и есть ли способ лучше ее решить? Мы не запускаем Kubernetes на этих машинах Linux, потому что они не являются серверами. Эти машины предназначены для личного развития.

Спасибо!


person Rong Shen    schedule 13.12.2017    source источник


Ответы (1)


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

Обычное решение - настроить приложение для использования заданного порта или диапазона портов. Если это невозможно, есть несколько вариантов решения проблемы.

Хост-сеть

Используйте docker run --network=host. Контейнеры совместно используют сетевой стек хостов, поэтому они доступны по IP-адресу хостов. Обратите внимание, что это дает контейнеру доступ к сети хостов, поэтому он может мешать работе хост-служб или подвергать контейнер большей части вашего хоста, чем обычно.

Маршрутизируемая, определяемая пользователем сеть.

Создайте определяемую пользователем сеть для ваших контейнеров и назначьте ей диапазон IP-адресов, который сеть может маршрутизировать на хост Docker. Тогда службы, прослушивающие порты в контейнерах, становятся адресуемыми напрямую.

docker network create \
    --subnet=10.1.3.0/24 \
    -o com.docker.network.bridge.enable_ip_masquerade=false \
    routable

Маршрут для новой сети докеров необходимо будет добавить к вашим сетевым шлюзам, чтобы они могли направлять трафик через ваш хост Docker. В Linux это будет примерно так:

ip route add 10.1.3.0/24 via $DOCKER_HOST_IP

Тогда вы сможете передавать данные как обычно

docker run --net=routable --rm -it alpine ping $DOCKER_HOST_GATEWAY_IP

Мост Маквлан

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

docker network create -d macvlan \
    --subnet=10.1.2.0/24 \
    -o macvlan_mode=bridge \
    -o parent=enp3s0 macvlan
docker run --net=macvlan --ip=10.1.2.128 --rm -it alpine ping 10.1.2.1

Обратите внимание, что вы не можете связываться с IP-адресом хостов докеров через этот мост. Вы можете добавить к хосту субинтерфейс macvlan и переместить на него IP-адрес хоста, чтобы разрешить трафик.

Некоторым виртуальным машинам и виртуальным сетям при генерации данных не хватает дополнительных MAC-адресов, о которых они не знают. AWS EC2, например, отклонит трафик контейнеров.

Контейнер iptables

Можно создавать правила NAT iptables в пространстве имен контейнеров. Чтобы сделать это внутри контейнера, контейнеру нужна возможность NET_ADMIN. Сценарий в какой-то форме может искать порты приложений после запуска и пересылать трафик с правилом DNAT из ваших статических портов с внешним отображением на динамические порты приложений.

docker run -p 5000:5000 --cap-add=NET_ADMIN debian:9
# port=$(ss -lntpH | awk '/"app-bin"/ { split($4,a,":"); print a[length(a)]; exit}')
# iptables -t nat -A -p tcp -m tcp --dport 5000 -j DNAT --to-destination 127.0.0.1:$port

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

pid=$(docker inspect -f '{{.State.Pid}}' ${container_id})
mkdir -p /var/run/netns/
ln -sfT /proc/$pid/ns/net /var/run/netns/$container_id
ip netns exec "${container_id}" iptables -t nat -vnL
person Matt    schedule 13.12.2017
comment
Большое спасибо за подробное объяснение каждого варианта. Мы выберем маршрутизируемый, определяемый пользователем параметр сети. Спасибо! - person Rong Shen; 14.12.2017