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

时间:2014-06-20 03:54:17

标签: nginx docker reverse-proxy docker-networking

所以我在Docker容器中运行了一个Nginx,我有一个在localhost上运行的mysql,我想从我的Nginx中连接到MySql。 MySql在localhost上运行,而不是将端口暴露给外部世界,所以它绑定在localhost上,而不是绑定在机器的ip地址上。

有没有办法从这个docker容器中连接到MySql或localhost上的任何其他程序?

35 个答案:

答案 0 :(得分:1368)

修改:如果您使用的是Docker-for-macDocker-for-Windows 18.03+,请使用主机host.docker.internal连接到您的mysql服务。

从Docker 18.09.3开始,这不适用于Docker-for-Linux。 A fix已于2019年3月8日提交,希望合并到代码库。在此之前,解决方法是使用qoomon's answer中描述的容器。


TLDR

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

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


有关docker容器网络模式的注意事项

Docker在运行容器时提供different networking modes。根据您选择的模式,您将以不同方式连接到在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

所以我的docker主机在172.17.42.1网络接口上有IP地址docker0

现在启动一个新容器并在其上获取一个shell: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

因此,泊坞主机​​172.17.42.1的IP地址被设置为默认路由,可以从容器中访问。

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”

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

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

我的泊坞主机上的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.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服务器将侦听所有网络接口上的连接。这意味着可以从Internet访问您的MySQL服务器;确保相应地设置防火墙规则。

注2:如果使用bind-address = 172.17.42.1,您的MySQL服务器将不会侦听与127.0.0.1的连接。在希望连接到MySQL的docker主机上运行的进程必须使用172.17.42.1 IP地址。

主机模式

