Docker 컨테이너 내부에서 머신의 로컬 호스트에 어떻게 연결합니까?


1449

도커 컨테이너 내에서 Nginx를 실행하고 localhost에서 mysql을 실행하고 있으며 Nginx 내에서 MySql에 연결하고 싶습니다. MySql은 localhost에서 실행 중이며 포트를 외부 세계에 노출시키지 않으므로 로컬 IP 주소는 컴퓨터의 IP 주소에 바인드되지 않습니다.

이 도커 컨테이너 내 에서이 MySql 또는 localhost의 다른 프로그램에 연결하는 방법이 있습니까?

이 질문은 도커 호스트의 IP 주소가 네트워크의 퍼블릭 IP 또는 프라이빗 IP 일 수 있다는 사실 때문에 "도커 컨테이너 내부에서 도커 호스트의 IP 주소를 얻는 방법"과 다릅니다. 도커 컨테이너 내에서 연결할 수 없습니다 (AWS에서 호스팅되는 경우 퍼블릭 IP를 의미합니다). Docker 호스트의 IP 주소가 있어도 Docker 네트워크가 오버레이, 호스트, 브리지, macvlan 등이 될 수 있으므로 IP 주소가 주어지면 컨테이너 내에서 docker 호스트에 연결할 수 없다는 의미는 아닙니다. 그 IP 주소.


왜 mysql을 docker0에 바인딩하지 않습니까?
ivant

2
Windows 시스템 :-$ docker run -d --name MyWebServer -P httpd
Lokesh S


없이 network: host당신은 호스트에 컨테이너에서 돌아갈 수 없습니다. 컨테이너로만 호스트하십시오. 이것이 컨테이너의 기본 이념입니다. 안정성과 보안상의 이유로 분리되어 있습니다.
FreeSoftwareServers

답변:


1968

편집 : 당신이 사용하는 경우 부두 노동자를 위해 맥 또는 부두 노동자를 위해 윈도우 18.03+를 그냥 호스트 사용하여 MySQL의 서비스에 연결 host.docker.internal(대신의를 127.0.0.1연결 문자열에서).

Docker 18.09.3에서 Docker-for-Linux에서는 작동하지 않습니다. 수정은 3 월 8, 2019 제출 된 희망의 코드베이스에 병합됩니다. 그때까지 해결 방법은 qoomon 's answer에 설명 된대로 컨테이너를 사용하는 입니다.

2020-01 : 일부 진전 이 이루어졌습니다. 모든 것이 잘되면 Docker 20.04에 도착합니다.


TLDR

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

참고 :이 모드 는 문서에 따라 Linux 용 Docker에서만 작동 합니다 .


도커 컨테이너 네트워킹 모드에 대한 참고 사항

Docker는 컨테이너를 실행할 때 다양한 네트워킹 모드를 제공합니다 . 선택한 모드에 따라 docker 호스트에서 실행되는 MySQL 데이터베이스에 다르게 연결됩니다.

docker run --network = "bridge"(기본값)

Docker docker0는 기본적으로 이름이 지정된 브리지를 만듭니다 . 도커 호스트와 도커 컨테이너 모두 해당 브리지에 IP 주소가 있습니다.

Docker 호스트에서 sudo ip addr show docker0다음과 같이 출력됩니다.

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::5484:7aff:fefe:9799/64 scope link
       valid_lft forever preferred_lft forever

도커 호스트는 네트워크 인터페이스 172.17.42.1에 IP 주소 를 가지고 docker0있습니다.

이제 새로운 컨테이너를 시작하고 쉘을 가져옵니다. docker run --rm -it ubuntu:trusty bash컨테이너 유형 내에서 ip addr show eth0기본 네트워크 인터페이스 설정 방법을 확인하십시오.

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.1.192/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
       valid_lft forever preferred_lft forever

여기 내 컨테이너에는 IP 주소가 172.17.1.192있습니다. 이제 라우팅 테이블을보십시오.

root@e77f6a1b3740:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

따라서 도커 호스트의 IP 주소 172.17.42.1는 기본 경로로 설정되며 컨테이너에서 액세스 할 수 있습니다.

root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms

docker run --network = "host"

또는 네트워크 설정이로 설정된host 도커 컨테이너를 실행할 수 있습니다 . 이러한 용기는 고정 표시기 호스트와 볼의 용기 지점에서 네트워크 스택을 공유 localhost(또는 127.0.0.1고정 표시기 호스트를 참조한다).

도커 컨테이너에서 열린 포트는 도커 호스트에서 열립니다. 그리고 이것은 -p또는 -P docker run옵션 을 요구하지 않습니다 .

내 도커 호스트의 IP 구성 :

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

호스트 모드 의 도커 컨테이너에서 :

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

보시다시피 도커 호스트와 도커 컨테이너는 모두 동일한 네트워크 인터페이스를 공유하므로 IP 주소가 동일합니다.


컨테이너에서 MySQL에 연결

브리지 모드

