如何将 UDP 数据包从 Docker 容器转发到主机 127.0.0.1?

如何将 UDP 数据包从 Docker 容器转发到主机 127.0.0.1?

我有一台主机(A),其中有一个 StatsD 守护进程正在监听 127.0.0.1:8125:

root@A# netstat -uln
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
udp        0      0 127.0.0.1:8125          0.0.0.0:*                          

并且在主机 A 上启动了一个 Docker 容器(B),并带有桥接网络:

root@A# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "02b013615710b375744975ff74bdd0b5dcc8c25debba4fa23ad8f53da2c684e3",
        "Created": "2017-04-21T08:13:04.389253904Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "e1fde895c871504f64627c88531a380269ee9fe8a9fa5237a98c81500fa47a7a": {
                "Name": "B",
                "EndpointID": "4e4a8758e811bb48cecec67d339c182c60e1d955126506cddb7d451e818c5535",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

我的网络接口:

root@A# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:60:00:2c:63 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:60ff:fe00:2c63/64 scope link 
       valid_lft forever preferred_lft forever

现在我想将带有指标的 UDP 数据包从容器 B 发送到 A 上的 StatsD(127.0.0.1:8125),如下所示:

root@B# echo "metric.name:1|c" | nc -w 1 -u 172.17.0.1 8125

接下来我应该怎么做才能将 UDP 数据包从 172.17.0.1:8125 转发到 127.0.0.1:8125?

我尝试添加 iptables 规则:

root@A# iptables -t nat -A PREROUTING -p udp -i docker0 -d 172.17.0.1 --dport 8125 -j DNAT --to-destination 127.0.0.1:8125

但我仍然没有在 StatsD 上看到我的 UDP 数据包。

iptables nat:

root@A# iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 736 packets, 53956 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 211K   13M DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
    3   116 DNAT       udp  --  docker0 *       0.0.0.0/0            172.17.0.1           udp dpt:8125 to:127.0.0.1:8125

Chain INPUT (policy ACCEPT 724 packets, 53227 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 838 packets, 57674 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   20  1186 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 1407 packets, 91792 bytes)
 pkts bytes target     prot opt in     out     source               destination         
84593 5296K MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:8080

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
 1285 77084 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
  933 55820 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:8080

iptables 过滤器:

root@A# iptables -t filter -L -n -v
Chain INPUT (policy ACCEPT 33641 packets, 5895K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
2298K 1931M DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
1165K  662M DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
 602K  560M ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
1133K 1269M ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 27954 packets, 14M bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (1 references)
 pkts bytes target     prot opt in     out     source               destination         
 8285  685K ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0            172.17.0.2           tcp dpt:8080

Chain DOCKER-ISOLATION (1 references)
 pkts bytes target     prot opt in     out     source               destination         
2298K 1931M RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

怎么了?

重要的:

  1. 我必须仅在 A 的 127.0.0.1:8125 上使用 statsd(不能仅将其设置为在 172.17.0.1:8125 上监听)
  2. Docker 网络仅为“桥接”(不能使用“主机”)

答案1

如果有人关心的话,我已经解决了这个问题

sysctl -w net.ipv4.conf.docker0.route_localnet=1

相关内容