도커 컨테이너에서 호스트 포트에 액세스하는 방법


278

jenkins를 실행하는 도커 컨테이너가 있습니다. 빌드 프로세스의 일부로 호스트 시스템에서 로컬로 실행되는 웹 서버에 액세스해야합니다. 호스트 웹 서버 (포트에서 실행되도록 구성 할 수있는)가 jenkins 컨테이너에 노출 될 수있는 방법이 있습니까?

편집 : Linux 시스템에서 기본적으로 docker를 실행하고 있습니다.

최신 정보:

아래 @larsks 응답 외에도 호스트 컴퓨터에서 호스트 IP의 IP 주소를 얻으려면 다음을 수행하십시오.

ip addr show docker0 | grep -Po 'inet \K[\d.]+'

이것은 끔찍한 대답이므로 주석을 사용하지만 이것이 boot2docker 설정이 아닌 한 일반적으로 172.17.1.78에서 주석에 액세스 할 수 있다고 생각합니다.
CashIsClay

@CashIsClay 나는 그것을 시도했지만, 여전히이 오류가 발생curl: (7) Failed to connect to 172.17.1.78 port 7000: No route to host
트라이 Nguyen

지정하지 않았습니다. boot2docker를 실행 중입니까, 아니면 Linux에서 Docker를 기본적으로 실행 중입니까?
larsks

@larsks 죄송합니다. 방금 질문을 업데이트했습니다. Linux에서 기본적으로 실행 중입니다.
Tri Nguyen

답변:


206

Linux에서 Docker를 기본적으로 실행하는 경우 docker0인터페이스 의 IP 주소를 사용하여 호스트 서비스에 액세스 할 수 있습니다 . 컨테이너 내부에서 기본 경로가됩니다.

예를 들어, 내 시스템에서 :

$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link 
       valid_lft forever preferred_lft forever

그리고 컨테이너 내부 :

# ip route show
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0  src 172.17.0.4 

간단한 쉘 스크립트를 사용하여이 IP 주소를 추출하는 것은 매우 쉽습니다.

#!/bin/sh

hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip

iptablesDocker 컨테이너의 연결을 허용하기 위해 호스트 의 규칙 을 수정해야 할 수도 있습니다 . 이와 같은 것이 트릭을 수행합니다.

# iptables -A INPUT -i docker0 -j ACCEPT

이렇게하면 Docker 컨테이너에서 호스트의 모든 포트에 액세스 할 수 있습니다. 참고 :

  • iptables 규칙이 순서화되어 있으며이 규칙은 다른 규칙이 무엇인지에 따라 올바른 작업을 수행하거나 수행하지 않을 수 있습니다.

  • (a) 청취 중 INADDR_ANY(일명 0.0.0.0)이거나 명시 적으로 docker0인터페이스에서 청취중인 호스트 서비스에만 액세스 할 수 있습니다.


1
감사. iptables를 수정하지 않고 IP 주소를 얻는 것이 전부였습니다. :)
Tri Nguyen


7
Docker for MAC은 어떻습니까? AFAIK "Docker for MAC"에 사용 가능한 docker0 네트워크가 없습니다. 이 경우 컨테이너에서 호스트에 어떻게 연결할 수 있습니까?
Vijay

17
당신은 MAC의 V 17.06 이상을 위해 부두 노동자를 사용하는 경우, 단지 사용하는 docker.for.mac.localhost대신 localhost127.0.0.1. 여기 doc 입니다.
메리 토

1
IP 주소를받는 대신 호스트의 호스트 이름을 사용했습니다 (호스트의 호스트 이름 명령)
Marek F

312

macOS 및 Windows의 경우

Docker v 18.03 이상 (2018 년 3 월 21 일부터)

host.docker.internal내부 IP 주소를 사용하거나 호스트가 사용하는 내부 IP 주소로 해석되는 특수 DNS 이름에 연결 하십시오.

Linux 지원 보류 https://github.com/docker/for-linux/issues/264

이전 버전의 Docker가있는 MacOS

Mac 용 Docker v 17.12 ~ v 18.02

위와 동일하지만 docker.for.mac.host.internal대신 사용하십시오.

Mac 용 Docker v 17.06 ~ v 17.11

위와 동일하지만 docker.for.mac.localhost대신 사용하십시오.

Mac 17.05 이하용 Docker

도커 컨테이너에서 호스트 시스템에 액세스하려면 IP 별칭을 네트워크 인터페이스에 연결해야합니다. 원하는 IP를 바인딩 할 수 있으며 다른 IP에는 사용하지 않아야합니다.

sudo ifconfig lo0 alias 123.123.123.123/24

그런 다음 서버가 위에서 언급 한 IP 또는를 듣고 있는지 확인하십시오 0.0.0.0. 로컬 호스트에서 수신 대기 중이 127.0.0.1면 연결을 수락하지 않습니다.

그런 다음 도커 컨테이너를이 IP로 지정하면 호스트 시스템에 액세스 할 수 있습니다!

테스트하기 curl -X GET 123.123.123.123:3000위해 컨테이너 내부 와 같은 것을 실행할 수 있습니다 .

별칭은 재부팅 할 때마다 재설정되므로 필요한 경우 시작 스크립트를 작성하십시오.

솔루션 및 추가 문서 : https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


나는 이것을 성공적으로 테스트했다. 방화벽을 끌 필요가 없습니다
alvaro g

15
2017 년 6 월 17.06 이후 릴리스에서 docker.for.mac.localhost호스트가 사용하는 내부 IP 주소로 확인되는 특별한 Mac 전용 DNS 이름에 연결하는 것이 좋습니다 . ... 나는 그것을 테스트했고 실제로 작동합니다! :)
Kyr

나 같은 Mac 사용자를위한 답변을 찾아보십시오. 감사. 내가 얻지 못한 것 중 하나는 ip route show | awk '/default/ {print $3}'주는 사람에게 왜 하나의 IP이고 docker.for.mac.localhost다른 것입니다.
dmmd


1
host.docker.internaldocker 컨테이너와 hosts 파일의 구성 127.0.0.1 host.docker.internal에서 사용 하는 것이 좋습니다.
junlin

84

사용 --net="host"당신의 docker run다음 명령 localhost하여 고정 표시기 호스트를 가리 킵니다 당신의 고정 표시기 컨테이너에.


15
컨테이너가 가상화 환경에서 실행된다는 사실로 인해 Windows 용 Docker / Mac 용 Docker for Dpcker를 사용하는 사람들에게는 작동하지 않습니다 .Hyper-V (Windows) / xhyve (Mac)
ninjaboy

6
이! 이것이 답입니다!
user3751385

14
그냥 레코드 : 도커 Componse 내 network_mode: "host"
jbarros

클라이언트 및 서버의 Docker for Mac 버전 19.03.1에서는 작동하지 않습니다. 나는 그것이 효과가 있었으면 좋겠다.
클레이

1
내가 맥에 있더라도 두 개의 도커 컨테이너 사이의 통신을 원할 때 작동하며 모든 응용 프로그램을 도커 이미지로 변환하면 나에게 충분합니다.
bormat

26

docker-compose가있는 솔루션 : 호스트 기반 서비스에 액세스하려면 https://docs.docker.com/compose/compose-file/#network_modenetwork_mode 매개 변수 를 사용할 수 있습니다

version: '3'
services:
  jenkins:
    network_mode: host

편집 2020-04-27 : 로컬 개발 환경에서만 사용하는 것이 좋습니다.


그렇다면 젠킨스에 어떻게 접근합니까? 호스트 네트워크 모드를 사용하는 경우 포트 전달이 작동하지 않는 것 같습니다
Jeff Tian

1
매우 위험한 솔루션이며 전혀 권장되지 않습니다. 명시 적으로 필요하지 않는 한 호스트 네트워크를 컨테이너로 열면 안됩니다
Fatemeh Majd

12

현재 Mac 및 Windows에서이 작업을 수행하는 가장 쉬운 방법은 host.docker.internal호스트 컴퓨터를 사용하는 호스트 를 사용하는 것입니다. 불행히도 아직 리눅스에서는 작동하지 않습니다 (2018 년 4 월 현재).


이 솔루션은 Docker 버전 19.03.1에서 작동했습니다. 여기에 제공된 많은 다른 솔루션이 작동하지 않습니다. 이것은 docs.docker.com/docker-for-mac/networking/에
clay

12

https://github.com/qoomon/docker-host를 정확하게 수행하기위한 도커 컨테이너를 만들었습니다.

그런 다음 컨테이너 이름 dns를 사용하여 호스트 시스템에 액세스 할 수 있습니다. curl http://dockerhost:9200


그것은 영리한 해결책입니다. 트래픽이 많을 때이를 사용하는 것을 알고 있습니까? 이 컨테이너를 통한 모든 트래픽을 프록 싱하는 데 오버 헤드가있을 수 있습니다.
bcoughlan

3
예, 루프백 장치를
통해서만

11

이 모든 네트워킹 정크에 대한 더 간단한 해결책은 서비스에 도메인 소켓을 사용하는 것입니다. 어쨌든 호스트에 연결하려는 경우 소켓을 볼륨으로 마운트하기 만하면됩니다. postgresql의 경우 다음과 같이 간단했습니다.