브리지 모드의 컨테이너에서 도커 호스트에서 실행중인 MySQL에 액세스하려면 MySQL 서비스가 172.17.42.1IP 주소의 연결을 수신하고 있는지 확인해야합니다 .

이렇게하려면, 당신이 중 하나를 가지고 있는지 확인 bind-address = 172.17.42.1또는 bind-address = 0.0.0.0MySQL의 설정 파일 (my.cnf의)에서.

게이트웨이의 IP 주소로 환경 변수를 설정해야하는 경우 컨테이너에서 다음 코드를 실행할 수 있습니다.

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

그런 다음 응용 프로그램에서 DOCKER_HOST_IP환경 변수를 사용하여 MySQL에 대한 연결을 엽니 다.

참고 :bind-address = 0.0.0.0 MySQL 서버 를 사용하면 모든 네트워크 인터페이스에서 연결을 수신합니다. 즉, 인터넷에서 MySQL 서버에 접속할 수 있습니다. 방화벽 규칙을 적절히 설정하십시오.

참고 2 :bind-address = 172.17.42.1 MySQL 서버 를 사용하는 경우 에 연결된 연결을 수신하지 않습니다 127.0.0.1. MySQL에 연결하려는 도커 호스트에서 실행되는 프로세스는 172.17.42.1IP 주소 를 사용해야합니다 .

호스트 모드

호스트 모드의 컨테이너에서 도커 호스트에서 실행되는 MySQL에 액세스하려면 bind-address = 127.0.0.1MySQL 구성을 유지 하고 127.0.0.1컨테이너에서 연결하기 만하면됩니다.

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

참고 : 사용 mysql -h 127.0.0.1하지 말고 mysql -h localhost; 그렇지 않으면 MySQL 클라이언트는 유닉스 소켓을 사용하여 연결을 시도합니다.


8
자세한 답변을 주셔서 감사합니다! 내가 수집 한 것에서 호스트 모드를 사용하는 것이 localhost를 통해이 기능을 얻는 유일한 방법입니다. 시도하지는 않았지만 별도의 네트워크를 만들어 자체 브리지를 통해 컨테이너를 연결하여 공통 'localhost'를 제공 할 수 있다고 가정합니다.
Ben

26
OSX 사용자를위한 참고 사항 : "docker-machine ssh default"를 사용하여 먼저 docker virtual machine (boot2docker)에 로그인 한 후 "sudo ip addr show docker0"을 실행하십시오. 거기에서 토마스의 지시를 계속하십시오.
Charlie Dalsass

30
Mac 용 Docker를 실행 중이며 더 이상 172.17.42.1, 더 이상 docker0이 없습니다. 그것은 게이트웨이로서 172.17.0.1이었고 심지어 할 수 없었습니다telnet 172.17.0.1 3306
zx1986

26
이와 같은 네트워킹 대신 mysql 소켓을 컨테이너에 마운트 할 수 있습니다 -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sock.
chx

8
Docker0 인터페이스가 없으므로 Mac에서 Docker를 실행하고 boot2docker를 사용하지 않는 상황을 누군가가 해결할 수 있습니까?
TheJKFever

350

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


5
화려하고 고마워, 이것은 컨테이너 내에서 나를 위해 일했습니다. mysql -uroot -hdocker.for.mac.localhost
Richard Frank

1
docker.for.mac.localhost 정확히 내가 찾던 것입니다. 그러나 이것은 동시에 지옥만큼 더럽습니다. 도커에서 hook docker.for.mac.localhost는 Mac뿐만 아니라 모든 운영 체제에서 유효한 일반 도커 내부 이름이 될 것으로 기대합니다. 그러나 개발 목적으로는 이것으로 충분합니다.
99 소노

9093에 노출 된 포트에 어떻게 액세스합니까?. docker.for.mac.localhost 9093을 telnet하려고합니다. 연결할 수 없지만 docker.for.mac.localhost ping하면 도달 할 수 있습니다.
Achilleus

1
로컬 호스트의 하위 도메인 사용을 금지하는 RFC가 있으므로 컨테이너에서 호스트 확인을 위해 docker.for.mac.localhost 대신 DNS 이름 docker.for.mac.host.internal을 사용해야합니다 (여전히 유효 함). tools.ietf.org/html/draft-west-let-localhost-be-localhost-06을 참조하십시오 .
Jya

이것은 나를 위해 작동하지 않습니다. I docker run -e HOSTNAME= docker.for.mac.host.internal 일 때 컨테이너가 생성되지만 알림이 발생하지 않습니다. 그런 다음 crtl + C해야합니다. 와 --net=host -e HOSTNAME=localhost적어도 컨테이너 실행하고 서비스 I의 필요성을 찾을 수 없다는 불평 (MySQL의 데시벨).
Jorge Orpinel

83

위의 게시물과 비슷한 해킹을 수행하여 로컬 IP를 컨테이너의 별칭 이름 (DNS)에 매핑하십시오. 주요 문제는 리눅스와 OSX에서 호스트 IP 주소로 작동하는 간단한 스크립트를 사용하여 동적으로 접근하는 것 입니다. 두 환경에서 작동하는이 스크립트를 수행했습니다 (Linux 배포가 "$LANG" != "en_*"구성된 경우에도 ).

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

