Debian 10(buster) + ufw + Docker: 处理Docker容器无法与外部通信的问题

突然处理方法

在update-alternatives –config iptables命令中,将iptables-legacy设置为默认选项。

$ sudo update-alternatives --config iptables
alternative iptables (/usr/sbin/iptables を提供) には 2 個の選択肢があります。

  選択肢    パス                     優先度  状態
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        自動モード
  1            /usr/sbin/iptables-legacy   10        手動モード
  2            /usr/sbin/iptables-nft      20        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 1
update-alternatives: /usr/sbin/iptables (iptables) を提供するためにマニュアルモードで /usr/sbin/iptables-legacy を使います

$ sudo reboot

突然下结论。 xià

    • Debian 10はiptables v1.8系を採用.nftables APIを使うiptables-nftと旧来のiptables-legacyが用意されている.

 

    • デフォルトはiptables-nftだが,Dockerはiptables-legacyを使う.

 

    • この状態で,ufwなどを使ってiptables-nftで定義を設定すると,iptables-legacyの定義は無視される(ようだ).その結果,外部との通信ができない.

 

    そこで,iptables-legacyをデフォルトに変更し,定義をlegacy側に寄せて対処する.

详细解释

ufw和iptables

ufw(Uncomplicated Firewall)是一种简单易用的防火墙管理工具,只需编写ufw allow 22/tcp等命令即可实现端口开放。

在内部,它的定位类似于iptables(Netfilter)的包装器,可以让您忘记iptables易忘的命令体系。我认为它最初是为Ubuntu设计的工具,但是从很早以前开始也可以在Debian上使用。

iptables v1.8支持nftables API。

目前正在测试中的Debian GNU/Linux 10 (buster)中,iptables已从1.6版本升级到1.8版本。

    iptables 1.8.0 release [LWN.net]

在iptables 1.8中,新增了使用nftables Kernel API1的iptables-nft工具,旧有的工具可以使用iptables-legacy来进行操作。

iptables是Debian 10的默认设置,其中有一个指向iptables-nft的符号链接。ufw等使用这个默认设置。

$ ls -l /usr/sbin/iptables
lrwxrwxrwx 1 root root 26  2月 17 11:44 /usr/sbin/iptables -> /etc/alternatives/iptables
$ ls -l /etc/alternatives/iptables
lrwxrwxrwx 1 root root 22  2月 18 22:53 /etc/alternatives/iptables -> /usr/sbin/iptables-nft

Docker使用iptables-legacy。

一方面,Docker在处理iptables-nft时遇到了问题,因此不管默认设置如何,必须进行修正以始终使用iptables-legacy。

    • Docker doesn’t work with iptables v1.8.1 · Issue #38099 · moby/moby

 

    debian has iptables-legacy and iptables-nft now by myobie · Pull Request #2285 · docker/libnetwork

ufw + Docker = 使用iptables-nft + iptables-legacy

在这种情况下,如果使用默认设置的ufw和Docker,会存在iptables-nft和iptables-legacy两个定义。

$ sudo iptables-nft -L
Chain INPUT (policy DROP)
target     prot opt source               destination
ufw-before-logging-input  all  --  anywhere             anywhere
ufw-before-input  all  --  anywhere             anywhere
ufw-after-input  all  --  anywhere             anywhere
ufw-after-logging-input  all  --  anywhere             anywhere
ufw-reject-input  all  --  anywhere             anywhere
ufw-track-input  all  --  anywhere             anywhere
(省略)

$ sudo iptables-legacy -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy DROP)
target     prot opt source               destination
DOCKER-USER  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
(省略)

从这里开始,只能做出推测,但据推测,在这种情况下,只有 iptables-nft 的定义才会生效。因此,尽管 Docker 已经为我们更改了定义,但却无法生效,导致容器无法与外部通信。

当使用ping命令指定IP地址时可以正常通信,但当指定主机名时无法解析DNS的情况。

$ sudo docker run -it --rm busybox
/ # ping github.com
ping: bad address 'github.com'
/ # ping 192.30.255.112
PING 192.30.255.112 (192.30.255.112): 56 data bytes
64 bytes from 192.30.255.112: seq=0 ttl=49 time=133.961 ms
64 bytes from 192.30.255.112: seq=1 ttl=49 time=134.677 ms

处理方法:将iptables-legacy设置为默认选项。

嗯,关于解决方法,我们建议大家都使用iptables-legacy,包括ufw在内。

正如在 moby/moby的Issue评论中提到的那样,Docker 与 iptables v1.8.1 不兼容。因此,我们将把默认的 iptables 更改为 iptables-legacy。

$ sudo update-alternatives --config iptables
alternative iptables (/usr/sbin/iptables を提供) には 2 個の選択肢があります。

  選択肢    パス                     優先度  状態
------------------------------------------------------------
* 0            /usr/sbin/iptables-nft      20        自動モード
  1            /usr/sbin/iptables-legacy   10        手動モード
  2            /usr/sbin/iptables-nft      20        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 1
update-alternatives: /usr/sbin/iptables (iptables) を提供するためにマニュアルモードで /usr/sbin/iptables-legacy を使います

只需要重新启动就完成了。

即使iptables-nft定义仍然存在,但作为默认选择的是iptables-legacy,因此legacy将优先使用。

请参考

    • Debian — buster の iptables パッケージに関する詳細

 

    • iptables 1.8.0 release [LWN.net]

 

    • Docker doesn’t work with iptables v1.8.1 · Issue #38099 · moby/moby

 

    debian has iptables-legacy and iptables-nft now by myobie · Pull Request #2285 · docker/libnetwork
API自体从2014年1月发布的Linux Kernel 3.13版本开始提供。
原本iptables-nft应该可以使用相同的命令,但是出现了一些问题。在Pull request中可以看到类似于“翻译器可能有bug,没有完全跟进到位?”的评论。
关于nftables支持,早在很久以前就有相关的问题提出([feature request] nftables support · Issue #26824 · moby/moby)。
bannerAds