docker run -v /var/run/postgresql:/var/run/postgresql

그런 다음 네트워크 대신 소켓을 사용하도록 데이터베이스 연결을 설정했습니다. 말 그대로 그 쉬운.


이것은 훌륭한 솔루션입니다. 좋은 작업!
유료

2
참고로, 우리는 이것과 관련하여 큰 문제를 겪었습니다 : Docker for Mac은 소켓을 마운트 된 볼륨으로 지원하지 않습니다. 이것은 맥이 그것을 시도 할 때까지 수영으로 갔다. :(
mlissner

감사! 리눅스에서 매력처럼 작동했습니다!
Marcelo Cardoso

7

다양한 솔루션을 살펴본 결과 가장 해킹이 적은 솔루션을 찾았습니다.

  1. 브릿지 게이트웨이 IP의 고정 IP 주소를 정의하십시오.
  2. extra_hosts지시문 에서 게이트웨이 IP를 추가 항목으로 추가하십시오 .

유일한 단점은이 작업을 수행하는 네트워크 나 프로젝트가 여러 개인 경우 IP 주소 범위가 충돌하지 않는지 확인해야합니다.

Docker Compose 예제는 다음과 같습니다.

version: '2.3'

services:
  redis:
    image: "redis"
    extra_hosts:
      - "dockerhost:172.20.0.1"

networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

그런 다음 호스트 이름 "dockerhost"를 사용하여 컨테이너 내부에서 호스트의 포트에 액세스 할 수 있습니다.



3

호스트 시스템에서 실행중인 로컬 웹 서버에 두 가지 방법으로 액세스 할 수 있습니다.

  1. 공개 IP로 접근 1

    Jenkins Docker 컨테이너의 웹 서버에 액세스하려면 호스트 컴퓨터 공용 IP 주소를 사용하십시오.

  2. 호스트 네트워크를 통한 접근법 2

    "--net host"를 사용하여 호스트의 네트워크 스택에 Jenkins 도커 컨테이너를 추가하십시오. 호스트 스택에 배포 된 컨테이너는 호스트 인터페이스에 대한 전체 액세스 권한을 갖습니다. 호스트 시스템의 개인 IP 주소를 사용하여 docker container의 로컬 웹 서버에 액세스 할 수 있습니다.

NETWORK ID          NAME                      DRIVER              SCOPE
b3554ea51ca3        bridge                    bridge              local
2f0d6d6fdd88        host                      host                local
b9c2a4bc23b2        none                      null                local

호스트 네트워크로 컨테이너를 시작하고 docker 컨테이너에서 연결할 수있는 사용 가능한 모든 네트워크 IP 주소를 나열하도록 Eg: docker run --net host -it ubuntu실행 ifconfig하십시오.

예 : 로컬 호스트 컴퓨터에서 nginx 서버를 시작했으며 Ubuntu 도커 컨테이너에서 nginx 웹 사이트 URL에 액세스 할 수 있습니다.

docker run --net host -it ubuntu

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a604f7af5e36        ubuntu              "/bin/bash"         22 seconds ago      Up 20 seconds                           ubuntu_server

개인 네트워크 IP 주소로 Ubuntu 도커 컨테이너에서 Nginx 웹 서버 (로컬 호스트 시스템에서 실행)에 액세스합니다.

root@linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes

3

대한 docker-compose컨테이너 사이에 사용 승인 된 솔루션을 개인 네트워크를 만들 브리지 네트워킹을 사용 docker0하지 않습니다 일 컨테이너에서 출구 인터페이스가 없기 때문에 docker0대신은 임의로 생성 된 인터페이스 ID가 같은있다 :

$ ifconfig

br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.32.1  netmask 255.255.240.0  broadcast 192.168.47.255

불행하게도, 임의의 ID는 예측할 수 없으며, 작성시 네트워크를 재 작성해야 할 때마다 변경됩니다 (예 : 호스트 재부팅시). 이것에 대한 나의 해결책은 알려진 서브넷에서 개인 네트워크를 만들고 iptables해당 범위를 허용 하도록 구성 하는 것입니다.

파일 스 니펫 작성 :

version: "3.7"

services:
  mongodb:
    image: mongo:4.2.2
    networks:
    - mynet
    # rest of service config and other services removed for clarity

networks:
  mynet:
    name: mynet
    ipam:
      driver: default
      config:
      - subnet: "192.168.32.0/20"

환경에 필요한 경우 서브넷을 변경할 수 있습니다. 나는 기본적으로 생성 된 것을보기 위해을 192.168.32.0/20사용하여 임의로 선택 했습니다 docker network inspect.

iptables프라이빗 서브넷을 소스로 허용하도록 호스트에서 구성 하십시오.

$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT

이것이 가장 간단한 iptables규칙입니다. 대상 포트와 같은 다른 제한을 추가 할 수 있습니다. iptables 규칙이 만족할 때 규칙을 유지하는 것을 잊지 마십시오.

이 방법은 반복 가능하므로 자동화 할 수 있다는 장점이 있습니다. ansible의 template모듈을 사용 하여 변수 대체로 작성 파일을 배포 한 다음 iptablesshell모듈을 사용하여 각각 방화벽 규칙을 구성하고 유지합니다.


나는 여러 가지 답변을 제안하는 것을 보았지만 iptables -A INPUT -i docker0 -j ACCEPT도움이되지는 않았지만 iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT여기 에 제안 된 것은 내 문제를 해결했습니다.
테리 브라운

1

이것은 오래된 질문이며 많은 답변이 있었지만 그 중 어느 것도 내 상황에 잘 맞지 않습니다. 필자의 경우 컨테이너는 매우 희박하며 컨테이너 내에서 호스트의 IP 주소를 추출하는 데 필요한 네트워킹 도구가 없습니다.

또한 --net="host"접근 방식은 여러 컨테이너로 잘 격리 된 네트워크 구성을 원할 때 적용 할 수없는 매우 거친 접근 방식입니다.

따라서 내 접근 방식은 호스트 측에서 호스트 주소를 추출한 다음 --add-host매개 변수 를 사용하여 컨테이너에 전달하는 것입니다 .

$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name

또는 호스트의 IP 주소를 환경 변수에 저장하고 나중에 변수를 사용하십시오.

$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name

그런 다음이 docker-host컨테이너의 호스트 파일에 추가되고 데이터베이스 연결 문자열 또는 API URL에서 사용할 수 있습니다.


0

두 개의 도커 이미지가 "이미"만들어져 있고 다른 컨테이너와 통신하기 위해 두 개의 컨테이너를 배치하려고 할 때.

이를 위해 고유 한 --name으로 각 컨테이너를 편리하게 실행하고 --link 플래그를 사용하여 컨테이너 간 통신을 활성화 할 수 있습니다. 도커 빌드 중에는 이것을 얻지 못합니다.

나 자신과 같은 시나리오에있을 때

docker build -t "centos7/someApp" someApp/ 

당신이하려고 할 때 끊어집니다

curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

"curl / wget"에 멈춰서 "라우트 호스트"를 반환하지 않습니다.

그 이유는 기본적으로 컨테이너에서 호스트로의 통신 또는 호스트에서 실행되는 다른 컨테이너와의 통신을 금지하기 때문에 docker가 설정 한 보안 때문입니다. 로컬 머신에서 실행되는 docker 머신의 에코 시스템이 너무 많은 장애물없이 서로 액세스 할 수 있다고 기대할 것입니다.

이에 대한 설명은 다음 설명서에 자세히 설명되어 있습니다.

http://www.dedoimedo.com/computers/docker-networking.html

네트워크 보안을 낮춤으로써 이동하는 데 도움이되는 두 가지 빠른 해결 방법이 제공됩니다.

가장 간단한 대안은 방화벽을 끄거나 모두 허용하는 것입니다. 이는 필요한 명령을 실행하는 것을 의미하며, systemctl stop firewalld, iptables -F 또는 이와 동등한 명령 일 수 있습니다.

이 정보가 도움이 되길 바랍니다.


3
참고로, --link이제는 더 이상 사용되지 않습니다
Mr.Budris

0

저에게 (Windows 10, Docker Engine v19.03.8) https://stackoverflow.com/a/43541732/7924573https://stackoverflow.com/a/50866007/7924573 의 혼합이었습니다 .

  1. host / ip를 host.docker.internal로 변경하십시오.
    예 : LOGGER_URL = " http : //host.docker.internal : 8085 / log "
  2. network_mode를 브리지로 설정하십시오 (포트 전달을 유지하려는 경우; host를 사용하지 않는 경우 ).
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge 또는 대안으로 --net="bridge"docker-compose를 사용하지 않는 경우 사용하십시오 ( https://stackoverflow.com/a/48806927/7924573 와 유사 )
    이전 답변에서 지적했듯이 이것은 로컬 개발 환경에서만 사용해야 합니다 .
    자세한 내용은 https://docs.docker.com/compose/compose-file/#network_modehttps://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds를 참조하십시오.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.