따라서 Docker Compose를 사용하면 전체 구성은 다음과 같습니다.

시작 스크립트 (docker-run.sh) :

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-compose.yml :

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

그런 다음 변경 http://localhosthttp://dockerhost코드에서.

DOCKERHOST스크립트 를 사용자 정의하는 방법에 대한 고급 안내서를 보려면 이 게시물 을 보고 스크립트 작동 방식에 대해 설명하십시오.


1
유스 케이스에 따라 DOCKERHOST도커 컨테이너가 로컬로 연결 해야하는 모든 서비스에서 "localhost"또는 0.0.0.0 대신 여기 값 을 사용하여 벗어날 수도 있습니다.
enderland

2
사용자 지정 네트워크와 호환되도록 솔루션을 약간 수정했습니다. export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') 여기서 <NETWORK-NAME> 은 docker-compose (일반적으로 path-name - network_name )에 의해 정의 된 브리지 또는 네트워크 이름 일 수 있습니다 .
dieresys 2016

1
주석을 추가해야합니다. dockerhostdb 연결을위한 호스트로 사용하십시오 (일반적 localhost으로 구성 파일에서 대체 ).
Justin

이상한 해결책, 그러나 그것의 유일한 것은 PHP CLI와 함께 docker에서 xdebug를 작동시키는 유일한 것
Eddie

hacl에서이 솔루션을 사용한 후 Acl이 작동을 멈췄습니다. 왜 그런지 알아?
HyukHyukBoi

41

이것은 앱이 연결할 수있는 코드 나 네트워킹을 건드리지 않고 NGINX / PHP-FPM 스택에서 나를 위해 일했습니다. localhost

mysqld.sock호스트에서 컨테이너 내부로 마운트 하십시오.

mysql을 실행하는 호스트에서 mysql.sock 파일의 위치를 ​​찾으십시오.
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

도커에서 예상되는 위치에 해당 파일을 마운트하십시오.
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

mysqld.sock의 가능한 위치 :

/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock 
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP

2
이것은 방화벽을 사용하지 않는 경우 Mysql을 외부에 노출시키지 않는 훨씬 깨끗한 솔루션입니다.
user1226868

5
소켓은 더 자주 차단되고 이상한 동작을 일으킬 수 있으므로 TCP뿐만 아니라 확장되지 않습니다. 가능할 때마다 TCP를 사용하십시오.
Joel E Salas 2016 년

3
@JoelESalas 그 주장에 대한 출처가 있습니까?
Private

이것이 가장 쉬운 해결책이라는 것을 알았습니다. 사용자 엄지 손가락! StackOverflow에 더 자주 기여해야합니다.
Private

2
@JoelESalas 당신이 착각했다고 생각합니다. mysql 클라이언트 라이브러리는 로컬 호스트에 실제로 연결하지 않고 로컬 호스트에 연결할 때 기본적으로 유닉스 소켓을 사용합니다. 유닉스 소켓은 TCP 스택과 라우팅의 오버 헤드를 피하고 더 빠르게 실행됩니다.
M Conrad

25

host.docker.internal모든 플랫폼에서 작업 할 때까지 수동 설정없이 컨테이너를 NAT 게이트웨이로 사용할 수 있습니다.

https://github.com/qoomon/docker-host


5
Windows 컨테이너가 설치된 Windows 용 Docker 19.03.2에서 이것이 작동하지 않음을 확인할 수 있습니다.
KMC

어떻게 고칠 수 있습니까? (저는 Windows 사용자가 아닙니다)
qoomon

환경에서 mysql이 사용하는 포트를 차단하지 않으면 호스트 된 컴퓨터 이름으로 서버를 참조 할 수 있습니다. 따라서 연결 문자열에서 컴퓨터 이름을 서버 이름으로 사용하십시오.
KMC

24

Linux 용 솔루션 (커널> = 3.6).

로컬 호스트 서버에는 IP 주소가 172.17.0.1 인 기본 도커 인터페이스 docker0 이 있습니다. 컨테이너는 기본 네트워크 설정 --net = "bridge"로 시작했습니다 .

  1. docker0 인터페이스에 route_localnet을 활성화하십시오.
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. iptables에 다음 규칙을 추가하십시오.
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. 로컬 호스트를 제외한 모든 사람이 의미하는 '%'의 액세스 권한으로 mysql 사용자를 만듭니다.
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. 스크립트에서 mysql-server 주소를 172.17.0.1로 변경하십시오.


로부터 커널 문서 :

route_localnet -BOOLEAN : 라우팅하는 동안 루프백 주소를 화성 소스 또는 대상으로 간주하지 마십시오. 이를 통해 로컬 라우팅 목적으로 127/8을 사용할 수 있습니다 ( 기본 FALSE ).