要从主机模式中的容器访问在docker主机上运行的MySQL,您可以将bind-address = 127.0.0.1保留在MySQL配置中,您只需要连接到{{1}来自你的容器:

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客户端会尝试使用unix套接字进行连接。

答案 1 :(得分:264)

对于macOS和Windows

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

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

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

适用于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

答案 2 :(得分:66)

我做了类似于以上帖子的hack,让本地IP映射到容器中的别名(DNS)。主要问题是动态使用一个简单的脚本,该脚本在 Linux和OSX主机IP地址中都有效。我做了这个在两个环境中都有效的脚本(即使在配置了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 的Linux发行版中):

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,完整配置将是:

启动脚本(docker-run.sh)

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

<强>搬运工-compose.yml

http://localhost

然后在代码中将http://dockerhost更改为DOCKERHOST

有关如何自定义{{1}}脚本的更高级指南,请查看dependent types并说明其工作原理。

答案 3 :(得分:38)

使用

host.docker.internal

代替

localhost

为我完美工作。 ?

答案 4 :(得分:34)

这对我来说非常适用于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

答案 5 :(得分:14)

对于Windows,

我已在春季配置中更改了数据库URL:spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

然后构建映像并运行。它为我工作。

答案 6 :(得分:13)

Windows 10解决方案

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

您可以使用主机docker.for.win.localhost的DNS名称来解析内部IP。 (警告某些来源提及windows,但应该是win

<强>概述
我需要做类似的事情,即从我的Docker容器连接到我的localhost,它运行Azure Storage EmulatorCosmosDB Emulator

Azure Storage Emulator默认侦听 127.0.0.1 ,同时您也可以更改其绑定的IP,我正在寻找一种可以使用默认设置的解决方案。

这也适用于从我的Docker容器连接到SQL ServerIIS,它们都在我的主机上本地运行,并具有默认端口设置。

答案 7 :(得分:12)

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

好的,您的localhost服务器具有默认的docker接口 docker0 ,其IP地址为 172.17.0.1 。您的容器以默认网络设置 - net =&#34; bridge&#34; 启动。

  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. 创建具有来自&#39;%&#39;的访问权限的mysql用户这意味着 - 来自任何人,不包括localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. 将脚本中的mysql-server地址更改为172.17.0.1

  5. 来自kernel documentation

      

    route_localnet - BOOLEAN:路由时不要将环回地址视为火星源或目的地。这样就可以使用127/8进行本地路由(默认为FALSE )。

答案 8 :(得分:10)

对于Windows上的用户,假设您正在使用网桥驱动程序,那么您需要专门将MySQL绑定到hyper-v网络接口的IP地址。

这是通过正常隐藏的C:\ ProgramData \ MySQL文件夹下的配置文件完成的。

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

答案 9 :(得分:9)

直到host.docker.internal在每种平台上都可以使用之前,您无需任何手动设置即可将我的容器用作NAT网关:

enter image description here

答案 10 :(得分:8)

编辑:我最终在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容器内运行的服务连接到Docker主机上运行的localhost服务(例如您的笔记本电脑)。

如何?

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

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

当您在容器内执行ifconfig(您需要apt-get install net-tools容器ifconfig可调用)时,您将看到网络接口与一个在Docker主机上(例如你的笔记本电脑)。

重要的是要注意我是Mac用户,但我在Parallels下运行Ubuntu,因此使用Mac并不是一个缺点。 ; - )

这就是你如何将NGINX容器连接到localhost上运行的MySQL。

答案 11 :(得分: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

答案 12 :(得分:5)

尝试一下:

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

这对我有用。希望有帮助!

答案 13 :(得分:5)

您需要了解gateway!我对本地服务器的解决方案是将其公开在0.0.0.0:8000下,然后使用子网运行容器运行docker,例如:

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

访问环回

答案 14 :(得分:4)

连接到网关地址。

const testData = [{
  location: 'FL',
  needs: [{
    date: '2021-01-01',
    count: 5
  }, {
    date: '2021-01-02',
    count: 1
  }, {
    date: '2021-01-03',
    count: 2
  }, {
    date: '2021-01-04',
    count: 23
  }, {
    date: '2021-01-05',
    count: 65
  }]
}, {
  location: 'AL',
  needs: [{
    date: '2021-01-01',
    count: 1
  }, {
    date: '2021-01-02',
    count: 2
  }, {
    date: '2021-01-03',
    count: 3
  }, {
    date: '2021-01-04',
    count: 4
  }, {
    date: '2021-01-05',
    count: 5
  }]
}]

const mapper = testData.reduce((acc, cur) => {
    cur.needs.forEach(item => {
    acc[item.date] = (acc[item.date] || 0) + item.count;
  });
  return acc;
}, {});

const dates = Object.keys(mapper);
dates.sort();
console.log(dates.map(k => mapper[k]));

确保宿主机上的进程正在监听这个接口或者所有接口,并且在docker之后启动。如果使用systemd,您可以添加以下内容以确保它在docker之后启动。

set(MY_VAR "-arch arm64 -mcpu=abc1 -c --debug -O2 -static -fstack-protector -ffreestanding -nostartfiles -std=c11")

if (MY_VAR MATCHES "^([^ ]+ +)*(-mcpu=[^ ]+)( +[^ ]+)*$")
    message(STATUS "Found match: ${CMAKE_MATCH_2}")
else()
    message(FATAL_ERROR "mismatch")
endif()

示例

❯ docker network inspect bridge | grep Gateway
                    "Gateway": "172.17.0.1"

答案 15 :(得分:4)

这是我的解决方案:它适用于我的案例

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

  • 重启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;

  • 创建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-composer

    运行

    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

答案 16 :(得分: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

答案 17 :(得分:2)

我不同意Thomasleveil的回答。

使mysql绑定到172.17.42.1将阻止使用主机上的数据库的其他程序到达它。这仅在所有数据库用户都已停靠时才有效。

将mysql绑定到0.0.0.0会将db打开到外部世界,这不仅是一件非常糟糕的事情,而且还与原作者想要做的事情相反。他明确地说“MySql在localhost上运行,而不是将端口暴露给外部世界,所以它绑定在localhost上”

回答ivant的评论

  

“为什么不将mysql绑定到docker0?”

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

作为结论,我还没有找到任何方法从docker容器到达主机上的(仅限localhost)数据库。这绝对是一种非常常见的模式,但我不知道该怎么做。

答案 18 :(得分:2)

对于Linux,您无法在其中更改localhost服务绑定到的接口

我们需要解决两个问题

  1. 获取主机的IP
  2. 使localhost服务可用于Docker

第一个问题可以使用qoomon的docker-host image来解决,如其他答案所示。

您需要将此容器与其他容器添加到同一网桥网络中,以便您可以访问它。在容器内打开一个终端,并确保可以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

现在,更棘手的问题使服务可以被docker访问。

我们可以使用telnet来检查是否可以访问主机上的端口(您可能需要安装它)。

问题在于我们的容器将只能访问绑定到所有接口的服务,例如SSH:

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

但是只能绑定到本地主机的服务将无法访问:

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

这里的正确解决方案是将服务绑定到dockers网桥。但是,此答案假定您无法更改此设置。因此,我们将改用iptables

首先,我们需要找到docker与ifconfig一起使用的桥接网络的名称。如果您使用的是未命名的网桥,则将为docker0。但是,如果您使用的是命名网络,则将有一个以br-开头的网桥,而docker将使用该网桥。我的是br-5cd80298d6f4

一旦有了该网桥的名称,就需要允许从该网桥路由到本地主机。出于安全原因,默认情况下将其禁用:

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

现在设置我们的iptables规则。由于我们的容器只能访问docker网桥网络上的端口,因此我们将假装我们的服务实际上已绑定到该网络上的端口。

为此,我们会将所有请求转发到<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

答案 19 :(得分:2)

这不是对实际问题的答案。这就是我解决类似问题的方式。该解决方案完全来自:Define Docker Container Networking so Containers can Communicate。感谢Nic Raboy

将其留给其他可能想要在一个容器与另一个容器之间进行REST调用的人使用。回答问题:在Docker环境中用什么代替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”

ssh放入第二个容器docker exec -it second_container shdocker exec -it second_container bash

在第二个容器内,您可以通过ping first_container ping第一个容器。另外,您的代码调用(例如http://localhost:5000可以替换为http://first_container:5000

答案 20 :(得分:2)

想到了几种解决方案:

  1. 首先将依赖项移至容器中
  2. 使其他服务可从外部访问,并使用该外部IP连接到它们
  3. 在没有网络隔离的情况下运行容器
  4. 避免通过网络连接,请改用作为卷安装的套接字

无法立即使用的原因是,默认情况下,容器使用其自己的网络名称空间运行。这意味着localhost(或指向回送接口的127.0.0.1)对于每个容器都是唯一的。连接到此端口将连接到容器本身,而不连接在docker外部或其他docker容器内部运行的服务。

选项1 :如果可以将您的依赖项移至容器中,那么我将首先这样做。当其他人尝试在自己的环境中运行容器时,它使您的应用程序堆栈可移植。而且,您仍然可以在主机上发布端口,其他尚未迁移的服务仍可以到达该端口。您甚至可以将端口发布到docker主机上的localhost接口,以避免使用诸如-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地址的其他方法,请see this post

选项3 :在没有网络隔离的情况下运行,即以--net host运行,意味着您的应用程序正在主机网络名称空间上运行。这对容器的隔离程度较小,这意味着您无法使用DNS通过共享的docker网络访问其他容器(相反,您需要使用已发布的端口来访问其他容器化的应用程序)。但是对于需要访问主机上仅在主机上的127.0.0.1上进行监听的主机上其他服务的应用程序,这可能是最简单的选择。

选项4 :各种服务还允许通过基于文件系统的套接字进行访问。该套接字可以作为绑定安装的卷安装到容器中,使您无需通过网络即可访问主机服务。要访问docker引擎,通常会看到将/var/run/docker.sock安装到容器中的示例(使该容器对主机具有根访问权限)。使用mysql,您可以尝试类似-v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sock之类的内容,然后连接到localhost,mysql会使用套接字将其转换为import SwiftUI struct ContentView : View { var body: some View { List { Text("This is some very long text can we can see scrolls past two lines ").lineLimit(nil) } } } #if DEBUG struct ContentView_Previews : PreviewProvider { static var previews: some View { ContentView() } } #endif

答案 21 :(得分:2)

非常简单快捷,请使用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”,以及运行数据库的主机的端口

答案 22 :(得分:2)

在Windows 10 Home上使用Docker Toolbox时,没有一个答案对我有用,但是 10.0.2.2 确实有用,因为它使用VirtualBox,该主机将主机暴露给该地址上的VM。

答案 23 :(得分:2)

对于Windows计算机:-

在构建期间运行以下命令随机暴露docker端口

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

enter image description here

enter image description here

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

localhost:32768 

您可以看到mediawiki页面

答案 24 :(得分:2)

CGroups和命名空间在集装箱生态系统中发挥着重要作用。

命名空间提供一层隔离。每个容器都在单独的命名空间中运行,其访问权限仅限于该命名空间。 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,运行和调试您的应用程序。但是,不建议这样做。希望能帮助到你。

答案 25 :(得分:1)

要使所有功能正常运行,您需要为服务器(caddy,nginx)创建一个配置,其中主域为“ docker.for.mac.localhost”。为此,在“ http://docker.for.mac.localhost/api”上的baseURL“ http:// localhost / api”中替换

docker-compose.yml

backend:
  restart: always
  image: backend
  build:
    dockerfile: backend.Dockerfile
    context: .
  environment:
    # add django setting.py os.getenv("var") to bd config and ALLOWED_HOSTS CORS_ORIGIN_WHITELIST
    DJANGO_ALLOWED_PROTOCOL: http
    DJANGO_ALLOWED_HOSTS: docker.for.mac.localhost
    POSTGRES_PASSWORD: 123456
    POSTGRES_USER: user
    POSTGRES_DB: bd_name
    WAITDB: "1"
  volumes:
    - backend_static:/app/static
    - backend_media:/app/media
  depends_on:
    - db

frontend:
  restart: always
  build:
    dockerfile: frontend.Dockerfile
    context: .
  image: frontend
  environment:
    #  replace baseURL for axios
    API_URL: http://docker.for.mac.localhost/b/api
    API_URL_BROWSER: http://docker.for.mac.localhost/b/api
    NUXT_HOST: 0.0.0.0
  depends_on:
    - backend

caddy:
  image: abiosoft/caddy
  restart: always
  volumes:
    - $HOME/.caddy:/root/.caddy
    - ./Caddyfile.local:/etc/Caddyfile
    - backend_static:/static
    - backend_media:/media
  ports:
  - 80:80
  depends_on:
    - frontend
    - backend
    - db

Caddyfile.local

http://docker.for.mac.localhost {

  proxy /b backend:5000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  proxy / frontend:3000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  root /

  log stdout
  errors stdout
  gzip
}

http://docker.for.mac.localhost/static {
  root /static
}

http://docker.for.mac.localhost/media {
  root /media
}

django settings.py

ALLOWED_HOSTS = [os.getenv("DJANGO_ALLOWED_HOSTS")]
    
CORS_ORIGIN_WHITELIST = [f'{os.getenv("DJANGO_ALLOWED_PROTOCOL")}://{os.getenv("DJANGO_ALLOWED_HOSTS")}']

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": os.getenv("POSTGRES_DB"),
        "USER": os.getenv("POSTGRES_USER"),
        "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
        "HOST": "db",
        "PORT": "5432",
    }
}

