我的情况:我想让我的基于 docker 的服务知道哪个 IP 正在从 Web 调用它们(我的应用程序的要求)。
我在云 VPS、debian jessie 上运行,使用的是 docker 1.12.2。
我使用nc
详细模式来打开端口8080
。
docker run --rm -p "8080:8080" centos bash -c "yum install -y nc && nc -vv -kl -p 8080"
假设 VPS 有域名example.com
,并且我的另一台机器有dead:::::beef
我调用的IP
nc example.com 8080
这服务器说:
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Listening on :::8080
Ncat: Listening on 0.0.0.0:8080
Ncat: Connection from 172.17.0.1.
Ncat: Connection from 172.17.0.1:49799.
172.17.0.1
位于服务器的本地网络,当然与我的客户无关。事实上:
docker0 Link encap:Ethernet HWaddr ....
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
如果我以主机网络模式启动容器
docker run --rm --net=host -p "8080:8080" centos bash -c "yum install -y nc && nc -vv -kl -p 8080"
然后再次呼叫我的服务器
nc example.com 8080
我得到了预期的结果:
Ncat: Connection from dead:::::beef.
Ncat: Connection from dead:::::beef:55650.
我的问题是:
- 为什么当不处于主机网络模式时,docker 会“屏蔽”ips?我认为 docker 守护进程很可能是打开端口、接收连接,然后使用其自己的内部虚拟网络接口连接将其中继到容器进程的进程。
nc
因此,在容器中运行只会看到调用来自 docker 守护进程的 IP。 - (如何)我可以让我的docker服务知道调用它的外部IP没有将其全部置于主机模式?
答案1
根据文档,默认驱动程序(即当您未--net=host
在 中指定时docker run
)是bridge
网络驱动程序。
这与 docker '屏蔽' IP 地址无关,而是bridged
与host
网络模式如何变化有关。
对于 Docker 来说,桥接网络使用软件桥接器,允许连接到同一桥接网络的容器进行通信,同时与未连接到该桥接网络的容器隔离。Docker 桥接驱动程序会自动在主机中安装规则,以便不同桥接网络上的容器无法直接相互通信。
Docker 创建一个隔离网络,以便桥接网络中的每个容器都可以通信,在您的情况下是docker0
。因此,默认情况下,docker 主机上的容器在此网络内进行通信。
您现在可能已经明白了,172.17.0.1
是网络上的默认路由docker0
,但它并不充当将数据包转发到目的地的路由器,因此您会将其视为 netcat 输出中的源。
事实上,你可以在ss -tulnp
你的docker主机上运行来验证这一点。你应该看到监听8080端口的进程是docker。
另一方面,使用主持人网络驱动程序意味着容器和主机之间没有隔离。您可以通过ss -tulnp
在 docker 主机上运行来验证这一点;您应该看到进程在监听套接字而不是 docker(在您的例子中,您应该看到nc
)。
答案2
我有完全相同的问题,而且解决方案来自 @TosoBoso 的这款工具非常适合我,因为我的 Web 后端前面有一个 Nginx 反向代理。Echo 的文档也帮助我更好地理解了这个问题。
基本上,您将在 Nginx 配置中重写标题(至少您需要X-Real-IP
),然后您可以在程序中稍后捕获它。
location /api/ {
proxy_pass http://127.0.0.1:7006/api/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}