如何从Docker容器内部获取Docker主机的IP地址


358

如标题所示。我需要能够检索Docker主机的IP地址和从主机到容器的端口映射,并在容器内部进行操作。


您能否详细说明如何使用此信息?您说“ Docker主机”-您是否在多个主机上运行Docker?容器知道主机和端口映射的IP地址后,它将做什么?
安迪

将docker主机IP地址传递到docker容器的最简单方法是,我认为您应该使用“ docker container exec”在容器内进行调用。假设您要从busybox容器内部ping主机,请使用:$ IP ='8.8.8.8'&& docker container busybox ping $ IP'查找主机IP的方法,请使用更多您喜欢的主机。
索洛亚历山德雷

Answers:


314
/sbin/ip route|awk '/default/ { print $3 }'

正如@MichaelNeale注意到的那样,没有必要使用此方法Dockerfile(除非仅在构建时需要此IP),因为此IP将在构建时进行硬编码。


49
当您对容器使用docker网桥(默认)时,这将输出网桥IP(如172.17.42.1),而不是主机的IP(如192.168.1.x)(我假设您的主机位于本地NAT上)。如果您需要192.168.1.x地址,在这种情况下使用@Magno Torres答案可能是人们想要的。
Programster

2
RUN将无法按您预期的那样工作-它只会在构建时计算IP-此后将永远是静态的,并且没有用。这将是构建主机的IP。
Michael Neale'3

7
@Programster,我可以假设人们想要docker主机和容器之间的连接,这就是网桥IP可以为您提供的(当然是在stndard“ home”安装中)。如果有人甚至可以在docker bridge之外并且无法访问,为什么有人需要“真实的”主机IP?这是所有刚安装docker并希望在短时间内使用它的人的解决方案。
脊髓2015年

1
@MichaelNeale,像以前一样,我假设大多数以Docker开头的人都需要主机和容器之间的连接,就是这样。如果有人在进行“适当的”部署,可能无论如何他都没有使用docker bridge,而是在使用自定义网络,并且可能他知道所有网络怪癖,或者他们已经设置了DNS(或任何发现)。
脊髓2015年

1
@spinus-但这仅在它在其构建的主机上运行时才有效-在那种情况下-您可以对其进行硬编码-或查找-我认为这不是有用的答案,并且会误导很多人人-建议您将其删除。(RUN位)
Michael Neale

182

从版本18.03开始,您可以host.docker.internal用作主机的IP。

工程在码头工人的Mac多克尔用于Windows,也许其他平台以及。

这是Mac特定docker.for.mac.localhost版本的更新,自版本17.06起提供,并且docker.for.mac.host.internal自版本17.12起提供,也可以在该平台上使用。

请注意,与MacWindows文档中一样,这仅用于开发目的。

例如,我在主机上设置了环境变量:

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

2
@allanberry不幸的是,Docker人们更愿意不给我们提供独立于平台的方式来执行此操作,因为他们不愿意接受意想不到的用例(例如从Docker容器访问本地计算机上的任何服务)
Andy

21
我像构建它一样被介绍给Docker ,可以在任何地方运行它。但这是完全错误的,因为您还必须同时配置主机系统。这docker.for.mac..是没有用的,因为在大多数情况下,您公司中没有仅Linux或Mac的环境。混合使用,您有使用Linux,Mac和Windows的开发人员。该域没有意义,因为在99%的环境中,它是一个混合的Host OS环境。我不会在macOS下开发容器并将其部署到macOS服务器。我将其部署到Linux。这就是每个人都在做的。那么,整个意义docker.for.mac..何在?
TheFox

1
@allanberry docker.for.mac.host.internal不管是否使用Docker都无关紧要docker-compose。我想在配置文件中使用固定主机。例如IDK,docker.host.internal始终指向主机IP地址。不管我使用哪个主机系统。这就是使用Docker的全部要点:我想自治。我知道这在macOS上更加棘手,因为主机系统和容器之间还有另一层。但是无论如何,docker.for.mac.host.internal如果您只能将其用于macOS ,我认为这是没有用的。
TheFox

1
host.docker.internal 至少在撰写此评论时,它也适用于Windows的Docker
joanlofe

1
这非常完美,我在其中一个容器中有用于Windows的dockerCe和运行的jenkins。我想在jenkins中运行docker命令,但docker无法在添加云步骤时进行连接,我使用了tcp://host.docker.internal:2375并启用了“在localhost:2375上公开守护程序”,它可以工作。节省了很多时间。谢谢!
维卡什(Vikash)

84

更新:在Mac的Docker(版本18.03)上,您可以使用host.docker.internal作为主机的IP。请参阅allanberry的答案。对于Docker for Mac的早期版本,以下答案可能仍然有用:

在适用于Mac的Docker上,docker0该桥不存在,因此此处的其他答案可能不起作用。但是,所有传出流量都通过父主机进行路由,因此,只要您尝试连接到它可以识别为自身的IP(并且Docker容器认为它本身不是),您就应该能够连接。例如,如果从父计算机运行此命令,请执行以下操作:

ipconfig getifaddr en0

这应该向您显示Mac在其当前网络上的IP,并且您的Docker容器也应该能够连接到该地址。如果此IP地址发生更改,这当然很痛苦,但是您可以通过在父计算机上执行以下操作,将自定义的回送IP添加到Mac上,使容器认为容器本身不是它自己:

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。使用完该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与您自己网络中的IP不冲突。


系统重启后会清除这些回送设置吗?
Robbo_UK

@Robbo_UK是的,重新启动Mac后,回送别名将消失。
指挥官

1
使用此主机名没有任何意义,因为它在Linux的Docker下不起作用。他们为什么不为Linux也添加它?
TheFox