nuxt.config.js(baseURL变量将覆盖环境的API_URL)

axios: {
  baseURL: 'http://127.0.0.1:8000/b/api'
},

答案 26 :(得分:1)

请首先查看this答案,以获取解决此问题所需的选项。但是,如果您使用updateUserState = function(req,res){ var query = {_id: req.body.game_id}; var update = {$set: { users.$[thisone].ready: true }}}; var options = {'new': true, 'safe': true, 'upsert': true, arrayFilters:[{ "thisone._id":<idhere> }] } }; Game.findOneAndUpdate(query,update,options, function(err,data){ if(err)res.send(err) else res.send(data) }) } ,则可以将docker-compose添加到服务中,然后使用network_mode: host连接到本地主机。这只是上面答案中描述的选项之一。在下面,您可以找到如何从127.0.0.1修改docker-compose.yml

https://github.com/geerlingguy/php-apache-container.git

--- version: "3" services: php-apache: + network_mode: host image: geerlingguy/php-apache:latest container_name: php-apache ... 表示我添加的行。


[其他信息]这在版本+中也有效。和“主机”或仅是“主机”都在2.2中工作。

docker-compose

答案 27 :(得分:1)

主机上的服务器正在监听5000端口;它将发送一个字符串 response from host 作为响应

echo "response from host" | nc -l -p 5000

