正如标题所示,我需要能够检索docker托管的IP地址以及从主机到容器的portmap,并在容器内部完成这些工作。
唯一的方法是在创建容器时将主机信息作为环境传递
run --env <key>=<value>
/sbin/ip route|awk '/default/ { print $3 }'
正如@MichaelNeale注意到的,在Dockerfile中使用这个方法是没有意义的(除非我们只在构建时需要这个IP),因为这个IP将在构建时被硬编码。
Dockerfile
--add-host可能是一个更干净的解决方案(但没有端口部分,只有主机可以处理这个解决方案)。因此,在docker run命令中,执行如下操作:
--add-host
docker run
docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print $3}'` [my container]
(来自https://stackoverflow.com/a/26864854/127400)
如果你启用了docker远程API(例如通过-Htcp://0.0.0.0:4243),并且知道主机的主机名或IP地址,这可以通过大量bash来完成。
-H
tcp://0.0.0.0:4243
在容器的用户bashrc中:
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。
/proc/self/cgroup
第三行卷曲到主机(假设您使用4243作为docker的端口),然后使用node解析DESIRED_PORT返回的JSON。
DESIRED_PORT
对于那些在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
与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 for Mac上,从18.03版开始,你可以使用host.docker.internal作为主机的IP。看到aljabear的回答。对于以前版本的Mac Docker,以下答案可能仍然有用:
在Docker for Mac上docker0桥不存在,所以这里的其他答案可能不起作用。然而,所有流出的流量都是通过你的父主机路由的,所以只要你试图连接到一个它识别为自己的IP(而docker容器并不认为是自己),你应该能够连接。例如,如果你从父机器运行:
docker0
ipconfig getifaddr en0
这应该会显示你的Mac在当前网络上的IP地址,你的docker容器也应该能够连接到这个地址。如果这个IP地址发生了变化,这当然是一件痛苦的事情,但是你可以在你的Mac上添加一个自定义环回IP,通过在父机器上做这样的事情,容器不会认为它是自己:
sudo ifconfig lo0 alias 192.168.46.49
然后,您可以在docker容器内使用telnet测试连接。在我的例子中,我想连接到一个远程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与您自己网络上的某些内容不冲突。
inet 127.0.0.1/8
127.*
192.168.*
从18.03版开始,你可以使用host.docker.internal作为主机的IP。
host.docker.internal
适用于Docker for Mac, Docker for Windows,以及其他平台。
这是mac特有的docker.for.mac.localhost和docker.for.mac.host.internal的更新,前者从17.06版开始可用,后者从17.12版开始可用,它们也可能在该平台上工作。
docker.for.mac.localhost
docker.for.mac.host.internal
注意,在Mac和窗户文档中,这仅用于开发目的。
例如,我在主机上设置了环境变量:
MONGO_SERVER=host.docker.internal
在我的docker-compose.yml文件中,我有这个:
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
下面是在AWS中运行Docker的另一个选择。这个选项避免了使用apk来添加curl包,节省了宝贵的7mb空间。使用内置的wget (BusyBox二进制文件的一部分):
wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4
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 < / p >
如果您在Service Fabric集群上运行Windows容器,则主机的IP地址可通过环境变量Fabric_NodeIPOrFQDN获得。服务Fabric环境变量
Fabric_NodeIPOrFQDN
在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'/.$//'`
我是这样做的。在这种情况下,它在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容器的本地机器。
如果你想要Windows上真正的IP地址(而不是桥接IP),并且你有docker 18.03(或最新的),执行以下操作:
Windows
IP
18.03
在镜像名为nginx的主机上运行bash(适用于Alpine Linux distribution):
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。
192.168.65.2
spinus
我在这里使用host.docker.internal:
主机有一个不断变化的IP地址(如果没有网络访问,则没有)。从18.03开始,我们的建议是连接到特殊的DNS名称host.docker.internal,它将解析为主机使用的内部IP地址。这是为了开发目的,不能在Docker for Windows之外的生产环境中工作。
也许我创建的容器也是有用的https://github.com/qoomon/docker-host
你可以简单地使用容器名称dns来访问主机系统,例如curl http://dockerhost:9200,所以不需要使用任何IP地址。
我使用的解决方案是基于一个“服务器”,它在接收到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 container
# 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>
Docker主机的IP地址由ipify通过http报头"X-Forwarded-For"返回
示例(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
在Ubuntu上,hostname命令可以与以下选项一起使用:
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 ifconfig.co
每种方法都有局限性,并且只适用于特定的场景。最可移植的选项仍然是运行容器时将IP地址作为配置注入,例如,这里有一个选项在主机上运行之前的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
这是node . js中的一个极简实现,用于在AWS EC2实例上运行主机的人,使用前面提到的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); })
我有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]
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和窗户上,可以使用特殊的DNS名称host.docker.internal。
主机有一个不断变化的IP地址(如果没有网络访问,则没有)。从18.03开始,我们的建议是连接到特殊的DNS名称host.docker.internal,它将解析为主机使用的内部IP地址。这是为了开发目的,不能在Mac Docker Desktop以外的生产环境中工作。
AFAIK,在Docker for Linux(标准发行版)的情况下,主机的IP地址将永远是 172.17.0.1(在Docker的主网络上,参见评论了解更多)。
172.17.0.1
最简单的方法是从主机通过ifconfig(接口docker0)获取:
ifconfig
在docker内部,来自docker的以下命令:ip -4 route show default | cut -d" " -f3
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.04 bash -c "apt-get update > /dev/null && apt-get install iproute2 -y > /dev/null && ip -4 route show default | cut -d' ' -f3"
试试这个:
docker run --rm -i --net=host alpine ifconfig
所以…如果你使用Rancher服务器运行你的容器,Rancher v1.6(不确定2.0是否有)容器可以访问http://rancher-metadata/,其中有很多有用的信息。
curl http://rancher-metadata/latest/self/host/agent_ip
详情见: https://rancher.com/docs/rancher/v1.6/en/rancher-services/metadata-service/ < / p >
docker network inspect bridge -f '\{\{range .IPAM.Config}}\{\{.Gateway}}\{\{end}}'
可以使用docker网络inspect来检索它
我的解决方案:
Docker运行——net=host
然后在docker容器中:
hostname -I | awk '{打印$1}'
在终端上使用hostname -I命令
hostname -I
另一种方法是基于traceroute,它在Linux主机上为我工作,例如在一个基于Alpine的容器中:
traceroute
traceroute -n 8.8.8.8 -m 4 -w 1 | awk '$1~/\d/&&$2!~/^172\./{print$2}' | head -1
如果没有成功响应,则尝试使用-m 4参数增加所测试跳的限制。
-m 4