Docker для Windows: не может получить доступ к службе на открытом порту в режиме контейнера Windows

Я использую следующие Dockerfiles для создания контейнера под управлением Jenkins в контейнере Windows на рабочем столе Windows 10 под управлением Docker для Windows версии 17.03

FROM microsoft/windowsservercore

RUN powershell -Command wget 'http://javadl.oracle.com/webapps/download/AutoDL?BundleId=210185' -Outfile 'C:\jreinstaller.exe' ; Start-Process -filepath C:\jreinstaller.exe -passthru -wait -argumentlist "/s,INSTALLDIR=c:\Java\jre1.8.0_91" ; del C:\jreinstaller.exe

ENV JAVA_HOME c:\\Java\\jre1.8.0_91  
RUN setx PATH %PATH%;%JAVA_HOME%\bin

CMD [ "java.exe" ]

Я создаю изображение из этого файла Docker:

docker build -t windows-java:jre1.8.0_91 .

Второй Dockerfile, который я использую для установки Jenkins поверх этого:

FROM windows-java:jre1.8.0_91

ENV HOME /jenkins  
ENV JENKINS_VERSION 2.58  
RUN mkdir \jenkins  
RUN powershell -Command "wget -Uri https://updates.jenkins-ci.org/latest/jenkins.war -UseBasicParsing -OutFile /jenkins/jenkins.war"

EXPOSE 8080  
EXPOSE 50000  

CMD java -jar C:\\jenkins\\jenkins.war


docker build -t jenkins-windows:2.0 .

Затем я запускаю контейнер следующим образом:

docker run --name jenkinsci -p 8080:8080 -p 50000:50000  jenkins-windows:2.0

Я вижу, что контейнер работает нормально, и журналы показывают все хорошо

PS C:\Users\mandeep\ringba\ringba-jenkins-setup-windows\jenkins-master> docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                              NAMES
85ba2ef525a1        jenkins-windows:2.0   "cmd /S /C 'java -..."   8 hours ago         Up 8 hours          0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp   jenkinsci

Однако я не могу получить доступ к серверу jenkins, работающему на http://localhost:8080 в веб-браузере хост-машины.

Не уверен, что это поможет, но когда я запускал докер в Linux container режим на той же машине, я смог получить доступ к серверу jenkins на http://localhost:8080 используя их официальный образ докера.

6 ответов

Решение

В настоящее время это известная проблема в Windows. Невозможно получить доступ к конечной точке контейнера с собственного хоста, используя localhost/127.0.0.1. Сегодня возможно использование контейнеров Linux, потому что Docker включил специальный обходной путь, который уникален для их реализации Moby/Linux для запуска контейнеров Linux в Windows.

Мы работаем над решением этой проблемы, но сегодня мы рекомендуем обойти это:

  • Доступ к конечным точкам контейнера с отдельного хоста с использованием IP-адреса хоста, на котором выполняется контейнер, и открытого порта для контейнера на его хосте
  • ИЛИ путем доступа к контейнеру на том же хосте, используя внутренний IP-адрес контейнера и опубликованный порт (вы можете использовать docker network inspect <network name> или же docker exec <container ID> ipconfig> получить IP-адрес самой конечной точки контейнера)

Чтобы завершить сообщение @Kallie-Microsoft:

На docs.docker.com добавлен раздел Ограничения контейнеров Windows для локального хоста и опубликованных портов.


Docker для Windows предоставляет возможность переключения контейнеров Windows и Linux. Если вы используете контейнеры Windows, имейте в виду, что существуют некоторые ограничения в отношении сетевого взаимодействия из-за текущей реализации Windows NAT (WinNAT). Эти ограничения могут быть устранены по мере развития проекта контейнеров Windows.

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

Итак, в сценарии, где вы используете Docker, чтобы получить изображение и запустить веб-сервер с помощью команды, подобной этой:

docker run -d -p 80:80 --name webserver nginx

Использование curl http://localhost/ или указание веб-браузера на http://localhost/ не будет отображать веб-страницу nginx (как это было бы с контейнерами Linux).

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

Вы можете получить IP-адрес контейнера, используя проверку докера с некоторыми параметрами --format и идентификатором или именем контейнера. В приведенном выше примере команда будет выглядеть следующим образом, используя имя, которое мы дали контейнеру (веб-серверу) вместо идентификатора контейнера:

$ docker inspect \
  --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
  webserver

Проблема здесь в том, что «localhost» не соответствует IP-адресу вашего контейнера, поскольку он работает не напрямую в Windows, а на виртуальной машине Linux через WSL. Это известная проблема с Docker Desktop.

Что вам нужно сделать, так это привязать свой локальный порт (в Windows) к порту в WSL.

В терминале Windows/Powershell:

Получить IP-адрес виртуальной машины Linux (Docker Desktop создает дистрибутив под названием «docker-desktop» в WSL2)

      $wsl_ip = (wsl -d "docker-desktop" -- "ifconfig" "eth0" "|" "grep" "inet addr:").trim("").split(":").split()[2]

Привяжите свой локальный порт к тому же порту в Linux (см. Netsh)

      netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=$wsl_ip

Я столкнулся с той же проблемой, порядок выполнения команды docker run имеет значение.

docker run -p <host port>:<container port> <image> Работает

docker run <image> -p <host port>:<container port> Не работает

Моя установка -

При использовании Windows 10 версии 2004 (сборка ОС 19041.329) WSL 2 включен - https://docs.microsoft.com/en-us/windows/wsl/wsl2-indexUbuntu 18.04, установленный из магазина Microsoft и включенный в докере.

образ

Использование Docker Desktop для Windows 4.20.1 и WSL 2 меня устраивает.

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

Внутри вашего Dockerfile напишите следующее:

EXPOSE 8080(или любые порты, которые вы хотите открыть)

Затем создайте свой образ и запустите его через Docker Desktop. Затем вы можете привязать порты хоста к портам контейнера в диалоговом окне, где вы также можете определить тома, переменные env и т. д. (дополнительные настройки).

См. следующую картинку:

Похоже, этот выпуск не кажется таким уж скучным, как был. Следуя документации на https://docs.docker.com/engine/reference/run/, вы можете указать IP-адрес на хост-машине, где вы хотите, чтобы порт (-ы) контейнера был открыт.

-p=[] : Publish a container's port or a range of ports to the host
               format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort
               Both hostPort and containerPort can be specified as a
               range of ports. When specifying ranges for both, the
               number of container ports in the range must match the
               number of host ports in the range, for example:
                   -p 1234-1236:1234-1236/tcp
               When specifying a range for hostPort only, the
               containerPort must not be a range.  In this case, the container port is published somewhere within the specified hostPort range. (e.g., `-p 1234-1236:1234/tcp`)
               (use 'docker port' to see the actual mapping)

Вероятно, это 127.0.0.1, и это решает проблему с доступом к открытому порту контейнера Docker в системе Windows. Просто используйте переключатель -p с IP-адресом при запуске контейнера.

docker run --rm -it -p 127.0.0.1:3000:3000 ubuntu:latest
Другие вопросы по тегам