nginx - run - 從Docker容器的內部,如何連接到本機的本地主機?




docker網路設定 (9)

所以我有一個在Docker容器中運行的Nginx,我有一個運行在本地主機上的mysql,我想從我的Nginx中連接到MySql。 MySql在本地主機上運行,並且不向外界公開端口,所以它綁定在本地主機上,不綁定在機器的IP地址上。

有沒有什麼辦法從這個碼頭容器內連接到這個MySql或本地主機上的任何其他程序?


對於macOS和Windows

Docker v 18.03及以上版本(自2018年3月21日起)

使用您的內部IP地址或連接到將解析為主機使用的內部IP地址的特殊DNS名稱host.docker.internal

Linux支持掛起https://github.com/docker/for-linux/issues/264

MacOS與早期版本的Docker

Docker for Mac v 17.12至v 18.02

同上,但使用docker.for.mac.host.internal代替。

Docker for Mac v 17.06至v 17.11

同上,但使用docker.for.mac.localhost代替。

Docker for Mac 17.05及以下版本

要從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 : https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


Linux解決方案(內核> = 3.6)。

好的,你的localhost服務器有默認的docker接口docker0 ,IP地址為172.17.0.1 。 您的容器以默認網絡設置啟動--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 )。


最簡單的Mac OSX解決方案

只需使用您的Mac的IP地址。 在Mac上運行這個來獲取IP地址並從容器中使用它:

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

只要在Mac上或其他碼頭容器中本地運行的服務器正在偵聽0.0.0.0,Docker容器就能夠在該地址處聯繫。

如果您只想訪問正在偵聽0.0.0.0的另一個Docker容器,則可以使用172.17.0.1


編輯:如果您使用Docker-for-macDocker-for-Windows 18.03+,只需使用host.docker.internal連接到您的mysql服務。

從Docker 18.04開始,這在Docker-for-Linux上不起作用。

TLDR

在你的--net="host" docker run命令中使用--net="host" ,然後--net="host"容器中的127.0.0.1將指向你的docker主機。

碼頭集裝箱聯網模式的注意事項

Docker在運行容器時提供了不同的聯網模式 。 根據您選擇的模式,您將不同地連接到在Docker主機上運行的MySQL數據庫。

碼頭運行--net =“bridge”(默認)

默認情況下,Docker會創建一個名為docker0的網橋。 碼頭主機和碼頭集裝箱在該橋上都有一個IP地址。

在Docker主機上,鍵入sudo ip addr show docker0您將看到如下輸出:

[[email protected]:~] $ 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

所以這裡我的碼頭主機在docker0網絡接口上有IP地址172.17.42.1

現在啟動一個新的容器並獲得一個shell: docker run --rm -it ubuntu:trusty bash並且在容器類型中使用ip addr show eth0來發現它的主網絡接口是如何設置的:

[email protected]:/# 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 。 現在看看路由表:

[email protected]:/# 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

因此,碼頭主機172.17.42.1的IP地址被設置為默認路由,並可從您的容器訪問。

[email protected]:/# 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

碼頭運行--net =“主機”

或者,您可以運行網絡設置設置為host的碼頭工具容器。 這樣的容器將與碼頭主機共享網絡堆棧,並且從容器的角度來看, localhost (或127.0.0.1 )將引用碼頭主機。

請注意,docker容器中打開的任何端口都將在docker主機上打開。 這不需要-p-P docker run選項

我的碼頭主機上的IP配置:

[[email protected]:~] $ 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

並從主機模式下的Docker容器中獲取:

[[email protected]:~] $ docker run --rm -it --net=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

如您所見,docker主機和docker容器共享完全相同的網絡接口,並且因此具有相同的IP地址。

從容器連接到MySQL

橋接模式

要以橋模式訪問在容器主機上運行的MySQL,您需要確保MySQL服務正在偵聽172.17.42.1 IP地址上的連接。