他们现在正在调查@TheFox:github.com/docker/libnetwork/pull/2348
Ivo Pereira

46

对于在AWS中运行Docker的用户,仍可以从容器内部获得主机的实例元数据

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+'
Meuoi


22

--add-host可能是更干净的解决方案(但如果没有端口部分,则只能使用此解决方案来处理主机)。因此,在您的docker run命令中,执行以下操作:

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [my container]

(来自https://stackoverflow.com/a/26864854/127400


当其他人想要在/ etc / hosts中输入条目时,我说“为此”。在这个问题上,这不是真的。OP还要求提供“主机和端口图”,而您仅介绍了主机。
Bryan 2015年

好。我有点困惑,因为可接受的解决方案也只涵盖主机部分。而且我认为您的解决方案优于棘突之一。
Augunrik

如果您想使用dind-docker-in-docker,这将不起作用。内部docker的IP地址将有所不同
嘈杂的

12

对于大多数希望自动执行此操作的应用程序,标准的最佳做法是:不这样做。相反,让运行容器的人员注入外部主机名/ IP地址作为配置,例如作为环境变量或配置文件。允许用户注入它可以为您提供最便携的设计。

为什么这会这么困难?因为容器将通过设计将应用程序与主机环境隔离。默认情况下,网络仅将名称空间指定为该容器,并且主机的详细信息受到保护,以防止容器中运行的进程可能无法完全信任该进程。


根据您的具体情况,有不同的选择:

如果您的容器通过主机网络运行,则可以直接查看主机上的路由表以查看默认路由。根据这个问题,以下对我有用:

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}'

如果您在云环境中运行,则可以从云提供商(例如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

真的很有帮助的curl ifconfig.co命令..谢谢:)
MadAboutProgramming

8

如果您要使用真实IP地址(而不是bridge IP),Windows并且您有docker 18.03(或更新的),请执行以下操作:

从主机那里映像名称是在容器中运行bash的nginx(对作品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地址正在更改(如果没有网络访问权限,则没有IP地址)。从18.03开始,我们的建议是连接到特殊的DNS名称host.docker.internal,它将解析为主机使用的内部IP地址。这是出于开发目的,不适用于Docker for Windows之外的生产环境。


2
我尝试了您的解决方案,但似乎找不到nslookup命令
Sergey

@Sergey您的图片基于Alpine Linux吗?如果不是,则检查与您的具体情况相同的项目linux distribution
卡米尔·维特科夫斯基

不,我完全使用您的命令-docker run -it nginx / bin / ash
Sergey

好的-如果您在Windows上,则我切换到了linux containers我而不在使用windows containers。可以通过右键单击,docker icon然后选择来执行此操作Switch to Linux containers。我认为这在下载图像时可能很重要。如果您windows container检查是否删除了旧nginx图像并再次下载,将为您提供另一个容器。如果它对您仍然不起作用-那么您可以尝试安装nslookupash
卡米尔·维特科夫斯基

如果您无法执行nslookup,请执行ping操作。它会显示已解析的IP。对我来说,这个答案有效,我只是host.docker.internal在容器内部使用此主机名()
Dmitry Minkovsky,

7

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

细节

MacWindows上,可以使用特殊的DNS名称host.docker.internal

主机的IP地址正在更改(如果没有网络访问权限,则没有IP地址)。从18.03开始,我们的建议是连接到特殊的DNS名称host.docker.internal,它将解析为主机使用的内部IP地址。这是出于开发目的,不适用于Docker Desktop for Mac以外的生产环境。


1
请不要对多个问题添加相同的答案。一旦赢得足够的声誉,就回答最好的一个,并将其余的标记为重复。如果不是重复的内容,则根据问题定制帖子,并标记为不删除。
巴尔加夫(Bhargav Rao)


5

如果启用了docker远程API(例如,通过)并且知道主机的主机名或IP地址,则可以通过大量的bash来完成。-Htcp://0.0.0.0:4243

在我容器的用户内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的端口),然后使用node解析返回的JSON DESIRED_PORT


仅在使用端口转发时适用。确实,HostPort这里确实有用的信息,不幸的是,HostIp可能是0.0.0.0
Arnout Engelen

4

我有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}}{{.Gateway}}{{end}}' bridge` [image]

3

对于在AWS中运行Docker的用户来说,这是另一个选择。此选项避免使用apk添加curl包装,并节省了宝贵的7mb空间。使用内置的wget(整体BusyBox二进制文件的一部分):

wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4

3

AFAIK,对于适用于Linux的Docker(标准发行版),主机的ip地址始终为 172.17.0.1

最简单的方法是ifconfig从主机通过(docker0接口):

ifconfig

在泊坞窗内部,泊坞窗的以下命令: 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:19.10 bash -c "apt-get update && apt-get install iproute2 -y && ip -4 route show default | cut -d' ' -f3"

希望对您有所帮助。


2

在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'/.$//'`

1
第一个代码块将获取容器IP,而不是主机IP
Ari,

mandoc hostname -I发出警告,不要“对输出顺序做任何假设”。
not_mutably_borrow '19

1

这是Node.js中的一个简约实现,使用上面提到的EC2元数据实例,可以由谁在AWS EC2实例上运行主机。

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);
    })


0

这是我的方法。在这种情况下,它将主机条目添加到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容器的本地计算机。



0

我使用的解决方案基于一个“服务器”,该服务器在收到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上运行,泊坞窗主机的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


-2

在Ubuntu上,hostname命令可以与以下选项一起使用:

  • -i--ip-address 主机名的地址
  • -I--all-ip-addresses主机的所有地址

例如:

$ hostname -i
172.17.0.2

要分配给变量,可以使用以下单线:

IP=$(hostname -i)

这将为您提供Docker容器而不是主机的IP地址
Mario Camou

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.