1
두 번째 iptable 명령의 목적은 무엇입니까? 첫 번째는 172.17.0.1:3306에서 127.0.0.1:3306과 일치하는 모든 tcp 대상을 다시 작성하는 것임을 이해할 수 있지만 두 번째 iptable 명령이 필요한 이유는 무엇입니까?
Patrick

17

Windows 10 용 솔루션

Docker Community Edition 17.06.0-ce-win18 2017-06-28 (안정적)

호스트의 DNS 이름을 사용 docker.for.win.localhost하여 내부 IP로 확인할 수 있습니다. (일부 언급 된 경고에주의 windows해야합니다. win)

개요
내를 실행중인 로컬 호스트, 내 부두 노동자의 컨테이너에 연결 비슷한, 할 필요가 Azure Storage EmulatorCosmosDB Emulator.

Azure Storage Emulator에 기본을 청취하여 127.0.0.1 , 당신은 너무, 나는 기본 설정으로 작동 할 수있는 솔루션을 찾고 있었다 바인딩 된 IP를 변경할 수있다.

이것은 또한 기본 포트 설정으로 호스트에서 로컬로 실행되는 Docker 컨테이너에서 SQL Server및 로 연결 IIS하는 데 사용됩니다.


13

매우 간단하고 빠른 경우 ifconfig (linux) 또는 ipconfig (windows)를 사용하여 호스트 IP를 확인한 다음

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

이렇게하면 컨테이너가 호스트에 액세스 할 수 있습니다. DB에 액세스 할 때는 이전에 지정한 이름 (이 경우 "dockerhost")과 DB가 실행중인 호스트의 포트를 사용해야합니다.


HaProxy에서이 솔루션은 어떤 이유로 든 acl의 작동을 중지했으며 기본 설정 만 작동합니다.
HyukHyukBoi

1
리눅스 시스템에서 작동하는 유일한 솔루션. +1
Rafik Farhad

11

Windows 10 Home에서 Docker Toolbox를 사용할 때 아무런 대답도 없었지만 10.0.2.2 는 호스트를이 주소의 VM에 노출시키는 VirtualBox를 사용하기 때문에 효과가 없었습니다.


2
효과가있다. --network = host를 지정할 필요조차 없습니다. 10.0.2.2가 호스트의 기본 IP로 설정되어있는 것 같습니다. 감사.
TheManish

그러나 모든 Windows 및 Mac 버전에서이 고정 IP를 사용할 수 있습니까? 스크립트를 통해 여러 플랫폼에서이 고정 IP를 어떻게 처리 할 수 ​​있습니까?
151291

이것은 나를 위해 일했습니다. 호스트 (윈도우)에서 ipconfig를 실행하고 IP 주소를Ethernet adapter vEthernet (DockerNAT)
Kihats

10

브리지 네트워크 드라이버를 사용한다고 가정하면 Windows 사용자는 MySQL을 hyper-v 네트워크 인터페이스의 IP 주소에 바인딩해야합니다.

이것은 일반적으로 숨겨진 C : \ ProgramData \ MySQL 폴더 아래의 구성 파일을 통해 수행됩니다.

0.0.0.0에 바인딩하면 작동하지 않습니다. 필요한 주소는 도커 구성에도 표시되며 제 경우에는 10.0.75.1입니다.


3
메달을받을 자격이 있습니다! 나는 이틀 동안이 일을 해왔다. 도와 주셔서 감사합니다!
Michael

1
나는 또한 이틀 동안이 일을하고 있었다. 내가 찾은 웹상의 유일한 곳입니다. Microsoft는 Docker 컨테이너 내에서 MSSQL에 연결하는 것에 대해 말할 때 완전히 침묵합니다. 그들이 스스로 작동하는지 궁금해합니다!
Contango

8

편집 : GitHub의 개념을 프로토 타이핑했습니다. 체크 아웃 : https://github.com/sivabudh/system-in-a-box


우선, 제 대답은 맥을 사용하는 사람들과 리눅스를 사용하는 사람들의 두 그룹에 맞춰져 있습니다.

호스트 네트워크 모드는 Mac에서 작동하지 않습니다. IP 별칭을 사용해야합니다 ( https://stackoverflow.com/a/43541681/2713729 참조).

호스트 네트워크 모드는 무엇입니까? 참조 : https://docs.docker.com/engine/reference/run/#/network-settings

둘째, Linux를 사용하는 사람들을 위해 (나의 직접적인 경험은 Ubuntu 14.04 LTS에 있었고 곧 프로덕션에서 16.04 LTS로 업그레이드하고 있습니다), , Docker 컨테이너 내에서 localhost실행 되는 서비스를 도커 호스트 (예 : 랩톱).

어떻게?

열쇠는 Docker 컨테이너를 실행할 때 호스트 모드 로 실행해야 합니다. 명령은 다음과 같습니다.

docker run --network="host" -id <Docker image ID>

당신이 작업을 수행 할 때 ifconfig(당신이해야합니다 apt-get install net-tools에 대한 컨테이너 ifconfig컨테이너 내부 호출 될), 네트워크 인터페이스 도커 호스트에서 하나 (예. 노트북)과 동일한 것을 볼 수 있습니다.

필자는 Mac 사용자이지만 Parallels에서 Ubuntu를 실행하므로 Mac을 사용하는 것이 불리하지는 않습니다. ;-)

