Hacking Limbo

Reading / Coding / Hacking

解决 Docker iptables 与 ferm 的冲突

Docker daemon 每次启动时都会往 iptables 里写入很多规则(虽然我觉得只需要 SNAT 这一条),docker run 如果指定了端口转发也同样在 nat table 里产生相应的 DNAT 规则。本来这没什么大碍,但是我们用 ferm 管理服务器的 iptables——更新配置之后,ferm 会调用 iptables-restore 刷新 iptables, 意味着所有不在 ferm 管理范围的规则都会丢失。

解决方法有两种:

  1. ferm.conf 里声明 @hook post "service docker restart", 即每次刷新 iptables 后重启 Docker daemon.
  2. 用 ferm 管理 Docker daemon 的 iptables 规则。

方案 1 的优点是不用管 Docker 到底写了什么规则,缺点是重启 Docker daemon 会中断一部分服务。方案 2 的优点是保持对 iptables 的完全控制,缺点是有可能漏掉规则,而且修改 Docker 配置之后还需要更新 ferm.conf.

选择方案 2 的话,可以在 Docker daemon 和容器启动之后,用 import-ferm 导出完整的规则,再挑选出 Docker 相关的部分合并进 ferm.conf:

table nat {
  chain DOCKER;

  chain PREROUTING {
    mod addrtype dst-type LOCAL jump DOCKER;
  }

  chain OUTPUT {
    daddr ! 127.0.0.0/8 mod addrtype dst-type LOCAL jump DOCKER;
  }

  chain POSTROUTING {
    saddr 172.17.0.0/16 outerface ! docker0 MASQUERADE;
  }
}

这样容器就能正常访问网络了,但是端口转发的规则还没有,table nat 里的 chain DOCKER 是空的。这个可以等用到的时候再看看怎么添加 😷。设想的方案(待试验):监听 Docker 事件,获取正在运行的容器,根据其配置的端口转发生成 ferm.docker.conf, 这个文件会被 @include 到主配置里。