iptables实现docker容器动态端口映射实操

背景

之前在《Docker 动态修改容器端口映射的方法》一文中,说明了如何使用修改配置和加防火墙规则实现动态端口映射。但是没有具体分享加防火墙实现动态端口映射的实际案例。今天就分享一下实际操作案例,供大家参考。

分析

动态端口映射的用途

容器端口的动态映射,是用于实现外部访问服务器上的容器内运行的服务的。

如果容器已经运行了,不想停止Docker服务,又想增加端口映射,以便让外部可以立即访问,那就需要使用iptables来实现端口的动态映射。如果可以重启Docker服务,那么采用前面的文章里的方法即可。

实践操作的环境

宿主机局域网IP:192.168.1.15

容器的IP:172.17.0.2

容器已映射端口:443

容器内有监听0.0.0.0的端口:8086

容器内是否开启防火墙:没有开启

宿主机是否正常访问容器的端口:是

宿主机是否开启IPv4转发:是

宿主机局域网IP查看:

ip addr

找到eth0即宿主机使用的网卡这一组,可以看到。

容器IP查看:

docker exec {容器名或容器ID} ip addr

找到eth0@ifxxx这样的一组,查看对应的IP。一般是172开头的,默认一般是172.17.0.2。

容器已有的端口映射查看:

docker ps

找到容器名那一行,找到PORTS那一列,就是已经做好的端口映射。例如:0.0.0.0:443->443/tcp 。

查看容器内已监听的端口:

docker exec {容器名或容器ID} netstat -ltnp|grep 0.0.0.0|grep -v 127.0.0.1

这里过滤出来监听0.0.0.0的端口并排除监听127.0.0.1的端口。选择一个没有做端口映射的来作为测试,我们这里选择的是8086。

查看容器是否开启防火墙:

docker exec {容器名或容器ID} service iptables status | grep Active

如果不是running状态,即没有运行。

因为我移除了iptbales服务配置文件,容器内的防火墙是没有起来的。

查看宿主机是否正常telnet访问容器的8086端口:

如上图所示,看到了Escape character is '^]'即表示端口是通的,可以正常访问,如果没有出现则表示不通。

查看宿主机是否开启IPv4转发:

sysctl net.ipv4.ip_forward

如果返回的值为1即表示开启了,值为0表示未开启。

可以看到,已经开启了IPv4的转发。

实践操作目标

我们使用iptables添加规则,实现在不重启Docker服务和容器的前提下,让外部可以访问容器里的8086服务,即可以telnet宿主机192.168.1.15的8086端口。

实践步骤

1.测试宿主机IP是否可以telnet 连接192.168.1.15 的8086

可以发现:

Trying 192.168.1.15...
telnet: connect to address 192.168.1.15: Connection refused

因为本机并没有监听8086端口,所以使用本机无法telnet8086端口。那从外部执行本机的8086就更不可能成功了。此时我们就是无法从外部访问容器的8086端口的。

2.设置根据端口的转发

只要宿主机IP接收到8086的端口的请求,就转发到172.17.0.2上的8086。前面我们已经确认了172.17.0.2的8086端口是可以通信的。所以请求只要转发到172.17.0.2的8086,请求就可以进入容器。

iptables -t nat -A DOCKER -p tcp --dport {容器外部端口} -j DNAT --to-dest {容器ip}:{容器内部端口}

-t nat:用于指定在nat表添加规则。NAT表用于做IP和端口转换的。

-p tcp:用于指定转换的协议为tcp,这个根据监听的协议来填写。

-A DOCKER:在DOCKER链追加一条规则。如果要把规则写到最开始即最优先匹配,可以把A换成I。A即add,追加到末尾,I即insert,插入到开头。

--dport即容器外部的端口,也即宿主机的端口。这里我们替换为8086。

-j DNAT:就是做DNAT的转换,把目的IP和端口进行转换。

--to-dest:将请求的目的IP和端口修改为什么。这里换为容器的IP和容器内监听的8086。

容器外部的端口和容器内部的端口可以不一样,但是容器内部的端口必须是内部已经监听的端口,而容器外部的端口就是外部拿来通信的端口。

最终的命令如下:

iptables -t nat -A DOCKER -p tcp --dport 8086 -j DNAT --to-dest 172.17.0.2:8086

执行后查看iptables的nat表:

iptables -t nat -nL DOCKER | grep 8086

在宿主机上试一下telnet就通了。

这样就搞定了吗?你从局域网的其他机器执行telnet 192.168.1.15 8086,发现还是不通。

到此,我们已经打通了宿主机可以通过宿主机IP对端口的直接访问,但是外部的还不行。如果你只是需要宿主机可以访问,那就到此结束了。如果你需要在局域网的其他机器也能访问,那还要继续。

3.添加允许外部IP访问8086端口的规则

iptables -A DOCKER -p tcp -s {外部IP} --dport {宿主机的端口} -j ACCEPT

默认不加-t参数,默认就是filter表。-s(源IP)参数用于指定外部特定IP允许访问宿主机。如果不加-s表示外部所有IP都可以访问。--dport则表示只能访问指定的端口。-j ACCEPT表示允许。

最终的命令如下:

iptables -A DOCKER -p tcp -s 外部IP --dport 8086 -j ACCEPT

不过你会发现,此时还是无法从外部IP访问8086。此时虽然外部能请求到宿主机的8086,但是宿主机将这个请求丢了。在宿主机上请求,因为都是内部IP,不管是用宿主机的局域网IP还是172的,都是内部流量,所以会通过容器的网桥进行转发,所以宿主机上可以通过宿主机IP访问到8086。

那从外部来的流量为什么能够转发呢?

因为前面已经将所有的发往8086的流量转发到172.17.0.2上了。现在允许外部请求到宿主机上,就会触发上面的转发规则,就马上转发到172.17.0.2了。一气呵成。

需要注意的是,添加外部允许访问8086端口,必须在DOCKER链,添加INPUT链是没有用的。为什么呢?

iptables先判断nat表中的DOCKER链是否存在对应的端口的转发,如果有则使用filter表的DOCKER来过滤流量,而不再过滤INPUT链了。所以此时必须将允许外部IP访问的规则加在filter表的DOCKER才有用。

如果DOCKER链没有对应端口的转发,则转入INPUT链过滤。

至于为什么会这样,请阅读《一文讲清楚docker利用iptables实现容器网络的原理》。

这样操作之后,就为容器动态添加了端口映射了。把规则删除之后,端口映射即消失。

总结

容器的端口映射,核心就是一个端口转发。另外一个规则就是一个允许外部访问的规则。


原文地址: iptables实现docker容器动态端口映射实操-七秒鱼笔记

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值