그리고 이것은 NGINX 컨테이너를에서 실행되는 MySQL에 연결하는 방법 localhost입니다.


1
호스트 모드는 OS 네트워크 스택을 사용하므로 더 나은 성능을 제공 한다는 점에 유의해야합니다 .
sivabudh

2
아주 좋은 지적입니다. 사용되지 않는 IP 연결 docs.docker.com/docker-for-mac/networking 을 사용하여 컨테이너에서 호스트 서비스로 연결할 수 있습니다 . 유쾌한 해결책은 아니지만 작동합니다.
Xavier Huppé

여기 좋은 물건. 로 컨테이너 안에 들어가면 --network="host"어떻게 예를 들어 mysql 호스트에 연결합니까?
Michael

1
@Buccleuch 그냥 사용하십시오 localhost. 내 GitHub 소스 코드를 확인하십시오 : github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . 를 검색 'HOST'하면 Postgresql에 연결하는 127.0.0.1이 표시됩니다.
sivabudh

@ user833482에 따라 볼륨을 마운트하고 물론 도커 컨테이너에 mysql-client와 서버를 설치 한 후 호스트 mysql 데이터베이스에 액세스 할 수있었습니다.
Michael

7

Mac OSX를위한 가장 간단한 솔루션

Mac의 IP 주소 만 사용하십시오. Mac에서 IP 주소를 가져 와서 컨테이너 내에서 사용하려면 다음을 실행하십시오.

$ ifconfig | grep 'inet 192'| awk '{ print $2}'

Mac 또는 다른 도커 컨테이너에서 로컬로 실행되는 서버가 0.0.0.0을 수신하는 한, 도커 컨테이너는 해당 주소에 도달 할 수 있습니다.

0.0.0.0에서 수신 대기하는 다른 도커 컨테이너에 액세스하려는 경우 172.17.0.1을 사용할 수 있습니다


1
Mac 용 Docker는 docker.for.mac.host.internal이제 호스트 이름을 공개합니다 .
Matt

5

이것은 실제 질문에 대한 답변이 아닙니다. 이것이 비슷한 문제를 해결하는 방법입니다. 솔루션은 완전히 다음과 같습니다 . 컨테이너가 통신 할 수 있도록 Docker 컨테이너 네트워킹을 정의하십시오 . Nic Raboy 덕분에

한 컨테이너와 다른 컨테이너 사이에서 REST 호출을 수행하려는 다른 사람들을 위해 여기에 남겨 두십시오. 도커 환경에서 localhost 대신 무엇을 사용해야합니까?

네트워크가 어떻게 보이는지 확인 docker network ls

새로운 네트워크 만들기 docker network create -d my-net

첫 번째 컨테이너를 시작하십시오 docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

첫 번째 컨테이너의 네트워크 설정을 확인하십시오 docker inspect first_container. "네트워크": 'my-net'이 있어야합니다

두 번째 컨테이너를 시작하십시오 docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

두 번째 컨테이너에 대한 네트워크 설정을 확인하십시오 docker inspect second_container. "네트워크": 'my-net'이 있어야합니다

두 번째 컨테이너 docker exec -it second_container sh또는 docker exec -it second_container bash.

두 번째 컨테이너 내부에서 첫 번째 컨테이너를 핑할 수 있습니다 ping first_container. 또한 다음과 같은 코드 호출 http://localhost:5000http://first_container:5000


정확히 내가 찾던 것. 감사합니다 : D
Simar Singh

5

창문의 경우

스프링 구성에서 데이터베이스 URL을 변경했습니다. spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

그런 다음 이미지를 빌드하고 실행하십시오. 그것은 나를 위해 일했다.


흥미로운 ....
Phil

나를 위해 작동하지 않습니다. Mac이 있고 PHP 컨테이너에서 localhost mysql에 연결하려고합니다. 어떤 아이디어?
A. Zalonis

4

Thomasleveil의 답변에 동의하지 않습니다.

mysql을 172.17.42.1에 바인드하면 다른 프로그램이 호스트의 데이터베이스를 사용하여 데이터베이스에 도달하지 못하게됩니다. 모든 데이터베이스 사용자가 고정되어있는 경우에만 작동합니다.

mysql을 0.0.0.0에 바인딩하면 db가 외부 세계에 열리게되는데, 이는 매우 나쁜 일일뿐만 아니라 원문 제작자가 원했던 것과 상반됩니다. "MySql이 localhost에서 실행 중이고 포트를 외부에 노출시키지 않으므로 localhost에 바인딩되어 있습니다"

ivant의 의견에 대답하려면

"mysql을 docker0에 바인딩하지 않는 이유는 무엇입니까?"

이건 불가능 해. mysql / mariadb 문서에는 여러 인터페이스에 바인딩 할 수 없다고 명시되어 있습니다. 0, 1 또는 모든 인터페이스에만 바인딩 할 수 있습니다.

