正如标题所示,我需要能够检索docker托管的IP地址以及从主机到容器的portmap,并在容器内部完成这些工作。


当前回答

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

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

例如:

$ hostname -i
172.17.0.2

要给变量赋值,可以使用以下一行代码:

IP=$(hostname -i)

其他回答

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

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

例如:

$ hostname -i
172.17.0.2

要给变量赋值,可以使用以下一行代码:

IP=$(hostname -i)

对于大多数希望自动执行此操作的应用程序来说,标准的最佳实践是:你不需要这样做。相反,你让运行容器的人注入一个外部主机名/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条目:

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

另一种方法是基于traceroute,它在Linux主机上为我工作,例如在一个基于Alpine的容器中:

traceroute -n 8.8.8.8 -m 4 -w 1 | awk '$1~/\d/&&$2!~/^172\./{print$2}' | head -1

它花了一点时间,但列出了第一跳的IP,该IP不是以172开头的。如果没有成功响应,则尝试使用-m 4参数增加测试跳数的限制。

唯一的方法是在创建容器时将主机信息作为环境传递

run --env <key>=<value>

我是这样做的。在这种情况下,它在docker镜像的/etc/hosts中添加了一个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容器的本地机器。