development

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

big-blog 2020. 9. 27. 12:59
반응형

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


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

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


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

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


TLDR

명령 --network="host"에서 사용하면 도커 컨테이너에서 도커 호스트를 가리킬 것입니다.docker run127.0.0.1

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


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

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

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

Docker docker0는 기본적으로 이름이 지정된 브리지를 생성합니다 . Docker 호스트와 Docker 컨테이너 모두 해당 브리지에 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.1IP 주소 가지고 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

따라서 Docker 호스트의 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

도커 실행 --network = "host"

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

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

내 Docker 호스트의 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 주소 에서 연결을 수신하는지 확인해야합니다 .

이렇게하려면 MySQL 구성 파일 (my.cnf)에 bind-address = 172.17.42.1또는 이 있는지 확인하십시오 bind-address = 0.0.0.0.

게이트웨이의 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 클라이언트는 유닉스 소켓을 사용하여 연결을 시도합니다.


macOS 및 Windows의 경우

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

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

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

이전 버전의 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

Docker 컨테이너에서 호스트 머신에 액세스하려면 네트워크 인터페이스에 IP 별칭을 연결해야합니다. 원하는 IP를 바인딩 할 수 있습니다. 다른 곳에 사용하고 있지 않은지 확인하십시오.

sudo ifconfig lo0 alias 123.123.123.123/24

그런 다음 서버가 위에서 언급 한 IP 또는 0.0.0.0. localhost에서 수신 중이 127.0.0.1면 연결을 수락하지 않습니다.

그런 다음 Docker 컨테이너를이 IP로 지정하면 호스트 머신에 액세스 할 수 있습니다!

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

재부팅 할 때마다 별칭이 재설정되므로 필요한 경우 시작 스크립트를 만듭니다.

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


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

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스크립트 를 사용자 정의하는 방법에 대한 고급 가이드는 작동 방법에 대한 설명과 함께이 게시물 을 참조하십시오.


이것은 앱이 연결할 수있을 것으로 기대하는 코드 나 네트워킹을 건드리지 않고 NGINX / PHP-FPM 스택에서 저에게 효과적이었습니다. localhost

mysqld.sock호스트에서 컨테이너 내부로 마운트 합니다.

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

Docker에서 예상되는 위치에 해당 파일을 마운트합니다.
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

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

좋아, localhost 서버에는 ip 주소가 172.17.0.1 인 기본 docker 인터페이스 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. localhost를 제외한 모든 사람을 의미하는 '%'에서 액세스 할 수있는 mysql 사용자를 만듭니다.
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. 스크립트에서 mysql-server 주소를 172.17.0.1로 변경하십시오.


로부터 커널 문서 :

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


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

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


Windows 10 용 솔루션

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

호스트의 DNS 이름을 사용 docker.for.win.localhost하여 내부 IP로 확인할 수 있습니다. (일부 소스가 언급 windows되었지만 반드시 있어야 함 win)

개요
비슷한 작업을 수행해야했습니다. 즉, Docker 컨테이너에서 Azure Storage EmulatorCosmosDB Emulator.

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

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


Windows 사용자의 경우 브리지 네트워크 드라이버를 사용한다고 가정하면 MySQL을 hyper-v 네트워크 인터페이스의 IP 주소에 구체적으로 바인딩 할 수 있습니다.

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

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


편집 : 결국 GitHub에서 개념을 프로토 타이핑했습니다. 확인 : https://github.com/sivabudh/system-in-a-box


첫째, 내 대답은 Mac 사용자와 Linux 사용자의 두 그룹을 대상으로합니다.

호스트 네트워크 모드는 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 컨테이너를 실행할 때 호스트 모드 로 실행해야한다는 것입니다 . 명령은 다음과 같습니다.

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

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

저는 Mac 사용자이지만 Parallels에서 Ubuntu를 실행하므로 Mac을 사용하는 것이 단점이 아닙니다. ;-)

그리고 이것이 NGINX 컨테이너를 localhost.


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을 사용할 수 있습니다.


매우 간단하고 빠르게 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가 실행중인 호스트의 포트를 사용해야합니다.


나는 Thomasleveil의 대답에 동의하지 않습니다.

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

mysql을 0.0.0.0으로 바인드하면 db가 외부 세계에 열리게되는데, 이는 매우 나쁜 일일뿐만 아니라 원래 질문 작성자가 원하는 작업과 반대입니다. 그는 "MySql은 localhost에서 실행 중이며 포트를 외부 세계에 노출하지 않으므로 localhost에 바인딩되어 있습니다."라고 명시 적으로 말합니다.

ivant의 의견에 대답하려면

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

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

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


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

  • #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 global dev 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 = 루트 \
                  sopheamak / springboot_docker_mysql

  
  • docker-composer로 실행

    버전 : '2.1'

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


Windows 10 Home에서 Docker Toolbox를 사용할 때 어떤 답변도 효과가 없었지만 10.0.2.2 는 호스트를이 주소의 VM에 노출하는 VirtualBox를 사용하기 때문에 작동했습니다.


몇 가지 해결책이 떠 오릅니다.

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

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

Option 1: If your dependency can be moved into a container, I would do this first. It makes your application stack portable as others try to run your container on their own environment. And you can still publish the port on your host where other services that have not been migrated can still reach it. You can even publish the port to the localhost interface on your docker host to avoid it being externally accessible with a syntax like: -p 127.0.0.1:3306:3306 for the published port.

Option 2: There are a variety of ways to detect the host IP address from inside of the container, but each have a limited number of scenarios where they work (e.g. requiring Docker for Mac). The most portable option is to inject your host IP into the container with something like an environment variable or configuration file, e.g.:

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

This does require that your service is listening on that external interface, which could be a security concern. For other methods to get the host IP address from inside of the container, see this post.

Option 3: Running without network isolation, i.e. running with --net host, means your application is running on the host network namespace. This is less isolation for the container, and it means you cannot access other containers over a shared docker network with DNS (instead, you need to use published ports to access other containerized applications). But for applications that need to access other services on the host that are only listening on 127.0.0.1 on the host, this can be the easiest option.

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


이것은 실제 질문에 대한 답이 아닙니다. 이것이 비슷한 문제를 해결 한 방법입니다. 솔루션은 전적으로 컨테이너가 통신 할 수 있도록 Docker 컨테이너 네트워킹을 정의 합니다. Nic Raboy 덕분에

Leaving this here for others who might want to do REST calls between one container and another. Answers the question: what to use in place of localhost in a docker environment?

Get how your network looks like docker network ls

Create a new network docker network create -d my-net

Start the first container docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Check out network settings for first container docker inspect first_container. "Networks": should have 'my-net'

Start the second container docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Check out network settings for second container docker inspect second_container. "Networks": should have 'my-net'

ssh into your second container docker exec -it second_container sh or docker exec -it second_container bash.

Inside of the second container, you can ping the first container by ping first_container. Also, your code calls such as http://localhost:5000 can be replaced by http://first_container:5000


You can get the host ip using alpine image

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

This would be more consistent as you're always using alpine to run the command.

Similar to Mariano's answer you can use same command to set an environment variable

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

The CGroups and Namespaces are playing major role in the Container Ecosystem.

Namespace provide a layer of isolation. Each container runs in a separate namespace and its access is limited to that namespace. The Cgroups controls the resource utilization of each container, whereas Namespace controls what a process can see and access the respective resource.

Here is the basic understanding of the solution approach you could follow,

Use Network Namespace

When a container spawns out of image, a network interface is defined and create. This gives the container unique IP address and interface.

$ docker run -it alpine ifconfig

By changing the namespace to host, cotainers networks does not remain isolated to its interface, the process will have access to host machines network interface.

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

If the process listens on ports, they'll be listened on the host interface and mapped to the container.

Use PID Namespace By changing the Pid namespace allows a container to interact with other process beyond its normal scope.

This container will run in its own namespace.

$ docker run -it alpine ps aux

By changing the namespace to the host, the container can also see all the other processes running on the system.

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

Sharing Namespace

This is a bad practice to do this in production because you are breaking out of the container security model which might open up for vulnerabilities, and easy access to eavesdropper. This is only for debugging tools and understating the loopholes in container security.

The first container is nginx server. This will create a new network and process namespace. This container will bind itself to port 80 of newly created network interface.

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

Another container can now reuse this namespace,

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

Also, this container can see the interface with the processes in a shared container.

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

This will allow you give more privileges to containers without changing or restarting the application. In the similar way you can connect to mysql on host, run and debug your application. But, its not recommend to go by this way. Hope it helps.


For Windows Machine :-

Run the below command to Expose docker port randomly during build time

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

enter image description here

enter image description here

In the above container list you can see the port assigned as 32768. Try accessing

localhost:32768 

You can see the mediawiki page


For Linux, where you cannot change the interface the localhost service binds to

There are two problems we need to solve

  1. Getting the IP of the host
  2. Making our localhost service available to Docker

The first problem can be solved using qoomon's docker-host image, as given by other answers.

You will need to add this container to the same bridge network as your other container so that you can access it. Open a terminal inside your container and ensure that you can ping 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

Now, the harder problem, making the service accessible to docker.

We can use telnet to check if we can access a port on the host (you may need to install this).

The problem is that our container will only be able to access services that bind to all interfaces, such as SSH:

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

But services bound only to localhost will be inaccessible:

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

The proper solution here would be to bind the service to dockers bridge network. However, this answer assumes that it is not possible for you to change this. So we will instead use iptables.

First, we need to find the name of the bridge network that docker is using with ifconfig. If you are using an unnamed bridge, this will just be docker0. However, if you are using a named network you will have a bridge starting with br- that docker will be using instead. Mine is br-5cd80298d6f4.

Once we have the name of this bridge, we need to allow routing from this bridge to localhost. This is disabled by default for security reasons:

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

Now to set up our iptables rule. Since our container can only access ports on the docker bridge network, we are going to pretend that our service is actually bound to a port on this network.

To do this, we will forward all requests to <docker_bridge>:port to localhost: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>

For example, for my service on port 1025

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

You should now be able to access your service from the container:

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

Until fix is not merged into master branch, to get host IP just run from inside of the container:

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

(as suggested by @Mahoney here).


I solved it by creating a user in MySQL for the container's ip:

$ 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

Then on container: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name

참고URL : https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach

반응형