결론적으로, 도커 컨테이너에서 호스트의 (localhost 전용) 데이터베이스에 도달하는 방법을 찾지 못했습니다. 그것은 매우 일반적인 패턴처럼 보이지만 어떻게 해야할지 모르겠습니다.


4
도커 호스트에서 172.17.42.1주소를 사용하여 MySQL 서버에 계속 연결할 수 있습니다 . 그러나 그렇지 않으면 귀하의 메모가 옳습니다. 또한 컨테이너를 연결할 수 있도록 hostMySQL 서버를 바인딩 할 수 있는 네트워킹 모드로 답변을 편집 127.0.0.1했습니다
Thomasleveil

아니요, 내가 말했듯이 mysql이 localhost에 바인딩되어 있으면 172.17.42.1에 연결할 수 없습니다.
orzel

4
"mysql 바인드를 172.17.42.1에 만들면 다른 프로그램이 호스트의 데이터베이스를 사용하여 접근 할 수 없게됩니다." -사실이 아닙니다. 다른 프로그램은 mysql을 사용할 수 있으며 localhost / 127.0.0.1 대신 172.17.42.1에 연결하면됩니다.
0x89

이 답변의 문제에 대한 해결책은 일반적으로 MySQL 서버가 인터넷에 연결되어 0.0.0.0데이터베이스에 액세스 할 수 없도록 방화벽 에 바인딩 한 다음 방화벽을 설정하는 것입니다.

4

내 해결책은 다음과 같습니다.

  • #bind-address = 127.0.0.1 /etc/mysql/mysql.conf.d의 주석 으로 로컬 mysql 서버를 공개 액세스로 설정

  • MySQL 서버를 다시 시작하십시오 sudo /etc/init.d/mysql restart

  • 다음 명령을 실행하여 모든 사용자 루트 액세스 호스트를여십시오. mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • sh 스크립트 작성 : run_docker.sh

    #! bin / bash

    HOSTIP =`ip -4 addr show scope 전역 개발자 eth0 | grep inet | awk '{print \ $ 2}'| 컷 -d / -f 1`


      docker run -it -d --name web-app \
                  --add-host = local : $ {HOSTIP} \
                  -p 8080 : 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = 데모 \
                  -e DATABASE_USER = 루트 \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • docker-composer로 실행

    버전 : '2.1'

    서비스:
    바람둥이 : extra_hosts : - "로컬 : 10.1.2.232" 이미지 : sopheamak / springboot_docker_mysql
    포트 : -8080 : 8080 환경: -DATABASE_HOST = 로컬 -DATABASE_USER = 루트 -DATABASE_PASSWORD = 루트 -DATABASE_NAME = 데모 -DATABASE_PORT = 3306


4

몇 가지 솔루션이 떠 오릅니다.

  1. 종속성을 컨테이너로 먼저 이동
  2. 다른 서비스를 외부에서 액세스 할 수있게하고 해당 외부 IP로 연결하십시오
  3. 네트워크 격리없이 컨테이너를 실행
  4. 네트워크를 통한 연결을 피하고 대신 볼륨으로 마운트 된 소켓을 사용하십시오

이것이 기본적으로 작동하지 않는 이유는 기본적으로 컨테이너가 자체 네트워크 네임 스페이스로 실행되기 때문입니다. 즉, localhost (또는 루프백 인터페이스를 가리키는 127.0.0.1)는 컨테이너마다 고유합니다. 이것에 연결하면 컨테이너 자체에 연결되며 도커 외부 또는 다른 도커 컨테이너 내부에서 실행되는 서비스는 아닙니다.

옵션 1 : 의존성을 컨테이너로 옮길 수 있다면 먼저해야합니다. 다른 사람들이 자신의 환경에서 컨테이너를 실행하려고 할 때 응용 프로그램 스택을 이식 가능하게 만듭니다. 또한 마이그레이션되지 않은 다른 서비스가 여전히 포트에 도달 할 수있는 호스트에 포트를 게시 할 수 있습니다. 도커 호스트의 로컬 호스트 인터페이스에 포트를 게시하여 게시 된 포트 -p 127.0.0.1:3306:3306에 대해 다음 과 같은 구문으로 외부에서 액세스 할 수 없도록 할 수도 있습니다 .

옵션 2 : 컨테이너 내부에서 호스트 IP 주소를 감지하는 다양한 방법이 있지만 각각 작동하는 시나리오는 제한적입니다 (예 : Mac 용 Docker 필요). 가장 휴대하기 쉬운 옵션은 환경 변수 또는 구성 파일과 같이 컨테이너에 호스트 IP를 주입하는 것입니다. 예 :

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

이를 위해서는 서비스가 해당 외부 인터페이스에서 수신 대기해야하며 이는 보안 문제 일 수 있습니다. 컨테이너 내부에서 호스트 IP 주소를 가져 오는 다른 방법 은이 게시물을 참조하십시오 .

