Docker 隐藏调用容器的IP
Docker hiding IP of calling container
免责声明:
我是网络新手。如果我没有使用适当的词汇来描述我的问题,请原谅我。
上下文:
所以我有几个应用程序容器 (Docker) 运行 在 CoreOS 上。每个容器必须具有不同的 IAM 角色。由于在同一主机上可能会有 N 个具有 N 个不同 IAM 角色 运行ning 的容器,这会导致使用 EC2 实例元数据 (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) 检索实例凭证时出现问题。每个容器都需要一组不同的凭据(因为每个容器都有不同的角色)。
为了解决这个问题,我偶然发现了这个项目 https://github.com/dump247/docker-ec2-metadata which is a Go proxy that intercepts (using iptables rules) calls to http://169.254.169.254/latest/meta-data/iam/security-credentials/ 并根据调用容器的 IAM 角色提供了正确的凭据。
重新路由呼叫的 iptables 规则(参见 https://github.com/dump247/docker-ec2-metadata/blob/master/README.md)是:
# Get the host IP address. You can use a different mechanism if you wish.
# Note that IP can not be 127.0.0.1 because DNAT for loopback is not possible.
PROXY_IP=$(ifconfig eth0 | grep -Eo "inet addr:[0-9.]+" | grep -Eo "[0-9.]+")
# Port that the proxy service runs on. Default is 18000.
PROXY_PORT=18000
# Drop any traffic to the proxy service that is NOT coming from docker containers
iptables \
-I INPUT \
-p tcp \
--dport ${PROXY_PORT} \
! -i docker0 \
-j DROP
# Redirect any requests from docker containers to the proxy service
iptables \
-t nat \
-I PREROUTING \
-p tcp \
-d 169.254.169.254 --dport 80 \
-j DNAT \
--to-destination ${PROXY_IP}:${PROXY_PORT} \
-i docker0
由于我们 运行 在 CoreOS 上,我们希望将该代理部署在 Docker 容器中。我们不想直接在 EC2 主机上安装代理。
假设我有 2 个容器 运行宁 2 个具有不同 IAM 角色的应用程序:
- 容器A:IP:172.17.0.7,IAM角色:角色A
- 容器B:IP:172.17.0.8,IAM角色:roleB
当代理拦截到 http://169.254.169.254/latest/meta-data/iam/security-credentials/ , the proxy needs to know the requesting container’s IP (e.g. 172.17.0.8), in order to use the Docker client (https://github.com/fsouza/go-dockerclient 的请求时)以检索请求容器的 IAM 角色(使用环境变量传递给容器,例如:docker run -e IAM_ROLE=arn:aws:iam::123456789012:role/roleA --name containerA myapp
)
问题:
检索请求容器的 IP(在我们的示例中为 172.17.0.[7, 8])当代理 运行 在 EC2 主机上本地时工作得很好。这是我的心智模型,当代理 运行 在主机上本地时会发生什么:
containerA 调用 http://169.254.169.254 -> iptables 路由发生 -> 调用被重定向到 localhost:18000 -> 代理容器将 containerA 的 IP 视为传入请求的源
但是,当代理 运行 位于 Docker 容器中时,它就不能很好地工作。请注意,我使用 docker run -p 18000:18000 -v /var/run/docker.sock:/var/run/docker.sock ec2-metadata-proxy
启动代理
当代理运行在Docker容器中时,请求容器的IP是docker0接口的IP(如172.17.42.1),无法确定请求容器。同样,这是我的心智模型,当代理 运行 在容器中时会发生什么:
containerA 调用 http://169.254.169.254 -> iptables 路由发生 -> 调用被重定向到 localhost:18000 -> Docker 调用代理容器的路由 -> 代理容器看到 docker0 的 IP作为传入请求的来源
问题:
如何确保代理看到的 IP 地址是请求容器(例如 containerA)的 IP 地址,而不是 docker0 接口的 IP 地址?
经过一些试验,我发现运行 --net=host
模式下的代理容器解决了这个问题。
通过使用此选项,代理容器与主机共享相同的网络堆栈,从而绕过 docker0 网桥。
免责声明:
我是网络新手。如果我没有使用适当的词汇来描述我的问题,请原谅我。
上下文:
所以我有几个应用程序容器 (Docker) 运行 在 CoreOS 上。每个容器必须具有不同的 IAM 角色。由于在同一主机上可能会有 N 个具有 N 个不同 IAM 角色 运行ning 的容器,这会导致使用 EC2 实例元数据 (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) 检索实例凭证时出现问题。每个容器都需要一组不同的凭据(因为每个容器都有不同的角色)。
为了解决这个问题,我偶然发现了这个项目 https://github.com/dump247/docker-ec2-metadata which is a Go proxy that intercepts (using iptables rules) calls to http://169.254.169.254/latest/meta-data/iam/security-credentials/ 并根据调用容器的 IAM 角色提供了正确的凭据。
重新路由呼叫的 iptables 规则(参见 https://github.com/dump247/docker-ec2-metadata/blob/master/README.md)是:
# Get the host IP address. You can use a different mechanism if you wish.
# Note that IP can not be 127.0.0.1 because DNAT for loopback is not possible.
PROXY_IP=$(ifconfig eth0 | grep -Eo "inet addr:[0-9.]+" | grep -Eo "[0-9.]+")
# Port that the proxy service runs on. Default is 18000.
PROXY_PORT=18000
# Drop any traffic to the proxy service that is NOT coming from docker containers
iptables \
-I INPUT \
-p tcp \
--dport ${PROXY_PORT} \
! -i docker0 \
-j DROP
# Redirect any requests from docker containers to the proxy service
iptables \
-t nat \
-I PREROUTING \
-p tcp \
-d 169.254.169.254 --dport 80 \
-j DNAT \
--to-destination ${PROXY_IP}:${PROXY_PORT} \
-i docker0
由于我们 运行 在 CoreOS 上,我们希望将该代理部署在 Docker 容器中。我们不想直接在 EC2 主机上安装代理。
假设我有 2 个容器 运行宁 2 个具有不同 IAM 角色的应用程序:
- 容器A:IP:172.17.0.7,IAM角色:角色A
- 容器B:IP:172.17.0.8,IAM角色:roleB
当代理拦截到 http://169.254.169.254/latest/meta-data/iam/security-credentials/ , the proxy needs to know the requesting container’s IP (e.g. 172.17.0.8), in order to use the Docker client (https://github.com/fsouza/go-dockerclient 的请求时)以检索请求容器的 IAM 角色(使用环境变量传递给容器,例如:docker run -e IAM_ROLE=arn:aws:iam::123456789012:role/roleA --name containerA myapp
)
问题:
检索请求容器的 IP(在我们的示例中为 172.17.0.[7, 8])当代理 运行 在 EC2 主机上本地时工作得很好。这是我的心智模型,当代理 运行 在主机上本地时会发生什么:
containerA 调用 http://169.254.169.254 -> iptables 路由发生 -> 调用被重定向到 localhost:18000 -> 代理容器将 containerA 的 IP 视为传入请求的源
但是,当代理 运行 位于 Docker 容器中时,它就不能很好地工作。请注意,我使用 docker run -p 18000:18000 -v /var/run/docker.sock:/var/run/docker.sock ec2-metadata-proxy
当代理运行在Docker容器中时,请求容器的IP是docker0接口的IP(如172.17.42.1),无法确定请求容器。同样,这是我的心智模型,当代理 运行 在容器中时会发生什么:
containerA 调用 http://169.254.169.254 -> iptables 路由发生 -> 调用被重定向到 localhost:18000 -> Docker 调用代理容器的路由 -> 代理容器看到 docker0 的 IP作为传入请求的来源
问题:
如何确保代理看到的 IP 地址是请求容器(例如 containerA)的 IP 地址,而不是 docker0 接口的 IP 地址?
经过一些试验,我发现运行 --net=host
模式下的代理容器解决了这个问题。
通过使用此选项,代理容器与主机共享相同的网络堆栈,从而绕过 docker0 网桥。