nginx - docker连接本地mysql - 从Docker容器的内部,如何连接到本机的本地主机?




docker宿主机ip (9)

对于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

所以我有一个在Docker容器中运行的Nginx,我有一个运行在本地主机上的mysql,我想从我的Nginx中连接到MySql。 MySql在本地主机上运行,​​并且不向外界公开端口,所以它绑定在本地主机上,不绑定在机器的IP地址上。

有没有什么办法从这个码头容器内连接到这个MySql或本地主机上的任何其他程序?


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或其他Docker容器中运行的服务器正在侦听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