옵션 3 : 네트워크 격리없이 실행, 즉로 실행은 --net host애플리케이션이 호스트 네트워크 네임 스페이스에서 실행되고 있음을 의미합니다. 이는 컨테이너의 격리 수준이 낮으므로 DNS를 사용하여 공유 도커 네트워크를 통해 다른 컨테이너에 액세스 할 수 없다는 것을 의미합니다 (대신 컨테이너화 된 다른 응용 프로그램에 액세스하려면 게시 된 포트를 사용해야 함). 그러나 호스트에서만 수신 대기하는 호스트의 다른 서비스에 액세스해야하는 응용 프로그램의 127.0.0.1경우 가장 쉬운 옵션이 될 수 있습니다.

옵션 4 : 다양한 서비스는 파일 시스템 기반 소켓을 통한 액세스도 허용합니다. 이 소켓을 바인드 마운트 볼륨으로 컨테이너에 마운트 할 수 있으므로 네트워크를 통하지 않고 호스트 서비스에 액세스 할 수 있습니다. 도커 엔진에 액세스하기 위해 종종 /var/run/docker.sock컨테이너 에 마운트하는 예를 볼 수 있습니다 (컨테이너 루트 액세스를 호스트에 부여). mysql을 사용하면 mysql 이 소켓을 사용하여 변환하는 것과 같은 것을 시도하고 -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sock연결할 수 localhost있습니다.


3

알파인 이미지를 사용하여 호스트 IP를 얻을 수 있습니다

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

항상 alpine을 사용하여 명령을 실행할 때보 다 일관성이 있습니다.

Mariano의 대답과 유사하게 동일한 명령을 사용하여 환경 변수를 설정할 수 있습니다

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up

3

로컬 호스트 서비스가 바인딩하는 인터페이스를 변경할 수없는 Linux의 경우

우리가 해결해야 할 두 가지 문제가 있습니다

  1. 호스트의 IP 얻기
  2. Docker에서 로컬 호스트 서비스 사용 가능

첫 번째 문제는 다른 답변에서 제공된 것처럼 qoomon의 docker-host image를 사용하여 해결할 수 있습니다 .

이 컨테이너를 다른 컨테이너와 동일한 브리지 네트워크에 추가해야 액세스 할 수 있습니다. 컨테이너 내부의 터미널을 열고 핑이 가능한지 확인하십시오 dockerhost.

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

이제 더 어려운 문제로 인해도 커가 서비스에 액세스 할 수 있습니다.

telnet을 사용하여 호스트의 포트에 액세스 할 수 있는지 확인할 수 있습니다 (설치해야 할 수도 있음).

문제는 컨테이너가 SSH와 같은 모든 인터페이스에 바인딩 된 서비스에만 액세스 할 수 있다는 것입니다.

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

그러나 localhost에만 바인딩 된 서비스에는 액세스 할 수 없습니다.

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

여기서 올바른 해결책은 서비스를 도커 브리지 네트워크에 바인딩하는 것입니다. 그러나이 답변은이를 변경할 수 없다고 가정합니다. 대신 우리는을 사용할 것 iptables입니다.

먼저, docker가 사용하는 브리지 네트워크의 이름을 찾아야합니다 ifconfig. 이름이없는 브리지를 사용하는 경우이 이름은 docker0입니다. 그러나 명명 된 네트워크를 사용하는 경우 br-해당 도커로 시작하는 브리지 가 대신 사용됩니다. 광산은 br-5cd80298d6f4입니다.

이 브리지의 이름이 설정되면이 브리지에서 로컬 호스트로 라우팅을 허용해야합니다. 보안상의 이유로 기본적으로 비활성화되어 있습니다.

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

이제 iptables규칙 을 설정하겠습니다 . 컨테이너는 도커 브리지 네트워크의 포트에만 액세스 할 수 있으므로 서비스가 실제로이 네트워크의 포트에 바인딩 된 것처럼 가장합니다.

이를 위해 모든 요청 <docker_bridge>:portlocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

예를 들어, 포트 1025의 내 서비스

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

이제 컨테이너에서 서비스에 액세스 할 수 있어야합니다.

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready

1
이것은 @ ray-d가 위에서 언급 한 것과 동일하지만 잘 설명되어 있습니다. 감사합니다! 또한 docker-compose를 사용할 때 docker0 인터페이스에 도착하는 모든 패킷에 대해 PREROUTING 체인에 DNAT 규칙도 추가해야했습니다. sysctl -w net.ipv4.conf.docker0.route_localnet=1iptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd

3

당신은 게이트웨이 를 알아야합니다 ! 로컬 서버와 내 솔루션은 아래를 노출했다 0.0.0.0:8000으로, 다음 실행 고정 표시기 서브넷실행 컨테이너 와 같은 :

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

이제 루프백에 액세스 할 수 있습니다. http://172.35.0.1:8000


3

이 시도:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

얻기 위해 192.168.1.202 , 사용을ifconfig

이것은 나를 위해 일했습니다. 이 도움을 바랍니다!


2

CGroup과 네임 스페이스는 컨테이너 생태계에서 중요한 역할을합니다.

