Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

いきなり対処法

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). 

no_clock
P2P地震情報とかも作ってます.
https://www.nyamikan.net/
m3dev
インターネット、最新IT技術を活用し日本・世界の医療を改善することを目指します
https://m3.recruitment.jp/engineer/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした