正如标题所述,我需要能够在容器内部检索Docker主机的IP地址和主机到容器的端口映射。
正如标题所述,我需要能够在容器内部检索Docker主机的IP地址和主机到容器的端口映射。
/sbin/ip route|awk '/default/ { print $3 }'
正如 @MichaelNeale所指出的,除非我们只在构建时需要这个IP地址,否则在Dockerfile
中使用此方法没有意义,因为该IP地址将在构建时硬编码。
从版本18.03开始,您可以使用host.docker.internal
作为主机的IP地址。
在Docker for Mac,Docker for Windows,以及可能还有其他平台中都适用。
这是针对Mac特定的更新,自17.06版本起可用的docker.for.mac.localhost
和自17.12版本起可用的docker.for.mac.host.internal
,这些选项也可能仍然适用于该平台。
请注意,正如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
docker.for.mac..
在大多数情况下是无用的,因为你的公司中往往不仅有Linux或Mac环境。开发人员使用的是Linux、Mac和Windows混合环境。这个领域没有意义,因为在99%的情况下,这是一个混合Host OS环境。我不会在macOS下开发容器,然后将其部署到macOS服务器上。我会将其部署到Linux上。这是每个人都会做的。那么,docker.for.mac..
到底有什么意义呢? - TheFox更新:在Docker for Mac版本18.03及以上,您可以将host.docker.internal用作主机的IP。请参见aljabear的答案。对于早期版本的Docker for Mac,以下答案仍然有用:
在Docker for Mac上,docker0
桥不存在,因此这里的其他答案可能无法正常工作。但是,所有的出站流量都将通过您的父主机路由,因此只要您尝试连接到一个被它本身(且docker容器不认为它本身)识别为自己的IP,您就应该能够连接。例如,如果您从父机运行此命令:
ipconfig getifaddr en0
这应该会显示您的Mac在当前网络上的IP地址,您的Docker容器也应该能够连接到此地址。当然,如果IP地址发生变化,这可能会很麻烦,但是您可以在父机上执行类似于以下操作以将自定义环回IP添加到Mac上,从而使容器不认为它是本身:
sudo ifconfig lo0 alias 192.168.46.49
您可以在 Docker 容器中使用 telnet 进行连接测试。在我的情况下,我想要连接到远程的 xdebug 服务器。telnet 192.168.46.49 9000
现在,当针对 192.168.46.49 的流量进入您的 Mac 时(以及所有离开容器的流量都通过您的 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不会与您自己的网络中的某些内容发生冲突。172.17.0.1
(在Docker的主网络上,详见评论以了解更多信息)。获取它的最简单方法是通过从主机运行ifconfig
(接口docker0)。ifconfig
从 Docker 容器内部,可以使用以下命令获取 Docker 的 IP 地址: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:22.10 bash -c "apt-get update > /dev/null && apt-get install iproute2 -y > /dev/null 2> /dev/null && ip -4 route show default | cut -d' ' -f3"
docker0
默认桥接接口的容器。但对于使用 Docker Compose 启动的容器则不适用,它们不会在默认的桥接接口上运行。使用 docker network ls
和 docker network inspect <network_name>
可以帮助你找出该 IP 地址是什么。 - Carl Patenaude Poulindocker network ls
访问网络,如果您没有定义任何网络,则只需知道docker-compose在Docker内自动定义了虚拟网络(您也可以列出它们)。 - Nek对于在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
ifconfig eth0 | grep -oP 'inet \\K\\S+'
。 - Jean Claveaudocker network inspect bridge -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
可以使用docker network inspect来检索它。
创建容器时,唯一的方法是将主机信息作为环境变量传递
run --env <key>=<value>
-e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"
(使用 http://unix.stackexchange.com/questions/87468/is-there-an-easy-way-to-programmatically-extract-ip-address 的被接受答案)。 - ncoghlan--add-host
可能是一个更加干净的解决方案(但没有端口部分,只能处理主机部分)。因此,在您的 docker run
命令中,可以这样做:
docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print $3}'` [my container]
对于大多数希望自动执行此操作的应用程序,标准最佳实践是:不要这样做。相反,您可以让运行容器的人将外部主机名/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桌面版,它们将DNS条目注入到嵌入式虚拟机中:
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
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地址(如果您没有网络访问,则没有IP地址)。从18.03版本开始,我们建议连接到特殊的DNS名称host.docker.internal,该名称解析为主机使用的内部IP地址。这仅用于开发目的,在Docker Desktop for Mac之外的生产环境中将无法正常工作。