docker 默认运行在桥接模式下(这比运行在主机网络模式下更安全); docker中的进程获取主机上第一个不是127.0.0.1的网络接口的ipv4地址;这个 ipv4 地址通过环境变量 HOSTIP 传递给 docker;在 docker 里面有一个 nc 命令连接到主机 ip 和端口 5000 上的服务器;该命令还会读取服务器的响应。

HOST=$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p'); docker run -e HOSTIP="${HOST}" --rm -it alpine /bin/sh -c 'echo "greetings from container" | nc $HOSTIP 5000 -v'

计算第一个列出的接口的 ipv4 地址的表达式在 osx 和 linux 上都有效:

HOST=$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p')

为了使它更通用:您可以在另一个 docker 容器中运行服务器,如下所示:

docker run --expose 5000 -p :5000:5000 --rm -it alpine /bin/sh -c 'echo "response from host" | nc -l -p 5000'

--expose 5000 docker 容器可以接受端口 5000 上的连接

-p :5000:5000 主机端的 docker 引擎正在侦听任何接口上的 5000 端口,并将连接转发到容器网络上的 5000 端口(运行 nc)。

答案 28 :(得分:0)

直到fix未被合并到master分支中,以使主机IP仅在容器内部运行:

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

(由@Mahoney here建议)。

