Fedora上のPodman Pod:Kubernetes-nativeアーキテクチャに基づくコンテナのグループ化とsystemdサービスの自動生成

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

複数のバラバラなコンテナを管理する際の問題

Podmanを使い始めた頃は、データベース、バックエンド、フロントエンドとそれぞれ別々にコンテナを起動していた。ちょっとしたテストにはそれで十分だったが、数日も経つと頭を抱える問題がいくつも出てきた。どのコンテナを先に起動すればいい?データベースが立ち上がる前にバックエンドが起動するとすぐにクラッシュする。全部止めたいときは一つずつstopしなければならない。コンテナ間のネットワークはブリッジを自分で設定し、内部DNSの名前も覚えておく必要がある。

Kubernetesのドキュメントを読んで初めて、なぜPodという概念が使われているのかがわかった――関連するコンテナをひとつの単位にまとめるためだ。Podmanは最初からPodをサポートしており、追加のプラグインもデーモンも不要だ。ローカル環境でKubernetesを学び始める際にDockerからPodmanに移行する人が多い理由も、ここにある。

なぜPodがこの問題を解決できるのか

Kubernetesのアーキテクチャでは、デプロイの最小単位はコンテナ単体ではなくPodだ。同じPod内のコンテナは以下を共有する:

  • 同じnetwork namespace――同じIP、同じloopbackインターフェース
  • 外部にポートを公開せずlocalhostで通信できる
  • ひとつのブロックとして一緒に起動・停止する
  • infra container(一時停止コンテナ)がnamespaceを保持する――Kubernetesと全く同じ仕組み

Docker Composeは仮想ネットワークと内部DNSでコンテナを繋ぐが、それはComposeの独自の抽象化であり、Kubernetesのモデルとは異なる。Podman PodはK8sが実際に使っているメカニズムをそのまま採用しているため、後でKubernetesのドキュメントを読んだときにネットワークやPodのライフサイクルが全く馴染みのない概念にならずに済む。

Podmanの準備を確認する

Fedoraを開発メイン機として2年ほど使っているが、パッケージの更新速度には満足している――Podmanはアップストリームのリリース直後に最新版が入ることが多い。現在のバージョンを確認する:

podman --version
podman info | grep -E "version|rootless"

インストールされていない場合やアップデートが必要な場合:

sudo dnf install -y podman

この記事はPodman 4.x以降を対象としている。Fedora 38以降ではデフォルトのリポジトリにPodman 4.xまたは5.xが含まれていることが多い。

実践例:WordPress + MariaDBをひとつのPodで動かす

理論の説明はこのくらいにして、具体的な例を見ていこう。WordPressとMariaDBを同じPod内で動かす。このユースケースは数分でセットアップできるほどシンプルだが、コンテナ単体との違いを明確に体感できる。

ステップ1 — Podの作成とポートの宣言

podman pod create \
  --name wordpress-pod \
  --publish 8080:80

注意:ポートマッピングはコンテナ作成時ではなく、Pod作成時に宣言する必要がある。Pod内のコンテナはPodのnetwork namespaceを共有しているため、外部へのポート公開はPodのみが担う――個々のコンテナは直接公開できない。

ステップ2 — MariaDBをPodに追加する

podman run -d \
  --pod wordpress-pod \
  --name mariadb \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=wordpress \
  -e MYSQL_USER=wpuser \
  -e MYSQL_PASSWORD=wppass \
  -v mariadb-data:/var/lib/mysql \
  docker.io/library/mariadb:10.11

ステップ3 — WordPressをPodに追加する

podman run -d \
  --pod wordpress-pod \
  --name wordpress \
  -e WORDPRESS_DB_HOST=127.0.0.1:3306 \
  -e WORDPRESS_DB_USER=wpuser \
  -e WORDPRESS_DB_PASSWORD=wppass \
  -e WORDPRESS_DB_NAME=wordpress \
  -v wordpress-data:/var/www/html \
  docker.io/library/wordpress:6.5

WORDPRESS_DB_HOST=127.0.0.1に注目してほしい。WordPressとMariaDBが同じPod内にいるため、localhostで自然に通信できる。Dockerの独立したネットワークを使う場合のようなサービスディスカバリーや内部DNSの設定は一切不要だ。

ステップ4 — Podの確認と管理

# Podの一覧を表示
podman pod ps

# Pod付きでコンテナを表示
podman ps --pod

# 各コンテナのログを確認
podman logs wordpress
podman logs mariadb

