エラーの内容
サーバーを再起動してコンテナを立ち上げようとすると、次のエラーが発生します:
Error response from daemon: driver failed programming external connectivity on endpoint mycontainer: iptables: No chain/target/match by that name.
再起動前は問題なく動いていました。コンテナの設定も変わっていません。それでもDockerはコンテナの起動を拒否します。表面上は何も壊れていないように見えるため、非常に厄介なエラーです。
何が起きているのか
Dockerはコンテナのネットワーキングを管理するために、iptablesにルールを挿入します。具体的にはDOCKER、DOCKER-USER、DOCKER-ISOLATION-STAGE-1といったチェーンを使用します。これらのチェーンはDockerデーモンの起動時に作成されます。
再起動後、Dockerの起動後にファイアウォールのルールがリロードまたはリセットされると、これらのチェーンが消去されます。DockerのルールはなくなりますがDockerはそれを認識しません。コンテナを起動しようとすると、Dockerは存在しないチェーンにルールを追加しようとするため、「No chain/target/match by that name」というエラーが発生します。
主な原因として考えられるもの:
- Dockerの起動後に
firewalldやufwがリロードされてiptablesをフラッシュする - 起動時に
iptables -Fまたはiptables --flushを実行するカスタムスクリプト - systemdの起動順序の競合:ファイアウォールの準備が整う前にDockerが起動し、その後ファイアウォールがすべてをリセットする
iptables-legacyとiptables-nftの切り替え — Debian/Ubuntu 20.04以降でよく見られる問題
修正方法1:Dockerデーモンを再起動する(応急処置)
今すぐ復旧させる最も速い方法はDockerを再起動することです。これによりiptablesのチェーンがゼロから再作成されます。
sudo systemctl restart docker
その後コンテナを起動します:
docker start mycontainer
# または
docker compose up -d
ほとんどの場合これですぐに解決します。ただし根本的な原因を解消しないと、次回の再起動時に同じエラーが再発します。続きを読んでください。
修正方法2:iptablesのバックエンドを確認する(Ubuntu/Debian)
Ubuntu 20.04以降またはDebian 10以降では、システムがiptables-nft(nftablesバックエンド)を使用している一方で、Dockerがiptables-legacyを期待している場合があります。これらが一致しないと、Docker起動時にチェーンの検索がサイレントに失敗します。
現在アクティブなバックエンドを確認します:
sudo update-alternatives --display iptables
現在の選択肢としてiptables-nftが表示されている場合は、レガシーに切り替えます:
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
Dockerを再起動します:
sudo systemctl restart docker
最近のDebian/Ubuntuマシンの大半では、これだけでエラーが解消されます。これらのシステムでは他の方法を試す前にまずこれを試してください。
修正方法3:systemdのサービス起動順序を修正する(firewalld)
firewalldを使用していますか?それが原因である可能性が高いです。firewalldは起動時に独自のルールセットをリロードします。そのリロードがDockerがチェーンをセットアップした後に行われると、firewalldがそれらを消去してしまいます。
firewalldがアクティブか確認します:
sudo systemctl status firewalld
sudo firewall-cmd --list-all
firewalldの起動が完了するまでDockerが待機するよう、systemdに指示します:
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/after-firewalld.conf <<EOF
[Unit]
After=firewalld.service
EOF
変更を適用します:
sudo systemctl daemon-reload
sudo systemctl restart docker
firewalldが実際には必要ない開発サーバーでは、無効化してしまいましょう:
sudo systemctl disable --now firewalld
修正方法4:Dockerの後でiptablesのフラッシュスクリプトが実行されないようにする
/etc/rc.localや専用のsystemdユニットなど、iptablesのルールをフラッシュするカスタムスクリプトがありますか?Dockerとの起動タイミングを確認してください。
すべてのチェーンを手動でフラッシュし、Dockerに再構築させます:
# すべてのiptablesルールをクリア
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -t mangle -F
sudo iptables -t mangle -X
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
# DockerのチェーンをDockerに再構築させる
sudo systemctl restart docker
フラッシュスクリプトを残す必要がある場合は、スクリプトの末尾にsystemctl restart dockerを追加してください。あるいはsystemdの起動順序を設定してDockerが常に最後に起動するようにします。
動作確認
修正を適用した後、DockerのチェーンがインポイントのIPtablesに存在することを確認します:
sudo iptables -L DOCKER --line-numbers
次のような出力が表示されるはずです:
Chain DOCKER (1 references)
num target prot opt source destination
ここでiptables: No chain/target/match by that nameが表示される場合は、Dockerのチェーンがまだ作成されていません。デーモンを再起動して再度確認してください。
コンテナが正常に起動することを確認します:
docker start mycontainer
docker ps # コンテナがUpと表示されるはずです
修正が再起動後も維持されることを確認するため、完全な再起動テストを行います:
sudo reboot
# 再接続後:
docker ps -a # コンテナの状態を確認
journalctl -u docker -n 50 # Dockerのログでエラーを確認
予防策
この問題が再発しないよう、以下の点を確認しておく価値があります:
- iptablesのバックエンドを固定する。
iptables-legacyへの切り替えは再起動後も維持されますが、OSのメジャーアップグレード後は再確認してください。UbuntuでのやAPTapt upgradeによって、nftに戻ってしまう場合があります。 --iptables=falseは理解した上で使用する。/etc/docker/daemon.jsonで"iptables": falseを設定すると完全な制御が可能ですが、NATやフォワーディングのすべてのルールを手動で管理することになります。ルールが一つでも欠けるとコンテナがインターネットにアクセスできなくなります。- 起動順序を可視化する。
systemd-analyze plot > boot.svgを実行してブラウザでSVGを開いてください。タイムライン上でDockerとfirewalldの起動タイミングが明確に確認でき、競合状態が一目でわかります。 - **DockerのサブネットをDockerを計画する。**カスタムサブネットを持つ複数のDockerネットワークを運用する場合、ホストネットワークとのCIDR競合により異なるクラスのエラーが発生します。ToolCraftのSubnet Calculatorを使えば、ブリッジサブネットを割り当てる前に既存のルートと衝突しないか素早く確認できます。
クイックリファレンス
# 最も一般的な修正手順:
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo systemctl restart docker
# DockerのチェーンがあることをDockerを確認:
sudo iptables -L DOCKER
# まだ失敗する場合はDockerのログを確認:
journalctl -u docker -n 100 --no-pager