答案 29 :(得分:0)

我通过在MySQL中为容器的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

然后在容器上:jdbc:mysql://<b>172.17.0.1</b>:3306/database_name

答案 30 :(得分:0)

我的方法是将主机IP作为环境变量传递给容器。 然后容器通过该变量访问主机。

答案 31 :(得分:0)

如果您使用docker-compose,也许可以工作:

iptables -I INPUT ! -i eth0 -p tcp --dport 8001 -j ACCEPT

eth0是连接Internet和8081主机服务器端口的网络接口

iptables规则的最佳方法是iptables TRACE

答案 32 :(得分:0)

您只需在主机上执行ifconfig来检查您的主机IP,然后从您的容器内连接到ip,对我来说就很完美。

答案 33 :(得分:0)

尽管有很多冗长而令人困惑的答案,但有一个简短的答案。如果您的 docker 网桥网络是 172.17.0.0/16,请执行以下操作:

  1. 将您的容器绑定到 172.17.0.1,例如。 -p 172.17.0.1:8080:8080(无论您的 Docker 网桥网络中的网关是什么)
  2. 只需访问 172.17.0.1 端口 8080 例如。 curl http://172.17.0.1:8080/ 来自其他容器

答案 34 :(得分:-18)

您可以使用ngrok创建到localhost计算机的安全隧道,然后将该隧道暴露给docker容器。

ngrok可于2017年5月22日免费使用。

步骤:

1)转到ngrok

2)download ngrok客户端并按照安装说明进行操作

3)SIGN UP用于帐户,他们将提供身份验证令牌。注册是必需的,因为ngrok仅在注册后为您提供tcp端口隧道。注册无需任何费用或信用卡。

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

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

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

您可以从泊坞广告容器内登录本地计算机的root帐户!

我已经在博客上发布了有关此解决方案的详细信息here