Py学习  »  docker

如何在docker container proxy_pass中配置nginx来自行托管它?[复制品]

pvd • 4 年前 • 1317 次点击  

所以我有一个nginx在docker容器中运行,有一个mysql在本地主机上运行,我想从nginx中连接到mysql。mysql在localhost上运行,并且没有向外部世界公开端口,因此它在localhost上绑定,而不是在机器的ip地址上绑定。

有没有办法从这个docker容器连接到本地主机上的mysql或其他程序?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/43192
 
1317 次点击  
文章 [ 19 ]  |  最新文章 4 年前
Stephens
Reply   •   1 楼
Stephens    6 年前

你可以使用 ngrok 创建到本地主机的安全隧道,然后将该隧道公开到Docker容器。

NgRok自2017年5月22日起免费使用。

步骤:

1)去 恩格罗克

2) download ngrok客户端并遵循安装说明

3) SIGN UP 对于帐户,它们将提供身份验证令牌。需要注册,因为ngrok只在注册后提供tcp端口隧道。报名不需要任何费用或信用卡。

4)在您的终端 ngrok tcp 3306 . 3306 是mysql在本地运行的端口,您也可以使用任何其他端口。

5)您将从步骤接收地址 4 例如: tcp://0.tcp.ngrok.io:10117 . 这是到本地计算机的隧道连接。 0.tcp.ngrok.io 被映射到 localhost 港口 10117 映射到本地端口 三千三百零六 . 现在您可以使用这个地址从任何地方访问本地主机端口3306,包括在这台机器上运行的任何Docker容器。在Docker容器(无论它在哪里)中,假设已经安装了MySQL客户端,请执行以下操作:

mysql --host 0.tcp.ngrok.io --port 10117 -u root

您将能够登录到 root 从Docker容器中获取本地计算机的帐户!

我在博客上讨论过这个解决方案,请查看更多详细信息 here

patryk.beza
Reply   •   2 楼
patryk.beza    5 年前

直到 fix 未合并到 master 分支,要获取主机IP,只需从容器内部运行:

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

(根据建议 @Mahoney here )

Felipe Toledo
Reply   •   3 楼
Felipe Toledo    5 年前

非常简单快速,用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>"

这样,您的容器将能够访问您的主机。访问数据库时,请记住使用之前指定的名称,在本例中为“dockerhost”,以及运行数据库的主机端口

Elad
Reply   •   4 楼
Elad    5 年前

在Windows 10 Home上使用Docker工具箱时,没有一个答案对我有效,但是 100.2.2 是的,因为它使用了virtualbox,它向这个地址上的vm公开主机。

Lokesh S
Reply   •   5 楼
Lokesh S    5 年前

对于Windows计算机:

运行下面的命令在构建期间随机公开docker端口

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

enter image description here

enter image description here

在上面的容器列表中,您可以看到指定为32768的端口。尝试访问

localhost:32768 

您可以看到mediawiki页面

mohan08p
Reply   •   6 楼
mohan08p    6 年前

cgroup和命名空间在容器生态系统中扮演着重要角色。

命名空间提供了一个隔离层。每个容器在一个单独的命名空间中运行,其访问权限仅限于该命名空间。cgroup控制每个容器的资源利用率,而namespace控制进程可以看到和访问相应资源的内容。

以下是您对解决方案方法的基本理解,

使用网络命名空间

当容器从映像中派生时,将定义并创建网络接口。这将为容器提供唯一的IP地址和接口。

$ docker run -it alpine ifconfig

通过将名称空间更改为主机,cotainers网络不会与其接口保持隔离,进程将可以访问主机网络接口。

$ 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,运行并调试您的应用程序。但是,不建议这样走。希望有帮助。

Bruno Bieri
Reply   •   7 楼
Bruno Bieri    7 年前

我不同意汤马斯莱维尔的回答。

将mysql绑定到172.17.42.1将阻止其他程序使用主机上的数据库访问它。只有当所有数据库用户都已停靠时,此操作才有效。

将mysql绑定到0.0.0.0将使数据库对外开放,这不仅是一件非常糟糕的事情,而且与原问题作者想要做的相反。他明确表示“mysql运行在localhost上,没有向外界公开端口,所以它绑定在localhost上”

回答伊万特的评论

“为什么不把mysql也绑定到docker0呢?”

这是不可能的。mysql/mariadb文档明确表示不可能绑定到多个接口。只能绑定到0、1或所有接口。

最后,我没有找到任何方法从Docker容器访问主机上的(仅限本地主机)数据库。这显然是一个非常常见的模式,但我不知道怎么做。

hasnat
Reply   •   8 楼
hasnat    5 年前

您可以使用alpine映像获取主机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
sopheamak
Reply   •   9 楼
sopheamak    6 年前

这是我的解决方案:对我的案子有效

  • 通过注释将本地mysql服务器设置为公共访问 #bind-address = 127.0.0.1 在/etc/mysql/mysql.conf.d中

  • 重新启动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}' | 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

  
  • 与Docker作曲家一起运行

    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

dansalmo
Reply   •   10 楼
dansalmo    6 年前

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

qoomon
Reply   •   11 楼
qoomon    5 年前

在host.docker.internal为每个平台工作之前,您可以使用我的容器作为NAT网关,而无需任何手动设置 https://github.com/qoomon/docker-host

Community Benjamin Gruenbaum
Reply   •   12 楼
Community Benjamin Gruenbaum    6 年前

编辑:我最终在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的人(我的直接经验是使用Ubuntu14.04LTS,我很快就要升级到16.04LTS了)。 ,您可以将在Docker容器中运行的服务连接到 localhost 在Docker主机上运行的服务(如您的笔记本电脑)。

怎么用?