네임 스페이스는 격리 계층을 제공합니다. 각 컨테이너는 별도의 네임 스페이스에서 실행되며 해당 네임 스페이스로 액세스가 제한됩니다. Cgroup은 각 컨테이너의 리소스 사용률을 제어하는 ​​반면, 네임 스페이스는 프로세스가 각 리소스를보고 액세스 할 수있는 대상을 제어합니다.

다음은 수행 할 수있는 솔루션 접근 방식에 대한 기본 이해입니다.

네트워크 네임 스페이스 사용

컨테이너가 이미지에서 생성되면 네트워크 인터페이스가 정의되고 생성됩니다. 이는 컨테이너에 고유 한 IP 주소와 인터페이스를 제공합니다.

$ docker run -it alpine ifconfig

네임 스페이스를 호스트로 변경하면 코 테이너 네트워크는 해당 인터페이스와 격리되지 않고 프로세스는 호스트 시스템 네트워크 인터페이스에 액세스 할 수 있습니다.

$ docker run -it --net=host alpine ifconfig

프로세스가 포트에서 수신 대기하는 경우 호스트 인터페이스에서 수신 대기하고 컨테이너에 맵핑됩니다.

PID 네임 스페이스 사용 Pid 네임 스페이스 를 변경하면 컨테이너가 일반적인 범위를 벗어나 다른 프로세스와 상호 작용할 수 있습니다.

이 컨테이너는 자체 네임 스페이스에서 실행됩니다.

$ docker run -it alpine ps aux

네임 스페이스를 호스트로 변경하면 컨테이너는 시스템에서 실행중인 다른 모든 프로세스도 볼 수 있습니다.

$ docker run -it --pid=host alpine ps aux

네임 스페이스 공유

취약점으로 인해 열릴 수있는 컨테이너 보안 모델을 위반하고 도청에 쉽게 액세스 할 수 있으므로 프로덕션 환경에서이 작업을 수행하는 것은 좋지 않습니다. 이것은 도구 디버깅 및 컨테이너 보안의 허점을 과소 평가하기위한 것입니다.

첫 번째 컨테이너는 nginx 서버입니다. 새로운 네트워크 및 프로세스 네임 스페이스가 생성됩니다. 이 컨테이너는 새로 작성된 네트워크 인터페이스의 포트 80에 바인드됩니다.

$ docker run -d --name http nginx:alpine

다른 컨테이너는 이제이 네임 스페이스를 재사용 할 수 있습니다.

$ docker run --net=container:http mohan08p/curl curl -s localhost

또한이 컨테이너는 공유 컨테이너의 프로세스와의 인터페이스를 볼 수 있습니다.

$ docker run --pid=container:http alpine ps aux

이렇게하면 응용 프로그램을 변경하거나 다시 시작하지 않고도 컨테이너에 더 많은 권한을 부여 할 수 있습니다. 비슷한 방법으로 호스트에서 mysql에 연결하고 응용 프로그램을 실행하고 디버깅 할 수 있습니다. 그러나이 방법으로 이동하지 않는 것이 좋습니다. 도움이 되길 바랍니다.


1

Windows 시스템의 경우 :-

빌드하는 동안 도커 포트를 무작위로 노출하려면 아래 명령을 실행하십시오.

$docker run -d --name MyWebServer -P mediawiki

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

위의 컨테이너 목록에서 포트가 32768로 할당 된 것을 볼 수 있습니다.

localhost:32768 

미디어 위키 페이지를 볼 수 있습니다


5
이 답변은 일부 사용자에게 유용한 정보를 제공 할 수 있지만 잘못된 방법입니다 ! 컨테이너 에서 실행중인 서비스를 호스트 시스템 에서 액세스하는 것 입니다. 그러나 컨테이너 에서 호스트 에서 실행 되는 서비스에 액세스하는 것이 문제였습니다 .
einjohn

1

수정 사항master지점으로 병합되지 않을 때까지 컨테이너 내부에서 호스트 IP를 실행하십시오.

ip -4 route list match 0/0 | cut -d' ' -f3

( @Mahoney 에서 제안한대로 ).


1

컨테이너의 IP에 대해 MySQL에서 사용자를 만들어서 해결했습니다.

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

그런 다음 컨테이너에서 : jdbc:mysql://<b>172.17.0.1</b>:3306/database_name


이것이 가장 간단한 해결책입니다. 그것은 나를 위해 일했고 나는 많은 언급 한
Sopia 알프레드

-1

내가하는 방법은 호스트 IP를 환경 변수로 컨테이너에 전달하는 것입니다. 그런 다음 컨테이너는 해당 변수로 호스트에 액세스합니다.


어떻게하는지 설명해 주실 수 있습니까? 이 방법을 시도했지만 성공하지 못했습니다
kmjb

`docker run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee : / tmp # ./telnet $ HOST 22 10.145.2.123 시도 중 ... 10.145.2.123에 연결되었습니다. 이스케이프 문자는 '^]'입니다. SSH-2.0-OpenSSH_7.4`
F. Kam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.