- Authors
- Name
- 1. はじめに:Dockerの光と影、そしてPodmanへの転換
- 2. [革新1] デーモンレスアーキテクチャ:単一障害点の終焉
- 3. [革新2] ルートレスセキュリティ:権限のパラダイムシフト
- 4. [革新3] play kube:「開発と運用の言語を統一する」
- 5. [革新4] Podネイティブ管理:真のPod Manager
- 6. [革新5] Pastaネットワーキング:NATフリーのルートレスネットワーキング
- 7. Podman Desktop:GUIによるPodmanのフルエクスペリエンス
- 8. DockerからPodmanへ:実践的マイグレーションガイド
- 9. Podman vs Docker:総合比較
- 10. まとめ:コンテナの未来は引き算にある
- 11. 参考文献
- クイズ
1. はじめに:Dockerの光と影、そしてPodmanへの転換
1.1 Dockerが変えた世界
2013年、dotCloudのSolomon HykesがPyConで行った5分間のデモは、ソフトウェア業界の地図を完全に塗り替えました。 開発者の永遠の言い訳「自分のマシンでは動くのに」を歴史のゴミ箱に送りました。 DockerはLinuxコンテナ(LXC)を誰もが使えるものにし、イメージレイヤリング、Dockerfile、Docker Hubの三位一体で、 コンテナエコシステムのデファクトスタンダードとなりました。
しかし、すべての独占的な標準には構造的な脆弱性が伴います。
1.2 Docker Desktopライセンス変更の転機
2021年8月、Docker Inc.はDocker Desktopのライセンスポリシーを変更しました。 従業員250名以上または年間売上1,000万ドル超の企業は有料サブスクリプション(Pro、Team、Business)が必要になりました。 この変更は単なる価格政策を超えた意味を持ちます:
- サプライチェーン依存性:重要な開発ツールが単一ベンダーのライセンスポリシーに依存する事態に
- コンプライアンスリスク:無断使用は法的リスクを生む
- 代替手段の模索が加速:Red Hat、SUSE、Googleなどが代替エコシステムへの投資を強化
1.3 ソフトウェアサプライチェーンセキュリティの必須化
2020年のSolarWindsハッキング、2021年のLog4Shell、2024年のXZ Utilsバックドアに至るまで、 ソフトウェアサプライチェーンセキュリティは選択ではなく必須となりました。 コンテナランタイムはこのサプライチェーンの最下層に位置し、そのセキュリティモデルがスタック全体の信頼基盤を決定します。
root権限で動作するDockerデーモンは、この文脈において根本的な再評価の対象となりました。
1.4 Podmanへの転換
この3つのトレンド、すなわちライセンスリスク、サプライチェーンセキュリティ、アーキテクチャ上の限界の交差点に、 Red Hatが主導しオープンソースコミュニティと共に構築したPodmanが台頭しています。
Podmanは単なる「Dockerの代替」ではありません。コンテナ技術の根本的な前提を再設計するプロジェクトです。 2026年現在、Podman 5.xシリーズはTLS/mTLSベースのリモート接続暗号化、OCI Artifact管理の安定化、 macOS Hypervisor Frameworkのネイティブ統合、podman farm buildによるマルチプラットフォームビルドをサポートし、 エンタープライズ級のコンテナプラットフォームとして成熟しています。
本記事ではアーキテクトの視点から、Podmanがもたらす5つの根本的な革新を徹底分析します:
| 革新 | 主要テーマ | 解決する課題 |
|---|---|---|
| 革新1 | デーモンレスアーキテクチャ | 単一障害点(SPOF)の排除 |
| 革新2 | ルートレスセキュリティ | コンテナエスケープリスクの根絶 |
| 革新3 | play kube | 開発/運用の言語二重性の解消 |
| 革新4 | Podネイティブ管理 | Kubernetesネイティブワークフロー |
| 革新5 | Pastaネットワーキング | NATオーバーヘッドの除去、性能向上 |
2. [革新1] デーモンレスアーキテクチャ:単一障害点の終焉
2.1 Dockerデーモンの構造的問題
Dockerのアーキテクチャを理解するには、中心に位置するdockerd(Dockerデーモン)を理解する必要があります。 すべてのDocker CLIコマンドはREST APIを通じてdockerdに渡され、dockerdはcontainerdを呼び出し、 containerdがruncを通じて実際のコンテナを作成します。
+-------------------------------------------------------------+
| Docker Architecture (Client-Server) |
| |
| +----------+ REST API +------------------------+ |
| | docker | ----------------->| dockerd | |
| | CLI | /var/run/ | (Docker Daemon) | |
| +----------+ docker.sock | +------------------+ | |
| | | containerd | | |
| +----------+ REST API | | +------------+ | | |
| | docker | ----------------->| | | runc | | | |
| | CLI | /var/run/ | | +------------+ | | |
| +----------+ docker.sock | +------------------+ | |
| | | |
| +----------+ REST API | +-----+ +-----+ | |
| | docker | ----------------->| | C1 | | C2 | ... | |
| | CLI | | +-----+ +-----+ | |
| +----------+ +------------------------+ |
| ^ |
| | |
| * Single Point of Failure * |
| dockerdが停止すると |
| 全コンテナ管理が不能に |
+-------------------------------------------------------------+
この構造の3つの核心的問題:
第一に、単一障害点(SPOF):dockerdが異常終了すると、実行中の全コンテナの管理が不可能になります。 コンテナ自体は動き続けますが、ログ収集、ヘルスチェック、リソース制限変更などのすべての管理機能が完全に失われます。
第二に、root権限の必要性:dockerdはデフォルトでroot権限で動作します。 /var/run/docker.sockにアクセスできるユーザーは事実上root相当の権限を持ちます。 これは典型的な権限昇格攻撃ベクトルです。
第三に、リソースオーバーヘッド:コンテナが一つも動いていない状態でも、 dockerdとcontainerdがスタンバイ状態でメモリを占有します。
2.2 PodmanのFork-Execモデル
Podmanはデーモンを完全に排除することで、これらすべての問題を解決しました。Podmanという名前自体がPod Managerの略であり、 根本的に異なる哲学に基づいたアーキテクチャで構築されています。
+-------------------------------------------------------------+
| Podman Architecture (Daemonless Fork-Exec) |
| |
| +----------+ fork/exec +-------+ +--------------+ |
| | podman | -------------->| conmon |--->| Container 1 | |
| | CLI | +-------+ +--------------+ |
| +----------+ |
| | |
| | fork/exec +-------+ +--------------+ |
| +--------------------->| conmon |--->| Container 2 | |
| | +-------+ +--------------+ |
| | |
| | fork/exec +-------+ +--------------+ |
| +--------------------->| conmon |--->| Container 3 | |
| +-------+ +--------------+ |
| |
| * デーモンなし:各コンテナは独立したプロセス |
| * Podman CLIの終了はコンテナに影響しない |
| * conmon:軽量コンテナモニター(ログ、終了コード) |
| * OCI ランタイム(crun/runc)の直接呼び出し |
+-------------------------------------------------------------+
Podmanがコンテナを実行する際のプロセスフロー:
- ユーザーが
podman runを実行 - Podman CLIがOCIランタイム(デフォルト:
crun、またはrunc)を直接fork/exec conmon(Container Monitor)が作成され、コンテナプロセスのstdout/stderrと終了コードを管理- Podman CLIプロセスは役割を終えて終了
- コンテナは独立したプロセスとして動作を継続
"最良のデーモンとは、デーモンが存在しないことだ。Podmanはコンテナ管理に 特権を持つ常駐サービスは不要であり、やるべき仕事をして退場するツールが 必要であることを証明した。" — Dan Walsh, Red Hat コンテナセキュリティアーキテクト
2.3 systemd統合:コンテナをOSの第一級市民に
Podmanのデーモンレスアーキテクチャが持つ最も強力な利点の一つは、systemdとの自然な統合です。 Dockerではdockerdという別のサービスマネージャーがコンテナのライフサイクルを管理していましたが、 PodmanではLinuxのPID 1であるsystemdが直接コンテナを管理します。
これはコンテナがOSの第一級市民に昇格したことを意味します:
- 自動起動:システムブート時にコンテナが自動的に起動
- 依存関係管理:systemdの依存関係グラフを活用し
After=network-online.targetなどで制御 - ログ統合:
journalctlでコンテナログを統合表示 - リソース管理:systemd cgroupスライスによるリソース割り当て
- ヘルスチェック:
WatchdogSec=に基づく精密なヘルス監視
# /etc/containers/systemd/webapp.container (Quadlet形式)
[Unit]
Description=Production Web Application
After=network-online.target
Wants=network-online.target
[Container]
Image=registry.example.com/webapp:v2.1.0
PublishPort=8080:8080
Environment=NODE_ENV=production
Environment=DB_HOST=db.internal
Volume=/data/webapp:/app/data:Z
Network=webapp.network
AutoUpdate=registry
HealthCmd=/bin/curl -f http://localhost:8080/health || exit 1
HealthInterval=30s
HealthRetries=3
HealthStartPeriod=10s
[Service]
Restart=always
RestartSec=5
TimeoutStartSec=120
WatchdogSec=60
[Install]
WantedBy=multi-user.target default.target
2.4 Quadlet:systemdネイティブコンテナ管理の決定版
Podman 4.4で導入されたQuadletは、コンテナをsystemdユニットファイルの拡張として定義する革新的なアプローチです。 レガシーのpodman generate systemdが生成する長いコマンドラインの代わりに、 .container、.volume、.network、.pod、.kube、.build拡張子の宣言的ユニットファイルでコンテナを管理します。
Quadletの主な利点:
| カテゴリ | レガシー(generate systemd) | Quadlet |
|---|---|---|
| ファイル形式 | 自動生成された長いExecStart | 宣言的な.containerファイル |
| メンテナンス | イメージ更新時に再生成が必要 | 宣言的な編集 + daemon-reload |
| 可読性 | すべてのオプションが1コマンドライン | セクション別に構造化 |
| ファイル配置(root) | /etc/systemd/system/ | /etc/containers/systemd/ |
| ファイル配置(rootless) | ~/.config/systemd/user/ | ~/.config/containers/systemd/ |
マルチコンテナスタックの例 -- データベースとアプリケーション:
# ~/.config/containers/systemd/app-network.network
[Network]
Subnet=10.89.1.0/24
Gateway=10.89.1.1
# ~/.config/containers/systemd/postgres.container
[Unit]
Description=PostgreSQL Database
[Container]
Image=docker.io/library/postgres:16-alpine
Volume=pgdata.volume:/var/lib/postgresql/data:Z
Network=app-network.network
Environment=POSTGRES_DB=appdb
Environment=POSTGRES_USER=appuser
Secret=pg-password,type=env,target=POSTGRES_PASSWORD
HealthCmd=pg_isready -U appuser
HealthInterval=10s
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.target
# ~/.config/containers/systemd/pgdata.volume
[Volume]
# Quadletの適用
systemctl --user daemon-reload
# サービス起動
systemctl --user start postgres.service
# ステータス確認
systemctl --user status postgres.service
# ログ表示
journalctl --user -u postgres.service -f
Quadletはコンテナ管理における**Infrastructure as Code(IaC)**の精神を完璧に体現しています。 AnsibleやTerraformなどのツールで.containerファイルをデプロイすれば、別途のコンテナオーケストレータなしに、 systemd自体がコンテナオーケストレータになります。
3. [革新2] ルートレスセキュリティ:権限のパラダイムシフト
3.1 コンテナエスケープ:rootが危険な理由
Dockerのデフォルト実行モデルでは、コンテナ内のroot(UID 0)がホストのroot(UID 0)と同じUIDを共有しています。 もちろんLinux Capabilities、seccomp、AppArmor/SELinuxなどのセキュリティレイヤーで制限されていますが、 カーネルの脆弱性が発見されるたびにこれらの制限をバイパスされる可能性があります。
注目すべきコンテナエスケープ事例:
| CVE | 脆弱性 | 影響 |
|---|---|---|
| CVE-2019-5736 | runcの脆弱性 | コンテナからホストのruncバイナリを上書き |
| CVE-2020-15257 | containerd Shim API | ホストネットワーク名前空間にアクセス |
| CVE-2022-0185 | カーネルヒープオーバーフロー | 非特権コンテナからホストrootを取得 |
| CVE-2024-21626 | runcファイルディスクリプタリーク | コンテナからホストファイルシステムにアクセス |
これらの脆弱性に共通するのは、コンテナプロセスがホスト上でroot権限で動作するという前提を悪用している点です。
3.2 User NamespaceとUIDマッピング:Podmanの解答
PodmanのルートレスモードはLinux User Namespaceを使用して、この前提を完全に無効化します。 核心的な原理はシンプルです:コンテナ内のUID 0(root)をホスト上の非特権UIDにマッピングします。
+-------------------------------------------------------------+
| User Namespace UIDマッピング図 |
| |
| +---------------------+ +---------------------------+ |
| | コンテナ内部 | | ホストシステム | |
| | (User Namespace) | | | |
| | | | | |
| | UID 0 (root) ----+------+--> UID 1000 (youruser) | |
| | UID 1 ----+------+--> UID 100000 | |
| | UID 2 ----+------+--> UID 100001 | |
| | UID 3 ----+------+--> UID 100002 | |
| | ... | | ... | |
| | UID 65535 ----+------+--> UID 165535 | |
| | | | | |
| +---------------------+ +---------------------------+ |
| |
| * コンテナのrootがエスケープしてもホスト上ではUID 1000 |
| * 非特権ユーザー -> システムファイルへのアクセス不可 |
| * カーネルエクスプロイトの影響範囲が大幅に縮小 |
+-------------------------------------------------------------+
このマッピングは/etc/subuidと/etc/subgidファイルで設定されます:
# /etc/subuid - ユーザーごとの従属UID範囲
youruser:100000:65536
# /etc/subgid - ユーザーごとの従属GID範囲
youruser:100000:65536
# 意味:youruserはUID 100000から65536個のUIDを使用可能
実際のマッピングを確認する方法:
# ルートレスモードでコンテナを実行
podman run -d --name test-rootless alpine sleep 3600
# コンテナ内のUIDを確認
podman exec test-rootless id
# uid=0(root) gid=0(root) <- コンテナ内ではrootに見える
# ホスト上の実際のUIDを確認
podman top test-rootless huser
# HUSER
# 1000 <- ホスト上では一般ユーザー(UID 1000)
3.3 User Namespaceモード:きめ細かなセキュリティ制御
Podmanは--usernsオプションを通じて多様なUser Namespaceモードをサポートしています:
| モード | 説明 | 用途 |
|---|---|---|
auto | 自動UID/GID範囲割り当て(デフォルト) | 一般的なルートレスコンテナ |
keep-id | ホストユーザーのUIDをコンテナ内でそのまま維持 | バインドマウントのファイル権限維持 |
nomap | ホストユーザーのUIDをコンテナにマッピングしない | 最大限のセキュリティ分離 |
host | User Namespaceを無効化 | レガシー互換性(非推奨) |
# keep-idモード:ホストUIDをコンテナ内で維持
# -> バインドマウントしたファイルの所有権問題を解決
podman run --userns=keep-id -v $HOME/project:/workspace:Z \
-it node:20-alpine sh
# nomapモード:ホストユーザーのUIDを一切マッピングしない
# -> コンテナはホストユーザー所有のファイルにアクセス不可(world権限を除く)
podman run --userns=nomap alpine cat /proc/self/uid_map
3.4 コンプライアンス:PCI-DSS、FedRAMP、NIST規制への準拠
ルートレスコンテナは技術的改善を超えて、コンプライアンス面で決定的な優位性を提供します:
PCI-DSS v4.0(Payment Card Industry Data Security Standard):
- 要件7.2:「最小権限の原則に従いシステムコンポーネントへのアクセスを制限する」
- ルートレスコンテナはroot権限なしで動作し、この要件を構造的に満たす
FedRAMP(Federal Risk and Authorization Management Program):
- AC-6(最小権限):「システム機能に必要な最小限の権限のみを付与する」
- Podmanのルートレスモードはこの管理策の技術的実装そのもの
NIST SP 800-190(Application Container Security Guide):
- 「ホストOSへのリスクを低減するため、コンテナを非rootユーザーで実行する」
- Podmanはこれをデフォルト動作として実装
Linux Capabilities比較 -- Docker vs Podman:
Podmanはデフォルトでコンテナに11個のカーネルCapabilitiesのみを付与し、Dockerの14個より少なくなっています。 これは最小権限の原則の具体的な実装です:
# PodmanのデフォルトCapabilitiesを確認
podman run --rm alpine grep Cap /proc/1/status
# CapBnd: 00000000a80425fb
# DockerのデフォルトCapabilitiesを確認
docker run --rm alpine grep Cap /proc/1/status
# CapBnd: 00000000a80435fb
# -> DockerはCapabilitiesが多い(NET_RAWなどを含む)
セキュリティアーキテクトの原則:「セキュリティとは追加することではなく、不要なものを取り除くことだ。」 Podmanのルートレスモデルはこの原則の教科書的な実装です。
4. [革新3] play kube:「開発と運用の言語を統一する」
4.1 Docker Compose vs Kubernetes YAML:二重性の苦痛
開発者がクラウドネイティブ環境で直面する最も一般的な摩擦の一つは、 ローカル開発と本番デプロイの言語が異なることです。
+-------------------------------------------------------------+
| 開発/運用の言語二重性問題 |
| |
| 開発者のラップトップ 本番クラスター |
| +-------------------+ +--------------------+ |
| | docker-compose.yml| | deployment.yaml | |
| | | -------> | service.yaml | |
| | version: "3.8" | 変換 | configmap.yaml | |
| | services: | が必要 | ingress.yaml | |
| | web: | | | |
| | image: app | | apiVersion: apps/v1| |
| | ports: | | kind: Deployment | |
| | - "8080:80" | | spec: | |
| +-------------------+ | replicas: 3 | |
| +--------------------+ |
| |
| * 2つの構文、2つのツール、2倍の学習コスト |
| * 微妙な変換差異によるデプロイ失敗 |
| * 「自分のラップトップでは動いたのに…」の新たな変種 |
+-------------------------------------------------------------+
KomposeやDocker Compose to Kubernetesコンバーターなどのツールが存在しますが、 それらは問題の上にさらにレイヤーを追加しているだけで、根本的な解決策ではありません。
4.2 play kube:Kubernetes YAMLをローカルで実行
Podmanのplay kube(旧podman play kube、現podman kube play)はこの二重性を根本から排除します。 Kubernetes YAMLファイルをローカルのPodman環境でそのまま実行します。
サポートされるKubernetesリソースタイプ:
- Pod
- Deployment
- DaemonSet
- ConfigMap
- Secret
- PersistentVolumeClaim
ステップバイステップ:play kubeでマイクロサービススタックを実行
ステップ1 -- Kubernetes YAMLを作成(microservices-stack.yaml):
# microservices-stack.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: 'postgres'
DATABASE_PORT: '5432'
DATABASE_NAME: 'appdb'
APP_LOG_LEVEL: 'info'
---
apiVersion: v1
kind: Pod
metadata:
name: microservices
labels:
app: microservices-stack
environment: development
spec:
# Initコンテナ:データベースマイグレーション
initContainers:
- name: db-migration
image: docker.io/library/flyway/flyway:10
command: ['flyway', 'migrate']
env:
- name: FLYWAY_URL
value: 'jdbc:postgresql://localhost:5432/appdb'
- name: FLYWAY_USER
value: 'appuser'
- name: FLYWAY_PASSWORD
value: 'secret123'
volumeMounts:
- name: migration-scripts
mountPath: /flyway/sql
containers:
# データベース
- name: postgres
image: docker.io/library/postgres:16-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: 'appdb'
- name: POSTGRES_USER
value: 'appuser'
- name: POSTGRES_PASSWORD
value: 'secret123'
volumeMounts:
- name: pgdata
mountPath: /var/lib/postgresql/data
# APIサーバー
- name: api-server
image: docker.io/library/node:20-alpine
ports:
- containerPort: 3000
hostPort: 3000
env:
- name: DATABASE_HOST
value: 'localhost'
- name: DATABASE_PORT
value: '5432'
command: ['node', 'server.js']
volumeMounts:
- name: app-source
mountPath: /app
# Redisキャッシュ
- name: redis
image: docker.io/library/redis:7-alpine
ports:
- containerPort: 6379
command: ['redis-server', '--maxmemory', '256mb']
volumes:
- name: pgdata
persistentVolumeClaim:
claimName: pgdata-pvc
- name: migration-scripts
hostPath:
path: ./migrations
- name: app-source
hostPath:
path: ./src
ステップ2 -- スタックを実行:
# YAMLファイルからスタック全体を作成
podman kube play microservices-stack.yaml
# 実行状態を確認
podman pod ps
# POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
# a1b2c3d4e5f6 microservices Running 10 seconds ago 9f8e7d6c5b4a 4
# 個別コンテナを確認
podman ps --pod
# CONTAINER ID IMAGE STATUS POD ID NAMES
# ... docker.io/library/postgres:16 Up 10 seconds a1b2c3d4e5f6 microservices-postgres
# ... docker.io/library/node:20 Up 8 seconds a1b2c3d4e5f6 microservices-api-server
# ... docker.io/library/redis:7 Up 8 seconds a1b2c3d4e5f6 microservices-redis
# APIサーバーのログを確認
podman logs microservices-api-server
ステップ3 -- スタックを破棄:
# --downフラグでスタック全体を破棄・クリーンアップ
podman kube play --down microservices-stack.yaml
# 確認
podman pod ps
# (空 - すべてのリソースがクリーンアップ済み)
4.3 コンベンションベースのイメージビルド
play kubeの隠れた強力な機能の一つはコンベンションベースの自動イメージビルドです。 YAML内で参照されるイメージと同名のディレクトリが現在のパスに存在し、 その中にContainerfileまたはDockerfileがある場合、自動的にビルドされます。
プロジェクトディレクトリ構造:
+-- my-stack.yaml <- image: my-api を参照
+-- my-api/ <- 自動ビルド対象
| +-- Containerfile
| +-- src/
| +-- server.js
+-- my-frontend/ <- image: my-frontend を参照
+-- Containerfile
+-- dist/
+-- index.html
# --buildフラグでイメージ自動ビルド + 実行
podman kube play --build my-stack.yaml
# 既にビルド済みのイメージを置換(強制ビルド)
podman kube play --replace --build my-stack.yaml
この機能によりCI/CDパイプラインとローカル開発環境を同じYAMLで実行でき、 Podmanのビジョン「Develop locally, deploy globally」を実現します。
4.4 Initコンテナ:alwaysとonce
PodmanはKubernetesのInitコンテナ概念をローカルで忠実に実装しています。 Podman独自のalwaysとonceタイプの区別は実務で特に有用です:
| タイプ | 動作 | 用途 |
|---|---|---|
once(デフォルト) | Pod起動時に一度だけ実行され削除される | DBマイグレーション、シークレット初期化 |
always | Pod起動のたびに毎回実行される(削除されない) | ヘルスチェック待機、設定リフレッシュ |
# Initコンテナタイプの指定(Podmanアノテーション)
metadata:
annotations:
io.podman.annotations.init.container.type/wait-for-db: 'always'
spec:
initContainers:
- name: wait-for-db
image: docker.io/library/busybox:latest
command:
['sh', '-c', 'until nc -z localhost 5432; do echo "Waiting for DB..."; sleep 2; done']
alwaysタイプのInitコンテナはpodman kube generateの出力にも含まれるため、 ローカルで検証した初期化ロジックをそのままKubernetesクラスターに持ち込めます。
5. [革新4] Podネイティブ管理:真のPod Manager
5.1 Podmanの本質:Podを管理するツール
Podmanの名前はPod Managerに由来します。 これは単なる巧みなネーミングではなく、KubernetesのPod概念をローカル環境で第一級市民として実装するという設計意図を表しています。
Dockerでは複数のコンテナを一緒に実行するにはDocker Composeという別のツールが必要でしたが、 PodmanではPodが組み込み機能です。
+-------------------------------------------------------------+
| Podman Podアーキテクチャ |
| |
| +--- Pod ------------------------------------------------+ |
| | | |
| | +----------+ | |
| | | Infra | <- pauseコンテナ | |
| | |Container | <- ネットワーク名前空間のオーナー | |
| | | (pause) | <- Podライフサイクルのアンカー | |
| | +----------+ | |
| | | | |
| | |-- 共有: Network Namespace | |
| | |-- 共有: IPC Namespace | |
| | |-- 共有: UTS Namespace (hostname) | |
| | | | |
| | +----------+ +----------+ +----------+ | |
| | | App | | Sidecar | | Logging | | |
| | |Container | | (envoy) | | (fluentd)| | |
| | | | | | | | | |
| | | :8080 | | :15001 | | :24224 | | |
| | +----------+ +----------+ +----------+ | |
| | | |
| | * 全コンテナがlocalhostで通信 | |
| | * Kubernetes Podと同じネットワークモデル | |
| +--------------------------------------------------------+ |
| |
+-------------------------------------------------------------+
Podman Podの主な特徴:
- Infraコンテナ:KubernetesのPauseコンテナと同じ役割。ネットワーク名前空間を所有し、Pod内の全コンテナで共有
- localhost通信:Pod内のコンテナは
localhost(127.0.0.1)で通信 - 名前空間の共有:Network、IPC、UTS名前空間がデフォルトで共有
- 一括管理:
podman pod start/stop/rmによるPodレベルのライフサイクル管理
5.2 サイドカーパターンの実装
クラウドネイティブアーキテクチャで最も広く使われるサイドカーパターンは、 Podman Podを使ってローカルで完璧に実装できます:
# 1. Podを作成(ポートマッピングはPodレベルで設定)
podman pod create --name my-app \
--publish 8080:8080 \
--publish 9090:9090
# 2. メインアプリケーションコンテナ
podman run -d --pod my-app \
--name app-main \
my-registry.io/my-app:v1.0
# 3. サイドカー:Envoyプロキシ
podman run -d --pod my-app \
--name app-envoy \
docker.io/envoyproxy/envoy:v1.31
# 4. サイドカー:ログコレクター
podman run -d --pod my-app \
--name app-logger \
docker.io/fluent/fluentd:v1.17
# 5. サイドカー:メトリクスコレクター
podman run -d --pod my-app \
--name app-metrics \
docker.io/prom/node-exporter:v1.8
# Podのステータスを確認
podman pod inspect my-app
このパターンにより、Kubernetes向けのサービスメッシュ構成(Envoy + アプリ + ロギング)を ローカル開発環境で同じネットワークトポロジーでテストできます。
5.3 generate kube:ローカルからクラスターへの橋渡し
Podmanのgenerate kube(現podman kube generate)は、 ローカルで実行中のコンテナやPodをKubernetes YAMLにエクスポートする逆方向のワークフローをサポートしています。
完全なワークフロー例:
# ステップ1:ローカルでPodを構成
podman pod create --name webapp --publish 8080:80
podman run -d --pod webapp \
--name webapp-nginx \
-v ./html:/usr/share/nginx/html:Z \
docker.io/library/nginx:alpine
podman run -d --pod webapp \
--name webapp-redis \
docker.io/library/redis:7-alpine
# ステップ2:Kubernetes YAMLを生成
podman kube generate webapp -f webapp-k8s.yaml
# ステップ3:生成されたYAMLを確認
cat webapp-k8s.yaml
生成されたYAMLの例:
# webapp-k8s.yaml (podman kube generateにより自動生成)
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: '2026-03-01T09:00:00Z'
labels:
app: webapp
name: webapp
spec:
containers:
- name: webapp-nginx
image: docker.io/library/nginx:alpine
ports:
- containerPort: 80
hostPort: 8080
protocol: TCP
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html-host
- name: webapp-redis
image: docker.io/library/redis:7-alpine
volumes:
- name: html-host
hostPath:
path: /home/user/project/html
type: Directory
# ステップ4:生成されたYAMLをKubernetesクラスターに適用
kubectl apply -f webapp-k8s.yaml
# または別のPodmanホストで同じYAMLを実行
podman kube play webapp-k8s.yaml
generate kubeの追加オプション:
# Serviceオブジェクトも一緒に生成
podman kube generate -s webapp -f webapp-with-service.yaml
# Deploymentタイプで生成(レプリカ数指定)
podman kube generate --type deployment --replicas 3 webapp
# DaemonSetやJobタイプでも生成可能
podman kube generate --type job webapp
この双方向ワークフロー(play kube <-> generate kube)は、 「Develop locally, deploy globally」を技術的に可能にするPodmanの核心的な革新です:
+-----------------------------------------------------------+
| Podman <-> Kubernetes 双方向ワークフロー |
| |
| ローカル開発 Kubernetesクラスター |
| +---------+ +-------------+ |
| | podman | podman kube generate| kubectl | |
| | pod | --------------------->| apply -f | |
| | create | | | |
| | + run | podman kube play | Deployment | |
| | | <---------------------| export | |
| +---------+ +-------------+ |
| |
| * 同じYAML、同じセマンティクス |
| * 環境間の変換が不要 |
+-----------------------------------------------------------+
6. [革新5] Pastaネットワーキング:NATフリーのルートレスネットワーキング
6.1 ルートレスネットワーキングのジレンマ
ルートレスコンテナの最大の技術的課題の一つはネットワーキングです。 一般ユーザーにはネットワークインターフェースの作成やiptablesルールの操作の権限がありません。 Podmanがこの問題を解決するために最初に採用した技術がslirp4netnsでした。
slirp4netnsの動作原理:
slirp4netnsはユーザー空間でTCP/IPスタックをエミュレートします。 コンテナからのすべてのネットワークトラフィックは次のパスを辿ります:
Container -> TAPデバイス -> slirp4netns (ユーザー空間NAT) -> ホストネットワーク
このアプローチは動作しますが、すべてのパケットがユーザー空間でNAT変換されるため、 大きなレイテンシとCPUオーバーヘッドが発生します。
6.2 Pasta:パラダイムシフト
Pasta(Pack A Subtle Tap Abstraction)はpasstプロジェクトの一部であり、 slirp4netnsのNATベースのアプローチをL2-L4ソケットマッピングに置き換えた次世代ルートレスネットワーキングソリューションです。
Podman 5.0からデフォルトのルートレスネットワークドライバーとして採用され、 RHEL 9.5でもデフォルトに設定されています。
+-------------------------------------------------------------+
| slirp4netns vs Pasta アーキテクチャ比較 |
| |
| +- slirp4netns (レガシー) ---------------------------------+|
| | ||
| | コンテナ ユーザー空間 ホスト ||
| | +-------+ +------------------+ +----------+ ||
| | | eth0 |--->| slirp4netns |--->| Host | ||
| | | (TAP) | | +------------+ | | Network | ||
| | +-------+ | | ユーザー空間| | +----------+ ||
| | | | TCP/IP | | ||
| | | | + NAT | | <- 全パケットNAT処理||
| | | +------------+ | <- CPUオーバーヘッド大||
| | +------------------+ ||
| +----------------------------------------------------------+|
| |
| +- Pasta (Podman 5.0+デフォルト) --------------------------+|
| | ||
| | コンテナ カーネル空間 ホスト ||
| | +-------+ +------------------+ +----------+ ||
| | | eth0 |--->| L2->L4ソケット |--->| Host | ||
| | | (TAP) | | マッピング | | Network | ||
| | +-------+ | +------------+ | | cfg copy | ||
| | | | splice(2) | | +----------+ ||
| | | | sendmmsg() | | ||
| | | | recvmmsg() | | ||
| | | +------------+ | <- NATなし ||
| | +------------------+ <- 直接ソケット転送 ||
| +----------------------------------------------------------+|
| |
+-------------------------------------------------------------+
Pastaの核心的技術革新:
- ホストネットワーク設定のコピー:ホストのネットワーク設定をコンテナ名前空間に直接コピーし、NAT自体を不要にする
- L2-L4ソケットマッピング:Layer-2 TAPインターフェースのパケットをLayer-4ソケット(TCP/UDP/ICMP)に直接マッピング
- splice(2)システムコール:カーネルの
splice(2)システムコールを使用しローカル接続でゼロコピーデータ転送 - recvmmsg/sendmmsg最適化:単一のシステムコールで複数パケットを処理し、syscallオーバーヘッドを削減
- Tap Bypassパス:ローカルアドレス宛のパケットはL2変換をスキップし、L4ソケット間で直接転送
6.3 性能比較:slirp4netns vs Pasta
| メトリック | slirp4netns | Pasta | 改善率 |
|---|---|---|---|
| コンテナ起動時間 | 約1.2秒 | 約0.8秒 | 33%高速 |
| メモリ使用量 | 約100MB | 約85MB | 15%削減 |
| TCPスループット(1接続) | ベースライン | +15-30% | 大幅改善 |
| TCPレイテンシ(p50) | ベースライン | -20-40% | 大幅改善 |
| UDPスループット | ベースライン | +10-20% | 改善 |
| 並列接続(8以下) | ベースライン | 優位 | Pastaが勝利 |
| 並列接続(8超) | 優位 | ベースライン | slirp4netnsが勝利* |
| CPUオーバーヘッド(アイドル) | 高い | 低い | 大幅改善 |
*注:高並列シナリオ(並列数8超)では、slirp4netnsの方が良い性能を示す場合があります。 これはPastaのソケットマッピング方式が極度の高並列時に競合を起こす可能性があるためです。 ただし、一般的な開発環境やほとんどの本番ワークロードでは、Pastaが全般的に優位です。
6.4 Pastaネットワーキングの設定と使用
# PastaはPodman 5.0+でデフォルト
# 明示的に指定する場合:
podman run --network=pasta -d nginx
# slirp4netnsにフォールバックする場合:
podman run --network=slirp4netns -d nginx
# Pastaポートフォワーディング(特定ポートのみ公開)
podman run --network=pasta:-T,8080,-U,5353 -d my-app
# Pastaネットワーキングのステータス確認
podman inspect --format '{{.HostConfig.NetworkMode}}' <container>
6.5 ネットワークモード選択ガイド
| シナリオ | 推奨ネットワークモード | 理由 |
|---|---|---|
| 一般的なルートレス開発 | pasta(デフォルト) | 性能/互換性の最適なバランス |
| レガシー互換性が必要 | slirp4netns | 古いカーネルでも安定 |
| rootコンテナ | bridge(CNI/netavark) | rootモードの伝統的なブリッジ |
| ホストネットワークへの直接アクセス | host | ネットワーク分離が不要な場合 |
| Pod内のコンテナ間通信 | pod共有名前空間 | localhost通信 |
7. Podman Desktop:GUIによるPodmanのフルエクスペリエンス
7.1 Podman Desktopの概要
2025年はPodman Desktopにとって決定的な年でした。300万ダウンロードを突破し、 Docker Desktopの代替としての地位を確立しました。 2026年1月にはCNCF(Cloud Native Computing Foundation)プロジェクトとしても登録されました。
Podman Desktopの主な機能:
| 機能 | 説明 |
|---|---|
| コンテナ管理 | 作成、起動、停止、削除、ログ表示、ターミナルアクセス |
| イメージ管理 | ビルド、プル、プッシュ、検索、プルーン(不要イメージ削除) |
| Pod管理 | Pod作成、Kubernetes YAMLデプロイ、Podログ検索 |
| ボリューム/ネットワーク | ボリューム作成/削除、ネットワーク可視化と管理 |
| Kubernetes統合 | Kind、Minikube、OpenShiftクラスター統合 |
| エクステンション | BootC、Headlamp、AI Labエクステンション |
| Composeサポート | Docker Composeファイル互換実行 |
| ダッシュボードカスタマイズ | ウィジェット配置、テーブル列カスタマイズ |
7.2 エンタープライズPodman Desktop
Red Hatはエンタープライズ環境向けに機能を強化したRed Hat build of Podman Desktopをリリースしています:
- フリートワイド設定:レジストリミラー、HTTPプロキシなどの組織レベルの設定管理
- OpenShift統合:OpenShiftクラスターへの直接デプロイサポート
- BootCワークフロー:コンテナからブータブルOSイメージへの変換
- セキュリティポリシー適用:企業セキュリティ基準に準拠したデフォルト設定のデプロイ
8. DockerからPodmanへ:実践的マイグレーションガイド
8.1 マイグレーションが簡単な理由
PodmanはDocker CLIとのコマンドレベルの互換性を維持するよう設計されています。 ほとんどのdockerコマンドはそのままpodmanに置き換え可能です。
8.2 コマンドマッピング表
| Dockerコマンド | Podmanコマンド | 相違点 |
|---|---|---|
docker run | podman run | 同一 |
docker build | podman build | 同一 |
docker pull | podman pull | 同一 |
docker push | podman push | 同一 |
docker ps | podman ps | 同一 |
docker exec | podman exec | 同一 |
docker logs | podman logs | 同一 |
docker images | podman images | 同一 |
docker compose | podman compose | 別途インストールまたはpodman-compose |
docker swarm | サポートなし | 代わりにKubernetesを使用 |
| N/A | podman pod | Podman専用機能 |
| N/A | podman kube play | Podman専用機能 |
| N/A | podman kube generate | Podman専用機能 |
8.3 ステップバイステップマイグレーション
ステップ1 -- インストール:
# macOS
brew install podman
podman machine init --cpus 4 --memory 8192 --disk-size 60
podman machine start
# RHEL/CentOS/Fedora
sudo dnf install -y podman
# Ubuntu/Debian
sudo apt-get install -y podman
# Windows
winget install RedHat.Podman
ステップ2 -- Docker互換エイリアスの設定(任意):
# ~/.bashrc または ~/.zshrc
alias docker=podman
# Docker Socket互換性(Docker APIを使用するツール向け)
# macOS:
podman machine stop
podman machine set --rootful
podman machine start
# Linux (rootless):
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
ステップ3 -- Docker Composeファイルのマイグレーション:
# 方法1: podman compose(Podman 5.x組み込みサポート)
podman compose up -d
# 方法2: podman-compose(Pythonベースのスタンドアロンツール)
pip install podman-compose
podman-compose up -d
# 方法3: Kubernetes YAMLに変換(推奨)
# docker-compose.ymlをKubernetes YAMLに変換後
podman kube play my-stack.yaml
ステップ4 -- CI/CDパイプラインの更新:
# GitHub Actionsの例
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Podman
run: |
sudo apt-get update
sudo apt-get install -y podman
- name: Build Image
run: podman build -t my-app:${{ github.sha }} .
- name: Push to Registry
run: |
podman login -u ${{ secrets.REGISTRY_USER }} \
-p ${{ secrets.REGISTRY_PASS }} \
registry.example.com
podman push my-app:${{ github.sha }} \
registry.example.com/my-app:${{ github.sha }}
8.4 マイグレーション時の注意事項
| 領域 | Docker | Podman | 対策 |
|---|---|---|---|
| デーモン状態 | 常時稼働 | デーモンなし | systemdによる自動起動の設定 |
| Docker Socket | /var/run/docker.sock | Podman Socketの有効化が必要 | podman.socketサービスを有効化 |
| Docker Swarm | サポート | サポートなし | Kubernetesに移行 |
| イメージ保存先 | /var/lib/docker | ~/.local/share/containers(rootless) | 既存イメージの再プルが必要 |
| ネットワークドライバー | bridge(dockerd管理) | Netavark + Pasta(rootless) | 互換性あり、設定の確認が必要 |
| ビルドキャッシュ | Docker BuildKit | Podman Buildah組み込み | 互換性あり |
9. Podman vs Docker:総合比較
| 比較項目 | Docker | Podman |
|---|---|---|
| アーキテクチャ | クライアント-サーバー(dockerdデーモン) | デーモンレス(Fork-Exec) |
| デフォルト実行モード | root(rootlessは実験的) | rootless(デフォルト) |
| Podサポート | なし(Composeで代替) | ネイティブPodサポート |
| Kubernetes YAML実行 | 別途ツールが必要 | podman kube playが組み込み |
| systemd統合 | 限定的 | Quadletによるネイティブ統合 |
| コンテナ起動時間 | 約1.2秒 | 約0.8秒 |
| アイドルメモリ | 約100MB(デーモン含む) | 約85MB |
| アイドルCPU | デーモンが常時稼働 | 0%(デーモンなし) |
| カーネルCapabilities | 14(デフォルト) | 11(デフォルト) |
| OCI準拠 | 完全準拠 | 完全準拠 |
| イメージ互換性 | Docker Hubがデフォルト | Docker Hub + 全OCIレジストリ |
| ビルドツール | BuildKit | Buildah組み込み |
| ルートレスネットワーキング | slirp4netns | Pasta(デフォルト) |
| Docker Compose | ネイティブ | 互換(podman compose) |
| Docker Swarm | サポート | サポートなし(Kubernetes推奨) |
| GUIツール | Docker Desktop(有料*) | Podman Desktop(無料/オープンソース) |
| ライセンス | Apache 2.0(Engine)/ 有料(Desktop) | Apache 2.0(完全無料) |
| マルチプラットフォームビルド | buildx | podman farm build |
| シークレット管理 | Docker Secrets(Swarm) | podman secret |
| TLS/mTLSリモートアクセス | サポート | 5.xで強化 |
| OCI Artifact管理 | 限定的 | podman artifact(5.xで安定化) |
*Docker Desktop:従業員250名以上または年間売上1,000万ドル超の企業は有料サブスクリプションが必要
10. まとめ:コンテナの未来は引き算にある
Podmanが提示する5つの革新を振り返ると、一貫した哲学が貫かれています:
10.1 デフォルトとしてのセキュリティ
Dockerではセキュリティは「追加する」ものでした。ルートレスモードを有効にし、seccompプロファイルを書き、AppArmorポリシーを設定する必要がありました。 Podmanではセキュリティは**「最初からオン」**です。ルートレスがデフォルト、デーモンなし、最小限のCapabilitiesがデフォルトで適用されます。
引き算によるセキュリティ:デーモンの除去(デーモンレス)、rootの除去(ルートレス)、不要な権限の除去(最小限のCapabilities)。 追加されたセキュリティは忘れられますが、デフォルトで提供されるセキュリティは常に機能します。
10.2 開発と運用の言語統一
Docker Composeで開発しKubernetes YAMLでデプロイするという二重性は、 開発組織に目に見えない税金、すなわち変換コストを課してきました。
Podmanのplay kubeとgenerate kubeはこの税金を排除します。 開発者が書くYAMLがそのまま本番環境のYAMLになるというSingle Language Principleを実現します。
10.3 リソース効率
デーモンレスアーキテクチャはアイドル時のCPU使用率ゼロ、Pastaネットワーキングはオーバーヘッドの排除、 systemd統合は別途のオーケストレータのリソースコスト削減を意味します。 これは単一の開発マシンでは気づきにくいかもしれませんが、 数百台のエッジノード、リソースが制約されたIoT環境、 コスト最適化されたクラウドインフラでは有意義な差を生みます。
10.4 最終まとめ
+-------------------------------------------------------------+
| Podmanの5つの革新まとめ |
| |
| +-------------+ デーモンの除去 -> 安定性 |
| | 革新1 | SPOFの排除 -> コンテナの自律性 |
| | デーモンレス| systemd統合 -> OSネイティブ管理 |
| +-------------+ |
| |
| +-------------+ rootの除去 -> 攻撃面の最小化 |
| | 革新2 | User Namespace -> UID分離 |
| | ルートレス | 最小Capabilities -> コンプライアンス |
| +-------------+ |
| |
| +-------------+ 変換の除去 -> 開発/運用言語統一 |
| | 革新3 | K8s YAML直接実行 -> 環境間一貫性 |
| | play kube | コンベンションビルド -> ワークフロー簡素化|
| +-------------+ |
| |
| +-------------+ 抽象化の除去 -> K8sと同じ単位 |
| | 革新4 | ネイティブPod -> ローカルサイドカー |
| | Pod管理 | generate kube -> 双方向ワークフロー |
| +-------------+ |
| |
| +-------------+ NATの除去 -> レイテンシ削減 |
| | 革新5 | L2-L4ソケットマッピング -> スループット向上|
| | Pasta | splice(2) -> ゼロコピー転送 |
| +-------------+ |
| |
| * 共通哲学:不要なものを取り除くことで |
| 本質的な価値を最大化する |
+-------------------------------------------------------------+
PodmanはDockerを否定するものではありません。Dockerが始めたコンテナ革命の基盤の上に、 セキュリティ、標準準拠、リソース効率という現代の要件に合わせてコンテナ技術を再設計しています。
2026年のクラウドネイティブの世界において、コンテナツールを選ぶ基準は 「何ができるか」ではなく**「何をしないか」**であるべきです。 不要なデーモンを動かさない、不要な権限を付与しない、 不要な変換レイヤーを追加しない。それがPodmanが描くコンテナの未来です。
11. 参考文献
公式ドキュメント
- Podman公式ドキュメント
- Podman GitHubリリースノート
- Podman Desktop公式サイト
- Podman Quadletドキュメント
- podman-kube-playドキュメント
- podman-kube-generateドキュメント
- passt/pastaプロジェクト
Red Hatブログおよび技術ドキュメント
- Podman 5.0 Unveiled -- Red Hatブログ
- rootless Podmanのuser namespaceモードを理解する
- QuadletでPodman向けsystemdを改善する
- Podman play kubeでKubernetes Podを構築する
- 今すぐ試すべき5つのPodman機能
コミュニティおよび技術分析
- Podman 5 X Deep Dive -- hrdtr.dev
- Podman vs Docker: 2026年完全比較 -- Xurrent
- PodmanからKubernetesへ -- Better Stack
- ルートレスネットワーク性能に関する議論 -- GitHub
- Podman Desktop 2025の軌跡
- rootless Podmanはどのように動作するか? -- Opensource.com
- Dockerからの移行 -- Podman Desktopドキュメント
セキュリティとコンプライアンス
- NIST SP 800-190: Application Container Security Guide
- Podman Rootlessチュートリアル -- GitHub
- rootless Podmanのユーザーアクセス制御 -- Red Hat
クイズ
Q1: 「Kubernetesをローカルマシンに:Podmanがもたらす5つの革新」の主なトピックは何ですか?
Podmanのデーモンレスアーキテクチャ、ルートレスセキュリティモデル、play kubeによるK8s YAMLのローカル実行、Pod ネイティブ管理、Pastaネットワーキングまで、Dockerを超えてクラウドネイティブ開発環境の新たな標準となった5つの革新をアーキテクトの視点から徹底分析します。
Q2: [革新1] デーモンレスアーキテクチャ:単一障害点の終焉について説明してください。
2.1 Dockerデーモンの構造的問題 Dockerのアーキテクチャを理解するには、中心に位置するdockerd(Dockerデーモン)を理解する必要があります。 すべてのDocker CLIコマンドはREST APIを通じてdockerdに渡され、dockerdはcontainerdを呼び出し、 containerdがruncを通じて実際のコンテナを作成します。 この構造の3つの核心的問題: 第一に、単一障害点(SPOF):dockerdが異常終了すると、実行中の全コンテナの管理が不可能になります。
Q3: [革新2] ルートレスセキュリティ:権限のパラダイムシフトの核心的な概念を説明してください。
3.1 コンテナエスケープ:rootが危険な理由 Dockerのデフォルト実行モデルでは、コンテナ内のroot(UID 0)がホストのroot(UID 0)と同じUIDを共有しています。 もちろんLinux Capabilities、seccomp、AppArmor/SELinuxなどのセキュリティレイヤーで制限されていますが、 カーネルの脆弱性が発見されるたびにこれらの制限をバイパスされる可能性があります。
Q4: [革新3] play kube:開発と運用の言語を統一するの主な特徴は何ですか?
4.1 Docker Compose vs Kubernetes YAML:二重性の苦痛 開発者がクラウドネイティブ環境で直面する最も一般的な摩擦の一つは、 ローカル開発と本番デプロイの言語が異なることです。 KomposeやDocker Compose to Kubernetesコンバーターなどのツールが存在しますが、 それらは問題の上にさらにレイヤーを追加しているだけで、根本的な解決策ではありません。
Q5: [革新4] Podネイティブ管理:真のPod Managerはどのように機能しますか?
5.1 Podmanの本質:Podを管理するツール Podmanの名前はPod Managerに由来します。 これは単なる巧みなネーミングではなく、KubernetesのPod概念をローカル環境で第一級市民として実装するという設計意図を表しています。 Dockerでは複数のコンテナを一緒に実行するにはDocker Composeという別のツールが必要でしたが、 PodmanではPodが組み込み機能です。 Podman Podの主な特徴: Infraコンテナ:KubernetesのPauseコンテナと同じ役割。