為此,請確保您的MySQL配置文件(my.cnf)中的bind-address = 172.17.42.1bind-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服務器可以通過Internet訪問; 確保相應地設置防火牆規則。

注2:如果您使用bind-address = 172.17.42.1您的MySQL服務器將不會偵聽與127.0.0.1連接。 在想要連接到MySQL的172.17.42.1主機上運行的進程必須使用172.17.42.1 IP地址。

主機模式

要從主機模式的容器中訪問在docker主機上運行的MySQL,可以在您的MySQL配置中保留bind-address = 127.0.0.1 ,並且您只需從容器連接到127.0.0.1

[[email protected]:~] $ docker run --rm -it --net=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客戶端會嘗試使用unix套接字進行連接。


針對Windows 10的解決方案

Docker Community Edition 17.06.0-ce-win18 2017-06-28(stable)

您可以使用主機docker.for.win.localhost DNS名稱解析為內部IP。 (警告一些消息來源提到的windows但它應該是win

概觀
我需要做類似的事情,即從我的Docker容器連接到運行Azure Storage EmulatorCosmosDB Emulator本地主機。

默認情況下, Azure Storage Emulator127.0.0.1上偵聽,而您也可以更改IP的綁定,我正在尋找可以使用默認設置的解決方案。

這也適用於從我的Docker容器連接到SQL ServerIIS ,兩者都在我的主機上本地運行。


對於那些在Windows上的用戶,假設您使用橋接網絡驅動程序,您需要將MySQL專門綁定到hyper-v網絡接口的IP地址。

這是通過通常隱藏的C:\ ProgramData \ MySQL文件夾下的配置文件完成的。

綁定到0.0.0.0將不起作用。 所需的地址也顯示在docker配置中,在我的情況下是10.0.75.1。


我不同意Thomasleveil的回答。

將mysql綁定到172.17.42.1將阻止其他程序使用主機上的數據庫來訪問它。 這只適用於所有數據庫用戶都被docker化的情況。

將mysql綁定到0.0.0.0會將數據庫打開到外部世界,這不僅是一件非常糟糕的事情,而且與作者想要做的原始問題相反。 他明確地說:“MySql在本地主機上運行,不會將端口暴露給外部世界,所以它綁定在本地主機上”

回答ivant的評論

“為什麼不把mysql綁定到docker0呢?”

這不可能。 mysql / mariadb文檔明確指出不可能綁定到多個接口。 您只能綁定到0,1或全部接口。

作為一個結論,我沒有找到任何方法從docker容器到達主機上的(僅限localhost)數據庫。 這絕對是一種非常普遍的模式,但我不知道該怎麼做。


我做了一個類似於上面的獲取本地IP地址映射到容器中的別名(DNS)的黑客入侵。 主要的問題是通過一個簡單的腳本動態獲得,這個腳本可以在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://dockerhost http://localhost更改為http://dockerhost

有關如何自定義DOCKERHOST腳本的更多高級指南,請查看本文並解釋其工作原理。


這是我的解決方案:它適用於我的情況

  • 通過/etc/mysql/mysql.conf.d中的註釋#bind-address = 127.0.0.1將本地mysql服務器設置為公共訪問

  • 重啟mysql服務器sudo /etc/init.d/mysql restart

  • 運行以下命令以打開用戶root訪問任何主機mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES; 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}' | cut -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=demo \
                  -e DATABASE_USER=root \
                  -e DATABASE_PASSWORD=root \
                  sopheamak/springboot_docker_mysql

  
  • 與碼頭作曲家一起運行

    version: '2.1'
    
    

    services:
    tomcatwar: extra_hosts: - "local:10.1.2.232" image: sopheamak/springboot_docker_mysql
    ports: - 8080:8080 environment: - DATABASE_HOST=local - DATABASE_USER=root - DATABASE_PASSWORD=root - DATABASE_NAME=demo - DATABASE_PORT=3306





docker-networking