LoginSignup
9

More than 5 years have passed since last update.

Debian 10(buster) + ufw + Docker: Dockerコンテナが外部と通信できない問題の対処

Last updated at Posted at 2019-02-18

いきなり対処法

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

いきなり結論

  • 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サポート

現時点で testing である Debian GNU/Linux 10 (buster) では,iptablesが1.6から1.8にバージョンアップされています.

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を使うように修正が加えられています2 3

ufw + Docker = iptables-nft + iptables-legacy

ここで,デフォルトのままufwとDockerを使うと,iptables-nftiptables-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をデフォルトにする

さて,対処法ですが,ufwも含めてみんなiptables-legacyを使うようにします.

Docker doesn't work with iptables v1.8.1 · Issue #38099 · moby/mobyのIssue commentにもあるように,デフォルトの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が優先されるようです.

参考

  1. API自体は2014年1月にリリースされたLinux Kernel 3.13から提供されている

  2. 本来iptables-nftでも同じコマンドで通るはずなのですが,謎.Pull requestには『トランスレータのバグかもね? 追っかけきれてないけど😅』みたいなコメントが見られる.

  3. nftablesサポートについてはかなり前からIssueが上がっている様子([feature request] nftables support · Issue #26824 · moby/moby).

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9