1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DockerをPodmanに置き換えたらハマった (AlmaLinux 10での事例)

1
Posted at

はじめに

次の案件でPodmanが要件になっているのですが、自分ではまだPodman環境をゼロから構築した経験がありませんでした。そこで、社内の比較的自由に使える検証機を練習台として、Dockerで動かしていた環境をPodmanに置き換えてみることにしました。「rootlessで動くし、daemonレスだしセキュリティ的にも良さそう」くらいの軽い気持ちもありましたが、実際にやってみるといくつか想定外の詰まりどころがあったのでメモを残します。

構成はざっくりこんな感じでした。

  • OS: AlmaLinux 10(dnf/firewalld/SELinuxを利用)
  • 主なバージョン: Podman 5.8.2 / Docker 29.7.2
  • 1台のサーバに複数のdocker-compose環境が同居(Git管理ツール、チャットツールなど)
  • そのうち2つを同じサーバ上でPodmanに移行
  • 移行作業自体より、後半で遭遇した「原因不明の接続不可」に一番時間を取られました

小さなハマりどころ

1. podman-composeが入らない

$ dnf install -y podman podman-compose
No match for argument: podman-compose

素のリポジトリには無く、EPELが必要でした。

sudo dnf install -y epel-release
sudo dnf install -y podman-compose

2. イメージ名をいちいち聞かれる

podman-compose up すると、こんな対話プロンプトが出てきて止まります。

? Please select an image:
  ▸ registry.access.redhat.com/postgres:18
    registry.redhat.io/postgres:18
    docker.io/library/postgres:18

Dockerはデフォルトでdocker.io一択なので気にしたことがなかったのですが、AlmaLinuxをはじめとするRHEL系ディストリビューションのPodmanは/etc/containers/registries.confの既定設定でRedHat系レジストリも検索対象に入っています。そのためpostgres:18のように「レジストリ名を省略した書き方」だと毎回聞かれてしまいます。systemd経由で自動起動させると対話できず止まってしまうので、docker-compose.ymlのイメージ名はフルパス化しておくのが無難です。

image: docker.io/library/postgres:18

3. SELinuxでPermission denied

コンテナが Permission denied を吐いて起動しない。DockerからPodmanに変えて一番戸惑ったのがこれです。

chmod: changing permissions of '/var/lib/postgresql/18/docker': Permission denied

原因はSELinux。SELinuxが有効(enforcing)なホストでは、Podmanはbind mountに対してホスト側のSELinuxラベルをちゃんとチェックします。そのためdocker-compose.ymlをそのまま使い回すと、ラベル不一致で弾かれてしまいます。

volumes:
  - ./volumes/db:/var/lib/postgresql:z

:z を付けると、起動時にPodmanがラベルを付け替えてくれます。Dockerだと意識しなくても動いていた部分なので、地味に見落としがちです。

本題: 外部から繋がらない

コンテナは無事に立ち上がり、podman psの結果もUp。ローカルからcurlすると応答もある。なのに他のマシンからアクセスするとタイムアウト。

定番の切り分けを一通りやりました。

  • ポートはLISTENしている → OK
  • firewalldにポートは開いている → OK
  • カーネルのIPフォワーディングも有効 → OK

一通り確認しても「何も悪くないのに繋がらない」状態が続き、最終的にtcpdumpで切り分けました。

# 外部インターフェース側
sudo tcpdump -i eth0 -n port 8065
# → 他ホストからのSYNはちゃんと届いている

# Podmanのブリッジ側
sudo tcpdump -i podman1 -n port 8065
# → 何も出てこない

つまり「サーバには届いているが、コンテナまで転送されていない」。ここでnftablesのルールを一通り見ていくと、原因が見つかりました。

table ip filter {
    chain FORWARD {
        type filter hook forward priority filter; policy drop;
        ...
    }
}

これはDocker由来と思われるルールでした。docker compose downしても、Dockerサービス自体を停止しても、このテーブルは自動では削除されません。しかもFORWARDチェーンのデフォルトポリシーがdropになっており、docker0向けの通信だけを個別に許可する作りでした。そのため、Podmanのpodman1宛の通信は許可対象に入らず、まるごとドロップされていたのです。

補足: この環境はfirewalldがnftablesバックエンドで動作しており、Dockerがiptables-nft経由でルールを積んでいたと考えられます。iptables-legacyバックエンドや他のファイアウォール管理ツールを使っている環境では、テーブル名・チェーン名の見え方が異なります。

Podman側の設定自体は問題なく、原因はすでに役目を終えたはずのDocker由来と思われる残存設定でした。

対処はこうです。

sudo systemctl stop docker
sudo systemctl disable docker
sudo systemctl stop docker.socket
sudo systemctl disable docker.socket

sudo nft delete table ip filter
sudo nft delete table ip6 filter

削除後、問題なく疎通するようになりました。

最後の掃除

Dockerを完全に手放すにあたって、パッケージや/var/lib/dockerを消すだけでは終わりませんでした。

  • firewalldに残ったdockerゾーン・docker-forwardingポリシー
  • dockerグループ
  • Docker公式のdnfリポジトリ定義

firewalldのdockerゾーン・docker-forwardingポリシーは、本題で削除したnftablesルールと同じ仕組みに由来する可能性がありますが、そこまでは切り分けられていません。いずれにせよ、このあたりも棚卸しして削除し、Dockerの痕跡をひと通り無くしました。

まとめ

  • Podman移行でいちばん厄介だったのは「設定は合っているはずなのに繋がらない」パターン
  • 原因はPodmanでもコンテナでもなく、Docker由来と思われるnftablesルールの残存だった
  • SELinuxの:zやイメージ名のフルパス化など、Docker時代は意識しなくてよかった設定がいくつかある
  • ネットワーク周りで原因不明に陥ったら、tcpdumpでパケットが実際どこまで届いているか段階的に確認するのが結局一番早い
  • 別のランタイムに乗り換える際は、旧ランタイムがネットワーク層(iptables/nftables)に残す設定まで含めて洗い出す必要がある

同じようにDocker→Podman移行で困っている人の参考になれば幸いです。

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?