セキュリティを強化したDocker代替、「Podman」を探る
(betterstack.com)- PodmanはDockerに近いコンテナ実行体験を提供しつつ、デーモンなしで動作するため、セキュリティと監査追跡の面で差別化される
- DockerはDocker daemon中心のクライアント・サーバー構造を採用する一方、Podmanはユーザーセッション内でコンテナを直接生成するため、実行ユーザーの追跡がより明確
- OCI標準に従うため、Docker Hubの
hello-world、caddy、wordpress、mysql:5.7といったイメージを実行でき、多くの場合dockerコマンドをpodmanに置き換えて使える - 短いイメージ名はDockerのように自動でDocker Hubを既定値にしないため、完全なイメージ名、エイリアス、
unqualified-search-registries設定のいずれかが必要 - 複数コンテナ構成はPodman Compose、pods、Kubernetesマニフェストで扱えるが、Docker Swarmのような組み込みの本番向けオーケストレーションはなく、Kubernetesのような外部システムを使う必要がある
PodmanとDockerが分かれるポイント
- Podmanは、Dockerより安全で軽量な代替を目指すオープンソースのコンテナエンジン
- 常駐デーモンなしでコンテナを実行し、ユーザーがコンテナを直接管理する構造を持つ
- 基本的なセキュリティ方針は、rootlessコンテナ、ユーザー名前空間、カーネルcapabilityのより慎重な利用に置かれている
- Dockerのイメージやコマンド体系との互換性が高く、Docker代替を探す開発者やシステム管理者にとって実用的な選択肢となる
アーキテクチャと監査追跡
- Dockerはクライアント・サーバーモデルを使用し、コンテナ実行要求はDocker clientからDocker daemonへ渡される
- コンテナプロセスはユーザーセッションではなく、Docker daemonの子プロセスになる
- Linux Auditシステムである
auditdがコンテナプロセスのイベントを検知する際、audit user IDが実際のユーザーIDではなくunsetと表示される場合がある - この構造では、不正な活動を特定のユーザーに結び付けるのが難しい
- Podmanはデーモンレスアーキテクチャを採用する
- 各コンテナはユーザーのログインセッションを通じて直接生成される
- コンテナプロセスのデータがユーザー情報を保持する
auditdは特定のコンテナプロセスを起動したユーザーIDを正確に検知して記録できる
- イメージによっては、Podmanのコンテナ起動速度はDockerより最大50%速いことがある
コンテナライフサイクル管理
- Podmanはデーモンがないため、コンテナライフサイクル管理の方式もDockerと異なる
- Linuxではsystemdに大きく依存する
--restart alwaysフラグで指定したコンテナの再起動ポリシーを適用するために、podman-restartというsystemdサービスを使う- このサービスはシステム再起動後に指定コンテナを自動で再起動する
- 実行中のコンテナからsystemdサービスファイルを生成するコマンドも提供する
- コンテナを
systemd管理下に置くと、起動、停止、点検が容易になる
- コンテナを
- Dockerはこうした処理をdaemon内部で行う
オーケストレーションの選択肢
- ローカル開発では、Dockerユーザーは通常Docker Composeで複数コンテナアプリケーションを定義・管理する
- PodmanはComposeファイルをネイティブにはサポートしないが、互換代替としてPodman Composeを提供する
- 一般に既存の
docker-compose.ymlファイルとともに動作する - Docker Composeに慣れたユーザーは既存のComposeファイルをそのまま使える
- 一般に既存の
- Podmanのネイティブな方法としてはpodsが使える
- Kubernetesから持ち込まれた概念
- 複数コンテナを1つの単位のように管理できる
- 本番デプロイでは、PodmanにはDocker Swarmのような組み込みオーケストレーションツールがない
- この場合、Kubernetesのような外部オーケストレーションシステムが代替となる
- KubernetesはPodmanと統合できるが、正しく動作させるには追加の構成や設定が必要な場合がある
セキュリティのデフォルト設定
- コンテナセキュリティにおける大きなリスクは、コンテナ脱出によってホストシステムが侵害される状況
- PodmanはDockerより強力なデフォルトのセキュリティ設定を提供するよう設計されている
- rootlessコンテナ
- ユーザー名前空間
- seccompプロファイル
- Dockerでもrootlessコンテナ、ユーザー名前空間、seccompプロファイルは利用できるが、デフォルトでは有効化されておらず、追加設定が必要なことが多い
- Podmanの標準構成では、隔離されたユーザー名前空間内でrootlessコンテナを実行し、潜在的な脱出の影響を制限する
- Dockerのデフォルト設定では、コンテナプロセスを
rootとして実行するため、脱出時のリスクがより高い - capabilityのデフォルト値も異なる
- Podmanはデフォルトで11個のcapabilityでコンテナを起動する
- Dockerはより許容的なデフォルト設定で14個のcapabilityを使う
- どちらのツールも強固なセキュリティ構成に設定できるが、Podmanは一般にその状態へ到達するための労力が少ない
機能比較で目立つ違い
- Podmanはデーモンレスアーキテクチャとsystemd統合をサポートする
- コンテナをpodsにまとめられ、Kubernetes YAMLも扱える
- DockerはDocker Swarmをサポートするが、Podmanはサポートしない
- そのほか大半の機能は、両者がおおむね同等と見なせる
インストールと実行環境
- PodmanはDocker同様、主要OSで実行できる
- macOS
- Windows
- 主要なLinuxディストリビューション
- 重要な違いは、Linuxではネイティブに動作する一方、WindowsとmacOSでは仮想マシンが必要な点
- 例はDebian系LinuxディストリビューションであるUbuntu、Mint、Debianを前提とする
- 最新のPodmanをインストールするには、比較的新しいディストリビューションが必要
- 執筆時点の最新の主要Podmanバージョンは
4.x - Ubuntu 22.04 LTSはPodman
3.xに固定されている - 例はUbuntu 23.10を基準にしている
- 執筆時点の最新の主要Podmanバージョンは
- インストール後の出力例は
podman version 4.3.1で、ローカルでpodmanコマンドを実行できることを確認している
Dockerイメージの実行とOCI互換性
- PodmanはDockerエコシステムのツールでビルドされた
hello-worldイメージを実行できる - この互換性は、DockerとPodmanがどちらも**OCI(Open Container Initiative)**標準に従っているため
- OCIはイメージ形式仕様とランタイム仕様を定義する
- 異なるコンテナランタイム同士の相互運用を可能にする
- Docker Hub上の大半のDockerイメージとコンテナをPodmanで利用できる
- 既存ワークロードを修正なしでPodmanへ移行したり、Docker Hubのイメージライブラリを活用したりできる
hello-worldの出力に“Hello from Docker!”と表示されても、実際の実行主体はPodman- Docker clientやDocker daemonは実行過程に関与しない
短いイメージ名の扱い
- Dockerは完全なイメージ名を指定しない場合、Docker Hubである
docker.ioを既定レジストリとして使う - Podmanは短い名前の使用を推奨せず、既定レジストリを自動では想定しない
hello-worldはshortnames.confにエイリアスがあるため、docker.io/library/hello-worldとして解決されるcaddyのようにエイリアスがないイメージを短い名前で実行すると、次のエラーが発生するError: short-name "caddy" did not resolve to an alias and no unqualified-search registries are defined in "/etc/containers/registries.conf"
- 解決方法は3つある
- 完全なイメージ名を使い、
docker.io/library/caddyのように明示する registries.confに[aliases]セクションを追加し、"caddy"="docker.io/caddy"としてエイリアスを定義するunqualified-search-registries=["docker.io"]を設定し、短い名前をDocker Hubで検索するようにする
- 完全なイメージ名を使い、
- ユーザーごとの設定は
$HOME/.config/containers/registries.confに置ける- このファイルは
/etc/containers/registries.confより優先される - root権限なしで設定できるため、rootlessアプローチとより相性がよい
- このファイルは
- Dockerの代替としてPodmanを使うなら、長期的にはエイリアスより
unqualified-search-registries設定のほうが便利
プライベートレジストリの利用
- PodmanはDocker同様、プライベートレジストリを利用できる
- Docker Hubアカウントを使う例は次の流れに従う
- Docker Hubでaccess tokenを生成する
- 説明は
Podman tutorial、権限はRead & Writeに設定する - private repositoryを作成する
podman login docker.ioでログインする
docker.ioがregistries.confの最初のunqualified-search-registries項目なら省略できるが、レジストリを明示するのがよい慣行- レジストリを指定しないと、
podman loginは次のエラーで失敗するError: no registries found in registries.conf, a registry must be provided
- ログイン後、
hello-worldイメージをprivate repositoryへpushし、ローカルのpublicイメージを削除したうえでprivate repositoryのイメージからコンテナを実行できる - 有効なログイン資格情報がなければ、privateイメージのpull時にアクセス拒否や認証要求エラーが発生する
- プライベートレジストリ利用で目立つ違いは、
dockerの代わりにpodmanを付ける点であり、Podmanは広く使われるprivate registryと組み合わせて利用できる
Podman Composeで複数コンテナを実行
- 複数コンテナを1つの単位として実行する必要がある場合、Podmanは複数の選択肢を提供する
- Podman Compose
- pods
- Kubernetes manifests
- 例ではPodman Composeを使ってWordPressとMySQLを実行する
- Podman Composeはコミュニティ主導のツールで、Compose specificationを実装し、Podmanと統合される
- Python 3に依存しており、例ではpipxでインストールする
- インストール出力例は
podman-compose 1.0.6 - 使用したPodmanバージョンは
4.3.1
- インストール出力例は
pipxが$HOME/.local/binにインストールされる場合、そのパスが$PATHに含まれていないことがあるpipx ensurepathでパスを追加できる- 新しいターミナルを開くか、シェル設定ファイルを再読み込みする必要がある
WordPressとMySQLの例
- 例では
.envファイルにデータベースのユーザー名、パスワード、名前を定義し、docker-compose.ymlでWordPressとMySQLサービスを構成する podman-compose up -dを実行すると、Podman Composeはdocker-compose.ymlを解析するwordpressサービスの処理過程- 必要なexternal volumeを探し、なければ作成する
- 適切なnetworkを探し、なければ作成する
wordpressコンテナを起動する- ローカルイメージがなければ、設定された
docker.ioレジストリからwordpress:latestを取得する
dbサービスの処理過程podman-tutorial_dbvolumeを作成する- 既存ネットワークを確認する
mysql:5.7コンテナを起動する- ローカルイメージがなければDocker Hubから取得する
- 実行後、
localhost:8080でWordPressのインストールページを確認できる podman psの出力にはwordpressとdbコンテナが実行中として表示されるwordpressは0.0.0.0:8080->80/tcpでポートマッピングされるdbはmysql:5.7イメージで実行される
- イメージ一覧には
docker.io/library/wordpress:latestとdocker.io/library/mysql:5.7が表示される - ネットワーク一覧には既定の
podmanネットワークと、Podman Composeが作成したpodman-tutorial_defaultネットワークが表示されるpodman-tutorial_defaultは、docker-compose.ymlで定義されたコンテナを同じシステム上のほかのコンテナから分離するために作成される
- volume一覧には
podman-tutorial_dbとpodman-tutorial_wordpressが表示される podman-compose downはコンテナを停止・削除するが、networkとvolumeは保持する- volumeの削除には
podman volume rmを使う - networkの削除には
podman network rmを使う
- volumeの削除には
- コマンドはDockerおよびDocker Composeとほぼ同じで、
dockerとdocker-composeの代わりにpodmanとpodman-composeを入力する違いがある
選択基準
- Podmanはコンテナワークロード実行のためのDockerの実用的な代替
- Dockerでできることの大半を実行でき、バックグラウンドデーモンが不要という利点がある
- Dockerにはない機能も提供する
- Kubernetes manifestファイルの操作
- 個別コンテナをpodsとして構成
- より軽量で安全なコンテナ管理ソリューションが必要なら、Podmanのほうがよい選択かもしれない
- 強力なエコシステムと幅広いコミュニティサポートを優先するなら、Dockerのほうが適している可能性がある
- 追加の参考資料として、Podman公式Webサイト、ドキュメント、コミュニティを参照できる
1件のコメント
Hacker News の意見
Podman が systemd ユニットファイルをサポートしていた頃はよかった。コンテナだけでなく pod 全体も systemd で自動起動・自動更新できたから
ところがその機能をなくして Quadlet を推し始めた。単一コンテナはユニットファイルで扱えるが、pod は Kubernetes クラスタ定義を使わなければならない
さらに Docker と違ってコンテナが SELinux 定義に従うため、マッピングしたディレクトリにアクセスできず、何度も苦労した
結局 Podman は何をさせたいのか分からない。Kubernetes を使えということなのか? 論理的なパスをマッピングせず、すべて専用ディレクトリを作れということなのか?
この機能は、今では廃止された Podman の機能を使わずにユニットファイルを直接作成するもので、個人的には従来の Podman 方式よりずっとスムーズだった
機能の有効化は
$ podman-compose systemd -a create-unit、systemd ユニットの登録は$ podman-compose systemd -a register、$ systemctl --user enable --now "podman-compose@$PROJECT_NAME"で行う更新は
$ podman-compose pullの後に$ systemctl --user restart "podman-compose@$PROJECT_NAME"で処理する。$PROJECT_NAMEは通常ディレクトリ名確認したければ機能のソースコードはここにある: https://github.com/containers/podman-compose/blob/f6dbce3618...
まだ podman 4.3.1 を使ってはいるが、以降のバージョンでこの方式が動かなくなる理由はなさそう
それに podman-generate-systemd が生成していた systemd ファイルは、結局
"podman start containername"を実行する程度なので、自分で書くのも簡単。ただし docker-compose のようなものと違い、コンテナはほぼブラックボックスに近いQuadlet の利点は、コンテナ定義が
.containerファイルに宣言される点。以前は podman run のコマンドラインを手で systemd ユニットに書いていたので、その点では Quadlet は大きな改善で、docker-compose の代替にもなり得る。もちろん長所短所はあるpodman generate systemd [...]を実行しようとするたびに、この移行があったことを思い出させられるそれほど頻繁に遭遇しないのは、これをいい感じに処理する Ansible ロールを自分で作ってあるから
それでも Podman は方向性を見失っている感じが強い。すでにユニットファイルの保守や関係設計の方向を受け入れたのだから、そのままジェネレータを使わせてほしい。Quadlet だろうが、それの方が優れているという話だろうが、興味はない
containers.confに次を追加すればよい:[containers] label=falsePodman のデフォルトのセキュリティレベルが気に入らない場合、たいていは無効化する方法がある
このモデルは非常に直感的だったが、Docker Compose に適用するには手作業での移行がかなり必要だった
そこで Compose ファイルを NixOS 設定に変換し、ネイティブに解釈・管理できるようにするツールを作った: https://github.com/aksiksi/compose2nix
Podman を Docker より好む決定的な理由として、ほとんど語られない利点がある。Docker は ネットワーク設定を壊す
Docker と KVM 仮想マシンをブリッジと一緒に同時に動かそうとすると悪夢で、Podman はデフォルト設定だけでもずっと相性がよい
VPN も Docker のせいで壊れたり、Docker を壊したりしたことが何度もあった。Podman のネットワークが内部でどうなっているのかはよく分からないが、少なくとも他の作業を妨げないようによく設計されているように見える。Docker については絶対にそうは言えない
Dockerfile は純粋なゴミだと思っている。既存の言語で十分なのに、「退屈した開発者」が DSL やプログラミング言語を新しく作るのが本当に嫌いだ。特に YAML ならなおさらで、この場合は違うが、Dockerfile はなぜこういうことをやめるべきかを示す良い例だ
budなしで Buildah を見れば理由が分かる。ユースケースが標準的な道筋から少し外れただけでイライラする粗雑な DSL の代わりに、Bash、Fish、あるいは好きなものを使えるこうした悪い判断は Docker エコシステム全体に及んでいる。DCS と、常に未完成なその代替も一例。Cosign のような確立された署名プロトコルを使う代わりに、自動化が難しく、特に鍵のローテーションが厄介な複雑なシステムを作りたがった
Podman がもっと広く使われるようになるのは歓迎。あまりに多くのツールが、ユーザーが
sudo dockerグループを追加する前提で作られているため、ルートアクセスをむやみに与えないような セキュリティを意識した Docker 設定では壊れる認定 RHEL エンジニアとして、Podman はもう数年前から使っています。
正直、個人的なコンテナ利用にはかなり気に入っています。ただし職場では、開発者には今でも Docker を提供しています。これまでは、docker compose のシンプルさに匹敵するものを開発者に提供する方法がありませんでした。
コンテナイメージを作る際、CI パイプラインでは buildah も使っていますが、開発者というエンドユーザーの視点では docker compose が依然として支配的です。
https://www.techrepublic.com/article/how-to-fix-the-docker-a...
この問題のせいで、危うくやられるところでした。
Red Hat がなぜ Docker の代替に投資しているのかはまだよく分かりませんが、成果物は本当に気に入っています
Podman は Docker が行うほぼすべてのことをこなしつつ、pod のような機能が追加されていたり、デーモンなしでコンテナを作成するプロセスのように、やり方自体がより優れている場合も多いです
一般的な開発者にとって最大の問題は Docker compose でしょうが、単純な compose ファイルを使うなら、Docker compose 仕様との互換性を目指す podman-compose スクリプトがあります
docker-compose のバックエンドとして Podman を使う方法もあります [1]。全体として、2024年に Linux マシンで Docker を使うべき理由は見当たりません。macOS や Windows で Podman がどうなのかはよく分かりません
[1] https://www.redhat.com/sysadmin/podman-docker-compose
これに、Docker は以前も今もセキュリティ問題がとりわけ多く、Docker 式のコンテナやイメージが開発者の間で非常に広く使われているという点を合わせると、RHEL の価値観とアプローチにより合った独自実装を作らざるを得ませんでした
たとえば Docker は rootless にできるにもかかわらず、いまだにデフォルトでは使っていません。強化された環境では、docker ユーザーグループも、グループなしで実行する方式も、セキュリティ上多くのユースケースで受け入れにくいものです
初期の Docker は、非特権コンテナに最低限の隔離を持たせることにあまりにも消極的で、問題が知られた後も修正に長い時間がかかりました。ファイアウォールやネットワークルール、SELinux との相互作用の仕方にも問題が多いです。セキュリティを重視する専任の Linux システム管理者がいる会社で Docker 禁止が珍しくない理由です
最初からすべてのドキュメントが、攻撃的なほどユーザーフレンドリーでない GUI インストールへ誘導します。起動時に重いプロセスを立ち上げ、なぜかクラウドアカウントへの登録を要求し、いわゆるオープンソース製品を仕事で使うべきではないとまた小言を言ってきます
「コマンドライン Docker だけ」をインストールする非サポートの代替手段は不必要に複雑で、最後に試したときはほとんどの WSL VM がデフォルト状態ではサポートすらしていませんでした
一方 Podman は
winget install podmanで終わり、邪魔をしません。コンテナを実行する必要があるときだけ Podman VM を起動し、不要なときはシステムが以前どおりに動作しますcompose ファイルで何かを実行する必要があれば podman-compose があります。特殊な設定は扱えないかもしれませんが、私の用途ではうまく動きました
Podman がうまくできないのは VS Code 連携くらいですが、Windows で Docker をおとなしく動かす苦労は、VS Code のショートカットをいくつか失うことよりはるかに苛立たしいので、問題にはなりません
Windows でのコンテナの基本解として Podman をおすすめします。Docker を使う理由は、会社が費用を負担してくれるか、複雑な compose 構成がある場合くらいですが、そういう場合なら Kubernetes へ移行する価値があるかもしれません
システムを壊すようなことをし、rootless には何年も苦戦し、ベンダーロックインも見逃せません
Podman はオープンで、標準に従っており、Kubernetes とも相性が良いです。簡単なコンテナ市場に先に出たという理由だけで、開発者たちが Docker に費やした労力はばかげているほど大きかったです
Docker が消えれば、RedHat はより強い手で自社の企業アジェンダを押し進められます
Podman には利点もありますが、RedHat が Docker のすべてを置き換えようとする過程で、うまく実行されていない部分もあります
RedHat がコンテナ領域に取り組んできた歴史を見ると、貢献して改善できたはずの多くのプロジェクトに時間と労力を浪費した面があります
RedHat は顧客にとって正しいことをしようというアジェンダを持つ会社ではないので、より大きな視点で何を望むのか考える必要があります
macOS 向け Podman の唯一の大きな欠点は、コンテナからホストネットワークを使えない点です。ただし、コンテナからホストネットワークを使いたいケースはまれです
ただ、コンテナ内でネットワーク関連の実験をしながら、ホストと同じホスト名と IP アドレスを維持したい場合は考慮しておく必要があります。それでもこの制限は回避して使っています
セキュリティ優先のアプローチと判断は良さそうです。デフォルト設定から安全で、docker compose とも動作する点が気に入っています
ただ、Podman が十分に人気を得たら、いつかコマンドや yml 形式で独自路線を取るのか気になります。今は Docker と Docker compose ファイル形式に依存するツールのように見えます
Podman に Swarm の代替があるとよいです。現状では、オーケストレーション不足のために Kubernetes が松葉杖のように使われている感じがします
セキュリティをきちんと考えるチームなら、デフォルトから安全ではない Kubernetes を博士課程のように掘り下げなくても、小規模でコンテナを合理的かつシンプルに実行する方法を作れるように思います。そのうえで Docker compose 形式との互換性も維持できるでしょう
rootless コンテナと分離された名前空間が重要なセキュリティ機能であることには同意する。ただし Docker rootless でも可能で、複雑ではない。単にそう設定すればよい
現時点で可能なベストプラクティスをすべて適用し、Mastodon を docker rootless で設定する記事を書いたことがある [1]
Docker を使い続ける利点は、アクセシビリティがより高いことだ。コミュニティやブログが多く、docker compose の設定が広く出回っており、周囲にも使える人がより多い
結局、Podman も Docker も、ホスト上の分離された名前空間でプロセスを実行する
[1]: https://du.nkel.dev/blog/2023-12-12_mastodon-docker-rootless...
誤解はしないでほしい。Podman は素晴らしく、最近は Docker の代わりに使っているが、最初は単純な Docker の代替品だと思って使い始め、UID/GID マッピング、SELinux ポリシー、欠けている DNS 設定などで大いに痛い目を見た
問題を直そうとして
system migrateを実行し、設定全体を壊したことも何度もある。セキュリティ ACL、ID マッピング、ラベルに関する仕組みが別途存在するホームフォルダ配下で
chmod -Rを実行すると、おそらくすべてのコンテナが死ぬ可能性がある結果には満足しているが、Docker のように「そのまま動く」解決策とはかなり距離があった。自分が使い始めてからは、おそらくかなり改善されていると思う
自分の基準では Docker より使いやすかった。上で経験した状況より、今は改善されているようだ
大きな視点で見ると、Podman は昔の Linux のように不可欠な存在に感じられる
使っている人がごく少数だとしても、その存在だけで、はるかに大きなプロプライエタリソフトウェアの兄弟たちがひどいことをするのを防いでくれる
ここで「昔の Linux」と言ったのは、Linux の重要性が下がったという意味ではなく、今ではむしろさらに不可欠で中心的なものになったからだ