解决Docker容器iptables不能用

  • 解决Docker容器iptables不能用已关闭评论
  • 886 次浏览
  • A+
所属分类:linux技术
摘要

最近使用frp做跳板远程运维内网的服务器,尽管已经屏蔽了海外IP对vps服务器的访问,但是总觉得直接暴露远程管理的端口在互联网上还是不安全。于是想着用Ocserv做服务端先vpn拨进去在进行运维会安全很多。选择Ocserv的原因也是因为支持思科的anyconnect客户端,各大应用市场都不屏蔽比较具有易用性。

最近使用frp做跳板远程运维内网的服务器,尽管已经屏蔽了海外IP对vps服务器的访问,但是总觉得直接暴露远程管理的端口在互联网上还是不安全。于是想着用Ocserv做服务端先vpn拨进去在进行运维会安全很多。选择Ocserv的原因也是因为支持思科的anyconnect客户端,各大应用市场都不屏蔽比较具有易用性。

然而在Centos8上安装Docker之后,Docker中再使用Ocserv容器的时候iptables不能正常工作。目前貌似资料不好找,特此做个笔记保留下。

故障描述

附上Docker-Ocserv作者Git:https://github.com/Pezhvak/docker-ocserv我很喜欢这个封装好的Docker image,当然为了适配也做了一些更改,其中也包括了下文。

该Docker镜像使用非常小巧的 Alpine Linux,由于VPN拨号之后需要做NAT才可以访问其他网络中地址,结果抓包看到不正常。进入容器中提示如下。

iptables -L -n modprobe: can't change directory to '/lib/modules': No such file or directory iptables v1.8.7 (legacy): can't initialize iptables table `filter': Table does not exist (do you need to insmod?) Perhaps iptables or your kernel needs to be upgraded. 

作为关键词问搜索引擎之后得到的大多答案有两个解决问题的方法:

  1. 修改Docker容器的权限:给--privileged权限。或者担心权限过大限定特定权限:--cap-add NET_ADMIN --cap-add NET_RAW。我已经给了最大的--privileged权限还是无效。

  2. 提示的错误信息很明确,找不到对应的内核模块,让容器加载iptables相关内核模块。但是这个方法实际是不靠谱的,因为容器和宿主机共享内核。

于是在搜索了一些相关项目的issues帖子之后找到了根本解决的方法。

文中有人提到:发现宿主机是Centos8,并且容器为alpine:3.10的时候出现了相同问题。原因是Centos8没有加载iptables需要的内核模块。该作者通过先执行:sudo modprobe iptable_filter,sudo modprobe iptable_nat之后再开启alpine容器修复了这个问题。

我在想:我的宿主机Centos8运行的Iptables工作良好呀,怎么可能没有加载iptables所需要的内核模块呢?

再接下来的回帖中找到了答案:原来再存在两个版本的iptables,他们分别是iptables-nftiptables-legacy这两个iptables使用了不同的内核模块。alpine默认使用的是iptables-legacyCentos8默认使用的是iptables-nft。因为宿主机没有加载对应的内核模块所以容器就无法使用内核模块就说得过去了。

解决问题:

那么现在解决问题的方法有两个了,一个是参照文中提到的手动加载容器中iptables-legacy所需的模块(该方法我并未验证使用,担心对宿主机中已经配置好的iptables产生影响)。

第二个方法也是我在用的方法,将容器启动脚本中所有的iptables命令,更改为iptables-nft问题完美解决。

iptables-nft -L -n Chain INPUT (policy ACCEPT) target     prot opt source               destination  Chain FORWARD (policy ACCEPT) target     prot opt source               destination  Chain OUTPUT (policy ACCEPT) target     prot opt source               destination  # 例如: iptables-nft -t nat -A POSTROUTING -j MASQUERADE iptables-nft -A INPUT -p tcp --dport 443 -j ACCEPT iptables-nft -A INPUT -p udp --dport 443 -j ACCEPT 

相关链接:

https://github.com/kylemanna/docker-openvpn/issues/564
https://github.com/qdm12/gluetun/issues/896
https://github.com/moby/moby/issues/18230