关键是运行Docker容器时,必须使用 主办 模式。命令如下所示:

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

当你做一个 ifconfig (你需要 apt-get install net-tools 你的集装箱 命令 在你的容器中,你会看到网络接口和Docker主机上的一样(比如你的笔记本电脑)。

需要注意的是,我是一个mac用户,但是我在parallels下运行ubuntu,所以使用mac并不是一个缺点。;-)

这就是如何将nginx容器连接到运行在 本地服务器 .

Casey
Reply   •   13 楼
Casey    7 年前

对于windows上的用户,假设您使用的是网桥网络驱动程序,则需要将mysql明确绑定到hyper-v网络接口的ip地址。

这是通过通常隐藏的c:\ programdata\mysql文件夹下的配置文件完成的。

绑定到0.0.0.0将不起作用。所需的地址也显示在docker配置中,在我的例子中是10.0.75.1。

Ralph Willgoss
Reply   •   14 楼
Ralph Willgoss    5 年前

Windows 10解决方案

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

您可以使用主机的dns名称 docker.for.win.localhost ,以解析为内部IP。(警告提到的一些消息来源 windows 但应该是 win )

概述
我需要做一些类似的事情,从Docker容器连接到本地主机,它运行 Azure Storage Emulator CosmosDB Emulator .

这个 azure存储仿真程序 默认情况下侦听 127.0.0.1 ,虽然您也可以更改IP的绑定,但我正在寻找一个可以使用默认设置的解决方案。

这也适用于从Docker容器连接到 SQL Server IIS ,两者都以默认端口设置在主机上本地运行。

Ray D
Reply   •   15 楼
Ray D    6 年前

Linux解决方案(内核=3.6)。

好的,你的本地主机服务器有默认的Docker接口 道克尔0 带IP地址 172.170.1 . 容器以默认网络设置启动 --net=“桥” .

  1. 为Docker0接口启用Route\u 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服务器地址更改为172.17.0.1


kernel documentation :

路由本地网 -布尔值:路由时不要将环回地址视为火星源或目标。这允许使用127/8进行本地路由( 默认为False )

d-_-b
Reply   •   16 楼
d-_-b    5 年前

这对我来说在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
Marco Altran Mariano Ruiz
Reply   •   17 楼
Marco Altran Mariano Ruiz    6 年前

我做了一个类似于上面文章的黑客攻击,让本地IP映射到容器中的别名(DNS)。主要问题是动态地使用一个简单的脚本,该脚本在 Linux和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://localhost http://dockerhost 在你的密码里。

有关如何自定义 DOCKERHOST 剧本,看看 this post 并解释它是如何工作的。

Janne Annala
Reply   •   18 楼
Janne Annala    6 年前

适用于MacOS和Windows

Docker V 18.03及以上(自2018年3月21日起)

使用您的内部IP地址或连接到特殊的DNS名称 host.docker.internal 它将解析为主机使用的内部IP地址。

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

带有早期版本Docker的MacOS

Mac V 17.12至V 18.02的Docker

同上,但使用 docker.for.mac.host.internal 相反。

Mac V 17.06至V 17.11的Docker

同上,但使用 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 . 如果它在本地主机上监听 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

Thomasleveil
Reply   •   19 楼
Thomasleveil    5 年前

编辑: 如果你正在使用 Docker-for-mac Docker-for-Windows 18.03+,只需使用主机连接到mysql服务 host.docker.internal .

从Docker 18.09.3开始,这在Docker for Linux上不起作用。 fix 已于2019年3月8日提交,有望合并到代码库中。在此之前,解决方法是使用容器,如 qoomon's answer .


TLDR

使用 --network="host" 在你 docker run 命令,然后 127.0.0.1 在Docker容器中将指向Docker主机。

注意:此模式仅适用于Docker for Linux, per the documentation .


关于Docker容器联网模式的说明

Docker提供 different networking modes 当运行容器时。根据您选择的模式,您将以不同的方式连接到Docker主机上运行的MySQL数据库。

docker run--network=“桥”(默认)

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

所以我的Docker主机有IP地址 172.17.42.1 道克尔0 网络接口。

现在,启动一个新容器并在上面放置一个外壳: 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.1742.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=“主机”

或者,您可以使用 network settings set to host . 这样的容器将与Docker主机共享网络堆栈,从容器的角度来看, localhost (或 127.0.0.1 )将引用Docker主机。

请注意,在Docker容器中打开的任何端口都将在Docker主机上打开。而这不需要 -p or -P docker run option .

我的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

如你所见,Docker主机和Docker容器共享完全相同的网络接口,因此具有相同的IP地址。


从容器连接到mysql

桥式模式

从中的容器访问Docker主机上运行的MySQL 桥式模式 ,您需要确保mysql服务正在监听 172.1742.1 IP地址。

为此,请确保 bind-address = 172.17.42.1 bind-address = 0.0.0.0 在mysql配置文件(my.cnf)中。

如果需要使用网关的IP地址设置环境变量,可以在容器中运行以下代码:

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

然后在应用程序中,使用 DOCKER_HOST_IP 打开到MySQL的连接的环境变量。

注: 如果你使用 绑定地址=0.0.0.0 mysql服务器将监听所有网络接口上的连接。这意味着可以从Internet访问MySQL服务器;请确保相应地设置防火墙规则。

附注2: 如果你使用 绑定地址=172.17.42.1 你的mysql服务器不会监听连接到 127.0.0.1 . 在Docker主机上运行的进程要连接到MySQL,必须使用 172.1742.1 IP地址。

宿主模式

从中的容器访问Docker主机上运行的MySQL 宿主模式 ,你可以保留 bind-address = 127.0.0.1 在mysql配置中,您只需要连接到 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客户端将尝试使用unix套接字进行连接。