[Troubleshooting] ホストの iptables でポートを開けたのに、なぜ Docker コンテナは依然として遮断されるのか?

ホストの iptables INPUT チェーンにポートの allow ルールを追加したにもかかわらず、
Docker コンテナを -p host:container で公開したポートに接続できないケースがある。

結論から言うと、理由は明確である。

Docker のポート公開トラフィックは INPUT ではなく、FORWARD → DOCKER(-USER) チェーンで処理される。
そのため、INPUT にどれだけルールを追加しても、
Docker 系チェーンで DROP されていれば通信は遮断される。


なぜ INPUT が効かないのか

Docker のポート公開時のトラフィックフローは、通常以下のようになる。

外部 → DNAT → FORWARD → DOCKER-USER → DOCKER → コンテナ

つまり、コンテナ宛のトラフィックはホスト上のローカルプロセスではなく、
フォワーディングトラフィックとして扱われる。

したがって、許可/遮断の制御は DOCKER または DOCKER-USER で行う必要がある。


クイック診断

iptables -L DOCKER -n --line-numbers
iptables -L DOCKER-USER -n --line-numbers

以下のようなルールが存在する場合、実質的に「全遮断」状態である。

  • -p tcp --dport 0:65535 -j DROP
  • 条件なしの broad DROP ルール

最も危険な落とし穴(重要)

DOCKER-USER--dport だけを見て遮断してはいけない

次のようなルールはよく見かけるが、運用環境では危険である。

iptables -I DOCKER-USER -p tcp --dport 8080 -j DROP

理由

DOCKER-USER チェーンは DNAT 適用後 に評価される。
この時点での --dport 8080 は、外部ポートではなく「コンテナ内部ポート」 を指す。

その結果、以下のような状況が発生する。

  • コンテナ A: -p 9000:8080
  • コンテナ B: -p 8080:8080

意図: 「外部ポート 8080 だけを遮断したい」
現実: 内部ポート 8080 を使用するすべてのコンテナが同時に遮断される

これが本番環境で発生すると、
外部ポートだけで分離していたサービスが一斉に停止する。


安全なパターン(推奨)

原則

以下のルールは文法上 DOCKER に置き換えても動作するが、
運用環境では DOCKER-USER の使用を強く推奨する。

  • ESTABLISHED,RELATED を最初に許可する
  • 遮断対象はポートではなく コンテナ IP に絞る
  • 最後に RETURN を入れる

例:特定コンテナのみ制御する場合

# 応答トラフィックを許可
iptables -I DOCKER-USER 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 特定コンテナ IP を対象
iptables -I DOCKER-USER 2 -d 172.17.0.10/32 -p tcp --dport 8080 -s 203.0.113.10/32 -j ACCEPT
iptables -I DOCKER-USER 3 -d 172.17.0.10/32 -p tcp --dport 8080 -j DROP

# Docker のデフォルトフローに戻す
iptables -A DOCKER-USER -j RETURN

ポイント

「外部ポート」基準で制御するのではなく、
「どのコンテナ宛のトラフィックか」 を基準に制御する。

これにより、DNAT 前提の構造でも副作用を回避できる。


Tip(運用上の考慮点)

コンテナの再生成やサーバー再起動により、
コンテナ内部 IP は変更される可能性がある。

運用環境では、以下のいずれかで安定性を確保することを推奨する。

  • ユーザー定義 bridge ネットワーク + Static IP による固定(最も推奨)
  • もしくは、外部ポート基準でのマッチングが必要な場合、
    conntrack の original tuple(例:--ctorigdstport)を用いたルールを検討する
    (※ conntrack エントリ、カーネルモジュール、ルールの適用位置により挙動が異なるため、事前テスト必須)

ルール保存(再起動対策)

DOCKER / DOCKER-USER のルールは再起動で消える可能性がある。
以下のコマンドで保存しておくこと。

netfilter-persistent save

一行まとめ

  • Docker の公開ポートは INPUT ではなく DOCKER(-USER) で制御される
  • DOCKER-USER における --dport内部ポート基準のため、必ずコンテナ単位に絞る

この二点を押さえておけば、Docker × iptables に起因する事故の 90% は回避できる。

🛠 마지막 수정일: 2025.12.29

💡 お困りですか?
Zabbix、Kubernetes、各種オープンソースインフラの構築・運用・最適化・障害解析が必要であれば、いつでもご連絡ください。

📧 メール: jikimy75@gmail.com
💼 サービス: 導入支援 | 性能チューニング | 障害解析コンサルティング

What are your feelings

Updated on 2025-12-29