ブラウザでhttp://localhost:8080を開き、WordPressのセットアップ画面が表示されれば成功だ。次に、Podをひとつのまとまりとして管理してみよう:

# Pod全体を停止
podman pod stop wordpress-pod

# 再起動
podman pod start wordpress-pod

# リスタート
podman pod restart wordpress-pod

# Podと内部のコンテナをすべて削除
podman pod rm -f wordpress-pod

これが最も気に入っている点だ――コマンド一つでスタック全体を制御でき、コンテナの名前や停止順序を覚えておく必要がない。

podman generate systemdで自動化する

テスト時は手動でPodを動かしても問題ないが、再起動後に自動で再起動するサービスが必要な場合はsystemdを使う必要がある。podman generate systemdはunit fileを自動生成してくれる――手書きは不要だ。

既存のPodからsystemd unit fileを生成する

# unit fileを保存するディレクトリに移動
mkdir -p ~/.config/systemd/user/
cd ~/.config/systemd/user/

# unit fileを生成
podman generate systemd \
  --name \
  --files \
  --new \
  wordpress-pod

各フラグの説明:

  • --name:IDの代わりにコンテナ/Pod名を使用する(ログが読みやすくなる)
  • --files:stdoutに出力する代わりにファイルに書き込む
  • --new:起動のたびに既存のコンテナにアタッチする代わりにpodman runを実行する――新しいイメージへの更新に重要

このコマンドは3つのファイルを生成する:

  • pod-wordpress-pod.service――Podを管理し、コンテナをオーケストレーションする
  • container-mariadb.service――Podの準備完了後に起動する
  • container-wordpress.service――mariadbの後に起動する

rootlessサービスを有効化する(一般ユーザーで実行)

# 新しいunit fileを読み込むためsystemdをリロード
systemctl --user daemon-reload

# 自動起動を有効化
systemctl --user enable pod-wordpress-pod.service

# 今すぐ起動
systemctl --user start pod-wordpress-pod.service

# ステータスを確認
systemctl --user status pod-wordpress-pod.service

ログインしていなくてもサービスを動かす(Linger)

デフォルトでは、ユーザーのsystemdサービスはログイン中のみ動作する。SSHしなくても起動直後にPodが自動起動するようにするには:

sudo loginctl enable-linger $USER

# 確認
loginctl show-user $USER | grep Linger

このコマンドを実行すると、Podは本物のシステムサービスのように動作しながら、一般ユーザー権限で実行され続ける――rootで実行するよりもはるかに安全だ。

ベストプラクティス:Rootless Pod + Linger + 永続ボリューム

何度も試行錯誤した結果、Fedoraでの開発プロジェクトに最も安定して使えるワークフローはこれだ:

  1. 最初にnamed volumeを作成して、Podが削除・再作成されてもデータが残るようにする
  2. --newオプションでsystemdを生成する――再起動のたびに最新のイメージからコンテナを再作成することが保証される
  3. Lingerを有効にする――ログインセッションに依存しない
  4. 完全Rootless――podmanコマンドにsudoは一切不要

WordPressの新バージョンにアップデートする場合の例:

# 新しいイメージをPull
podman pull docker.io/library/wordpress:6.5

# リスタート――--newオプションにより、systemdが自動的に新しいイメージからコンテナを再作成する
systemctl --user restart pod-wordpress-pod.service

Fedora 40+とPodman 5.xを使っている場合の注意点

Podman 4.4以降、podman generate systemdコマンドはdeprecated(非推奨)とマークされており――Fedora 40+でPodman 5.xを使っている場合、この警告がより明確に表示される。公式の代替手段はQuadletだ:.container.podファイルを書けば、podman-system-generatorが自動的にsystemd unitに変換してくれる。Quadletは冗長性が低く、バージョン管理もしやすく、Podmanが長期的に公式推奨する方法だ。

ただし、podman generate systemdは依然として問題なく動作し、Quadletに移行する前に内部の仕組みを理解するための最速の方法でもある。generate systemdを先に理解しておくと、Quadletのファイルがずっと読みやすくなる――本質的なロジックは同じだからだ。

まとめ

最初にPodを使い始めたのは、全コンテナを一度に停止したいというシンプルな問題を解決するためだった。しかし本当のメリットはそこではなかった――追加設定なしでlocalhostを介した通信ができ、ライフサイクルが自動で同期され、podman generate systemdが再起動後の自動復旧まで面倒を見てくれる。rootlessで動き、sudoもデーモンも不要だ。Fedora上でこれまで使ってきた中で、最もシンプルでセキュアなコンテナワークフローだ。

Share: