如何从 docker 容器中获取 docker 主机的 IP 地址
Posted
技术标签:
【中文标题】如何从 docker 容器中获取 docker 主机的 IP 地址【英文标题】:How to get the IP address of the docker host from inside a docker container 【发布时间】:2014-05-21 14:20:26 【问题描述】:正如标题所说。我需要能够检索 docker 主机的 IP 地址和从主机到容器的端口映射,并在容器内执行此操作。
【问题讨论】:
您能否详细说明您希望如何使用这些信息?您说的是“docker hosts”——您是否在多个主机上运行 Docker?一旦你的容器知道了主机的 IP 地址和端口映射,它会做什么? 将 docker 主机 IP 地址传递给 docker 容器的最简单方法,我认为您应该使用 'docker container exec' 在容器内进行调用。假设你想从busybox容器内ping主机,例如: $ IP = '8.8.8.8' && docker container busybox ping $IP ' 找出主机IP的方法,用你喜欢的。 【参考方案1】:我的解决方案:
docker run --net=host
然后在 docker 容器中:
主机名-I | awk 'print $1'
【讨论】:
【参考方案2】:docker network inspect bridge -f 'range .IPAM.Config.Gatewayend'
可以使用 docker network inspect 检索它
【讨论】:
迄今为止的最佳答案,因为它不依赖于容器中存在的任何二进制文件。【参考方案3】:更新:在 Docker for Mac 上,从 18.03 版开始,您可以使用 host.docker.internal 作为主机的 IP。见aljabear's answer。对于 Docker for Mac 的早期版本,以下答案可能仍然有用:
在 Docker for Mac 上,docker0
网桥不存在,因此此处的其他答案可能不起作用。但是,所有传出流量都通过您的父主机路由,因此只要您尝试连接到它识别为自身的 IP(并且 docker 容器不认为是自身),您就应该能够连接。例如,如果您从父计算机运行它:
ipconfig getifaddr en0
这应该会向您显示 Mac 在其当前网络上的 IP,并且您的 docker 容器也应该能够连接到该地址。如果这个 IP 地址发生变化,这当然会很痛苦,但是您可以通过在父计算机上执行类似的操作,向您的 Mac 添加一个容器认为不是其自身的自定义环回 IP:
sudo ifconfig lo0 alias 192.168.46.49
然后,您可以使用 telnet 从 docker 容器中测试连接。就我而言,我想连接到远程 xdebug 服务器:
telnet 192.168.46.49 9000
现在,当流量进入您的 Mac 时,地址为 192.168.46.49(并且所有离开容器的流量都会通过您的 Mac),您的 Mac 将假定 IP 是它自己。当您使用完这个 IP 后,您可以像这样删除环回别名:
sudo ifconfig lo0 -alias 192.168.46.49
需要注意的一点是,如果 docker 容器认为流量的目的地是它自己,它就不会将流量发送到父主机。所以如果遇到问题,请检查容器内部的环回接口:
sudo ip addr show lo
就我而言,这显示了inet 127.0.0.1/8
,这意味着我无法使用127.*
范围内的任何IP。这就是我在上面的示例中使用192.168.*
的原因。确保您使用的 IP 不会与您自己网络上的某些内容发生冲突。
【讨论】:
这个主机名的使用没有意义,因为它在 Docker for Linux 下不起作用。为什么他们不为 Linux 也添加它? 他们现在正在调查它@TheFox:github.com/docker/libnetwork/pull/2348 我的容器中不存在 telnet 命令【参考方案4】:大多数希望自动执行此操作的应用的标准最佳做法是:您不需要。相反,您让运行容器的人注入外部主机名/IP 地址作为配置,例如作为环境变量或配置文件。允许用户注入它可以为您提供最便携的设计。
为什么会这么难?因为容器将在设计上将应用程序与主机环境隔离开来。默认情况下,网络仅被命名为该容器,并且主机的详细信息受到保护,不受容器内运行的进程的影响,这些进程可能不完全受信任。
根据您的具体情况有不同的选择:
如果您的容器在主机网络中运行,那么您可以直接查看主机上的路由表以查看默认路由。来自this question,以下对我有用,例如:
ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'
在容器中显示主机网络的示例如下所示:
docker run --rm --net host busybox /bin/sh -c \
"ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'"
对于当前版本的 Docker Desktop,他们将 DNS 条目注入嵌入式 VM:
getent hosts host.docker.internal | awk 'print $1'
在 20.10 版本中,如果您使用额外选项运行容器,host.docker.internal
别名也可以在 Linux 上运行:
docker run --add-host host.docker.internal:host-gateway ...
如果您在云环境中运行,您可以从云提供商处查看元数据服务,例如AWS 一:
curl http://169.254.169.254/latest/meta-data/local-ipv4
如果您想要您的外部/互联网地址,您可以查询远程服务,例如:
curl ifconfig.co
每一个都有限制,并且只在特定场景下有效。最便携的选项仍然是使用作为配置注入的 IP 地址运行您的容器,例如这是在主机上运行较早的ip
命令并将其作为环境变量注入的选项:
export HOST_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
docker run --rm -e HOST_IP busybox printenv HOST_IP
【讨论】:
【参考方案5】:AFAIK,对于 Docker for Linux(标准发行版),主机的 IP 地址将始终为172.17.0.1
(在 docker 的主网络上,请参阅 cmets 了解更多信息) .
获取它的最简单方法是从主机通过ifconfig
(接口 docker0):
ifconfig
在 docker 内部,来自 docker 的以下命令:ip -4 route show default | cut -d" " -f3
您可以使用以下命令行在 docker 中快速运行它:
# 1. Run an ubuntu docker
# 2. Updates dependencies (quietly)
# 3. Install ip package (quietly)
# 4. Shows (nicely) the ip of the host
# 5. Removes the docker (thanks to `--rm` arg)
docker run -it --rm ubuntu:20.10 bash -c "apt-get update > /dev/null && apt-get install iproute2 -y > /dev/null && ip -4 route show default | cut -d' ' -f3"
【讨论】:
这适用于附加到docker0
默认桥接接口的容器。使用 Docker Compose 建立的容器并非如此,它不会存在于默认的桥接接口上。 docker network ls
和 docker network inspect <network_name>
可以帮助您确定 IP 将是什么。
感谢您的指示。顺便说一句,我在 linux 上,我期望 172.17.0.1,实际上我正在检查一个容器,它有 172.23.0.1。运行容器的数量是否会通过增加 ip 号来影响主机的映射方式?
@funder7 这实际上取决于您在 docker 中使用的网络。你可以使用docker network ls
访问网络,如果你没有定义任何网络,只要知道docker-compose在docker内部自动定义了虚拟网络(你也可以列出)。
@Nek 可能是我的错,我正在查看容器的内部 ip,而我的 docker0 网络接口是 172.17.0.1,无论如何我使用了现在支持 linux 的 docker.host.internal。不过谢谢你的命令,我会试试看的!【参考方案6】:
这是 Node.js 中的一个简约实现,适用于在 AWS EC2 实例 上运行主机的用户,使用前面提到的 EC2 Metadata instance
const cp = require('child_process');
const ec2 = function (callback)
const URL = 'http://169.254.169.254/latest/meta-data/local-ipv4';
// we make it silent and timeout to 1 sec
const args = [URL, '-s', '--max-time', '1'];
const opts = ;
cp.execFile('curl', args, opts, (error, stdout) =>
if (error) return callback(new Error('ec2 ip error'));
else return callback(null, stdout);
)
.on('error', (error) => callback(new Error('ec2 ip error')));
//ec2
并用作
ec2(function(err, ip)
if(err) console.log(err)
else console.log(ip);
)
【讨论】:
【参考方案7】:从 18.03 版本开始,您可以使用 host.docker.internal
作为主机的 IP。
适用于 Docker for Mac、Docker for Windows,或许也适用于其他平台。
这是针对 Mac 的 docker.for.mac.localhost
的更新,从 17.06 版开始提供,docker.for.mac.host.internal
从 17.12 版开始提供,它们可能仍可在该平台上运行。
请注意,与 Mac 和 Windows 文档中一样,这仅用于开发目的。
例如,我在主机上设置了环境变量:
MONGO_SERVER=host.docker.internal
在我的docker-compose.yml
文件中,我有这个:
version: '3'
services:
api:
build: ./api
volumes:
- ./api:/usr/src/app:ro
ports:
- "8000"
environment:
- MONGO_SERVER
command: /usr/local/bin/gunicorn -c /usr/src/app/gunicorn_config.py -w 1 -b :8000 wsgi
【讨论】:
@allanberry 不幸的是,Docker 人员不喜欢给我们提供一种独立于平台的方式来做到这一点,因为他们不喜欢使用非预期的用例(比如从 docker 容器访问本地机器上的任何服务) 我被介绍给 Docker,就像 构建一次,到处运行。 但这完全是错误的,因为您还必须始终配置主机系统。所以docker.for.mac..
毫无用处,因为在大多数情况下,您的公司中没有仅限 Linux 或 Mac 的环境。它是混合的,您有使用 Linux、Mac 和 Windows 的开发人员。这个域没有任何意义,因为在 99% 的情况下它是一个混合主机操作系统环境。我没有在 macOS 下开发容器并将其部署到 macOS 服务器。我将它部署到 Linux。这是每个人都会做的。 那么docker.for.mac..
的全部意义是什么?
host.docker.internal
does work on Docker for Windows 也是如此,至少在撰写此评论时是这样。
@joanlofe 遗憾的是,它不再起作用了。于 19.03.2 测试。
host.docker.internal
为我工作(Windows 10、WSL2 Ubuntu 20.04、Laravel Sail)【参考方案8】:
试试这个:
docker run --rm -i --net=host alpine ifconfig
【讨论】:
【参考方案9】:所以...如果您使用 Rancher 服务器运行容器,Rancher v1.6(不确定 2.0 是否有此功能)容器可以访问 http://rancher-metadata/,其中包含很多有用的信息。
可以在容器内部找到 IP 地址:
curl http://rancher-metadata/latest/self/host/agent_ip
更多详情见: https://rancher.com/docs/rancher/v1.6/en/rancher-services/metadata-service/
【讨论】:
【参考方案10】:适用于 Mac 和 Windows 的 TLDR
docker run -it --rm alpine nslookup host.docker.internal
...打印主机的IP地址...
nslookup: can't resolve '(null)': Name does not resolve
Name: host.docker.internal
Address 1: 192.168.65.2
详情
在Mac 和Windows 上,您可以使用特殊的DNS 名称host.docker.internal
。
主机有一个不断变化的 IP 地址(如果您没有网络访问权限,则没有)。从 18.03 开始,我们的建议是连接到特殊的 DNS 名称 host.docker.internal,它解析为主机使用的内部 IP 地址。这是出于开发目的,不适用于 Docker Desktop for Mac 之外的生产环境。
【讨论】:
请不要添加same answer to multiple questions。一旦您获得足够的声誉,就回答最好的一个并将其余的标记为重复。如果不是重复的,请根据问题调整帖子并标记以取消删除。【参考方案11】:我有 Ubuntu 16.03。对我来说
docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ print $3'` [image]
不工作(生成错误的 ip)
我的工作解决方案是:
docker run --add-host dockerhost:`docker network inspect --format='range .IPAM.Config.Gatewayend' bridge` [image]
【讨论】:
【参考方案12】:在 Ubuntu 上,hostname
命令可以与以下选项一起使用:
-i
, --ip-address
主机名地址
-I
, --all-ip-addresses
主机的所有地址
例如:
$ hostname -i
172.17.0.2
要分配给变量,可以使用以下单行:
IP=$(hostname -i)
【讨论】:
这将为您提供 Docker 容器的 IP 地址,而不是主机的 IP 地址【参考方案13】:我使用的解决方案是基于一个“服务器”,当它收到一个http请求时,它会返回Docker主机的外部地址。
在“服务器”上:
1) 启动 jwilder/nginx-proxy
# docker run -d -p <external server port>:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
2) 启动 ipify 容器
# docker run -e VIRTUAL_HOST=<external server name/address> --detach --name ipify osixia/ipify-api:0.1.0
现在当容器向服务器发送 http 请求时,例如
# curl http://<external server name/address>:<external server port>
ipify通过http头“X-Forwarded-For”返回Docker主机的IP地址
示例(ipify 服务器的名称为“ipify.example.com”并在端口 80 上运行,docker 主机的 IP 为 10.20.30.40):
# docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
# docker run -e VIRTUAL_HOST=ipify.example.com --detach --name ipify osixia/ipify-api:0.1.0
现在可以在容器内调用:
# curl http://ipify.example.com
10.20.30.40
【讨论】:
【参考方案14】:也许我创建的容器也很有用https://github.com/qoomon/docker-host
您可以简单地使用容器名称 dns 来访问主机系统,例如curl http://dockerhost:9200,因此无需为任何 IP 地址而烦恼。
【讨论】:
【参考方案15】:如果您想要Windows
上的真实IP
地址(不是网桥IP
)并且您有docker 18.03
(或更新的),请执行以下操作:
在镜像名称为 nginx
的主机上运行 bash(适用于 Alpine Linux distribution
):
docker run -it nginx /bin/ash
然后在容器内运行
/ # nslookup host.docker.internal
Name: host.docker.internal
Address 1: 192.168.65.2
192.168.65.2
是主机的 IP - 而不是像 spinus
接受的答案中的网桥 IP。
我在这里使用host.docker.internal:
主机有一个不断变化的 IP 地址(如果您没有网络访问权限,则没有)。从 18.03 开始,我们的建议是连接到特殊的 DNS 名称 host.docker.internal,它解析为主机使用的内部 IP 地址。这是出于开发目的,不适用于 Docker for Windows 之外的生产环境。
【讨论】:
我试过你的解决方案,似乎找不到nslookup命令 @Sergey 你的图片是基于Alpine Linux
的吗?如果没有,请检查您的特定 linux distribution
的等效项。
不,我完全使用你的命令 - docker run -it nginx /bin/ash
好的 - 如果你在 Windows 上,那么我切换到 linux containers
并且我没有使用 windows containers
。你可以通过右键单击 docker icon
并选择 Switch to Linux containers
来做到这一点。我认为这在您下载图像时可能很重要。如果您有windows container
,请检查是否删除旧的nginx
图像并再次下载它会为您提供另一个容器。如果它仍然对您不起作用 - 您可以尝试在 ash
中安装 nslookup
。
如果不能做 nslookup,就做 ping。它将显示已解析的 IP。对我来说,这个答案有效,我只是在容器内使用这个主机名(host.docker.internal
)【参考方案16】:
这是我的做法。在这种情况下,它会在 docker 映像中的 /etc/hosts 中添加一个主机条目,将 taurus-host 指向我的本地计算机 IP::
TAURUS_HOST=`ipconfig getifaddr en0`
docker run -it --rm -e MY_ENVIRONMENT='local' --add-host "taurus-host:$TAURUS_HOST" ...
然后,在 Docker 容器中,脚本可以使用主机名 taurus-host 来访问我的本地机器,该机器托管 docker 容器。
【讨论】:
【参考方案17】:在linux下你可以运行
HOST_IP=`hostname -I | awk 'print $1'`
在 macOS 中,您的主机不是 Docker 主机。 Docker 将在 VirtualBox 中安装它的主机操作系统。
HOST_IP=`docker run busybox ping -c 1 docker.for.mac.localhost | awk 'FNR==2 print $4' | sed s'/.$//'`
【讨论】:
第一个代码块将获取容器 IP 而不是主机 IP mandoc ofhostname -I
警告不要“对输出的顺序做任何假设。”【参考方案18】:
如果您在 Service Fabric 群集上运行 Windows 容器,则主机的 IP 地址可通过环境变量 Fabric_NodeIPOrFQDN
获得。 Service Fabric environment variables
【讨论】:
【参考方案19】:Docker for Mac 我想从容器连接到主机上的服务
主机有一个不断变化的 IP 地址(如果您没有网络访问权限,则没有)。从 18.03 开始,我们的建议是连接到特殊的 DNS 名称 host.docker.internal,它解析为主机使用的内部 IP 地址。
网关也可以通过 gateway.docker.internal 访问。 https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds
【讨论】:
【参考方案20】:对于那些在 AWS 中运行 Docker 的人来说,这是另一种选择。此选项避免使用 apk 添加 curl 包并节省宝贵的 7mb 空间。使用内置的 wget(整体 BusyBox 二进制文件的一部分):
wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4
【讨论】:
【参考方案21】:https://docs.docker.com/machine/install-machine/
a) $ docker-machine ip
b) 获取一台或多台机器的 IP 地址。
$ docker-machine ip host_name
$ docker-machine ip host_name1 host_name2
【讨论】:
这会检索运行 docker 容器的虚拟机的 IP,而不是运行容器的主机的 IP。 这仅适用于在 docker-machine 上运行的 docker。新的 docker for mac 不能在 docker-machine 上运行。【参考方案22】:如果你启用了docker remote API(例如通过-H
tcp://0.0.0.0:4243
)并且知道主机的主机名或IP地址,这可以通过大量的bash来完成。
在我容器的用户bashrc
内:
export hostIP=$(ip r | awk '/default/print $3')
export containerID=$(awk -F/ '/docker/print $NF;exit;' /proc/self/cgroup)
export proxyPort=$(
curl -s http://$hostIP:4243/containers/$containerID/json |
node -pe 'JSON.parse(require("fs").readFileSync("/dev/stdin").toString()).NetworkSettings.Ports["DESIRED_PORT/tcp"][0].HostPort'
)
第二行从本地 /proc/self/cgroup
文件中获取容器 ID。
第三行卷曲到主机(假设您使用 4243 作为 docker 的端口)然后使用节点解析返回的 JSON 以获取 DESIRED_PORT
。
【讨论】:
这仅适用于您使用端口转发的情况。实际上HostPort
在这里可能是有用的信息,不幸的是HostIp
可能是0.0.0.0
【参考方案23】:
对于那些在 AWS 中运行 Docker 的人,主机的 instance meta-data 仍然可以从容器内部获得。
curl http://169.254.169.254/latest/meta-data/local-ipv4
例如:
$ docker run alpine /bin/sh -c "apk update ; apk add curl ; curl -s http://169.254.169.254/latest/meta-data/local-ipv4 ; echo"
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
v3.3.1-119-gb247c0a [http://dl-cdn.alpinelinux.org/alpine/v3.3/main]
v3.3.1-59-g48b0368 [http://dl-cdn.alpinelinux.org/alpine/v3.3/community]
OK: 5855 distinct packages available
(1/4) Installing openssl (1.0.2g-r0)
(2/4) Installing ca-certificates (20160104-r2)
(3/4) Installing libssh2 (1.6.0-r1)
(4/4) Installing curl (7.47.0-r0)
Executing busybox-1.24.1-r7.trigger
Executing ca-certificates-20160104-r2.trigger
OK: 7 MiB in 15 packages
172.31.27.238
$ ifconfig eth0 | grep -oP 'inet addr:\K\S+'
172.31.27.238
【讨论】:
这对于使用 AWS 的人来说是一种超级方便的方法。我用它来配置 Consul 代理的客户端和绑定地址。当您处于无法使用主机网络的情况下(例如在 Elastic Beanstalk 和 ECS 中部署容器)时,它是理想的选择。 这是救命稻草,谢谢。我无法弄清楚如何处理我的 ECS 集群中的容器之间的通信。 在 Phusion basimage(基于 ubuntu)上,我不得不稍微改变你的命令:ifconfig eth0 | grep -oP 'inet \K\S+'
如果 docker 有这样的东西那就太棒了
对于fargate,您必须在169.254.170.2/v2/metadata的json响应中搜索“IPv4Addresses”【参考方案24】:
/sbin/ip route|awk '/default/ print $3 '
正如@MichaelNeale 所注意到的,在Dockerfile
中使用此方法没有意义(除非我们仅在构建期间需要此IP),因为此IP 将在构建期间进行硬编码。
【讨论】:
当您对容器使用 docker 网桥(默认)时,这将输出 172.17.42.1 之类的网桥 IP,而不是 192.168.1.x 之类的主机 IP(我假设您的主机位于家庭 NAT 上)。如果您想要 192.168.1.x 地址,使用@Magno Torres 答案可能是人们在这种情况下想要的。 RUN 不会像你期望的那样工作 - 它只会在构建时计算 IP - 并且在那之后将永远是静态的,并且没有用。它将是构建主机的 IP。 @Programster,我可以假设人们想要 docker 主机和容器之间的连接,这就是桥 IP 可以给你的(当然在标准的“家庭”安装中)。如果它甚至可以在 docker bridge 之外并且无法访问,为什么有人需要“真实”主机 IP?这是所有刚安装 docker 并想在短时间内使用它的人的解决方案。 @MichaelNeale,和以前一样,我认为大多数开始使用 docker 的人都需要在他们的主机和容器之间建立连接,就是这样。如果有人在做“正确”的部署,可能他并没有使用 docker bridge,他使用的是自定义网络,而且他可能知道所有的网络怪癖或者他们设置了 DNS(或任何发现)。 @spinus - 但这只有在它在构建它的主机上运行时才有效 - 在这种情况下 - 你可以硬编码它 - 或查找它 - 我认为它不是一个有用的答案,会误导很多人 - 建议您删除它。 (运行位)【参考方案25】:--add-host
可能是更简洁的解决方案(但没有端口部分,只有主机可以使用此解决方案处理)。因此,在您的 docker run
命令中,执行以下操作:
docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ print $3'` [my container]
(来自https://***.com/a/26864854/127400)
【讨论】:
当其他人想在 /etc/hosts 中添加条目时,我说“为此而生”;在这个问题上,这不是真的。 OP 还要求提供“主机和端口映射”,而您只覆盖了主机。 好的。我有点困惑,因为公认的解决方案也只涵盖主机部分。而且我认为您的解决方案优于棘突的解决方案。 如果你想使用 dind - docker-in-docker,这不起作用。内部 docker 会有不同的 ip【参考方案26】:唯一的方法是在创建容器时将主机信息作为环境传递
run --env <key>=<value>
【讨论】:
更具体地说,可以使用如下命令行选项传入网桥 IP 地址:-e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"
(使用来自unix.stackexchange.com/questions/87468/… 的接受答案)
我认为它不适用于 Docker for Mac / Windows。 (网桥IP)以上是关于如何从 docker 容器中获取 docker 主机的 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章