DockerとPodmanの比較 [Container Runtime Meetup #3]

Akihiro Suda
nttlabs
Published in
11 min readFeb 5, 2021

Container Runtime Meetup #3 (2021/1/28) で発表した、「DockerとPodmanの比較」の内容をブログにまとめてみました。

Container Runtime Meetup #3 発表資料 「DockerとPodmanの比較」

Podmanとは

Podmanは、Red Hat社を中心とするコミュニティが開発している、Docker互換のコンテナエンジンです。RHEL、CentOS、Fedora などの Linuxディストリビューションに標準で付属しています。

Podmanの使い方は、コマンド名が docker ではなく podman である点を除けば、Docker とほぼ同じです。(例: podman run -p 80:80 --name nginx docker.io/library/nginx )

“Podman”は “Pod Manager” を意味しますが、Podmanを用いてKubernetesのPodを管理することは、基本的にはできません。ただし、CRIランタイムとしてCRI-Oを用いている場合に限り、 podman ps --external コマンドや podman diff コマンドでKubernetesのPodに関する情報を表示できます。

比較するバージョン

本記事では、Docker 20.10.2 および Podman 3.0.0-rc1 を比較します。いずれも Container Runtime Meetup #3 (2021/1/28) 開催時点で最新のバージョンです。

比較: アーキテクチャ

Dockerはデーモン ( dockerd )とクライアント ( docker CLI )にわかれており、両者はREST APIで通信します。

一方、Podmanは基本的にはデーモン無しで動作します。厳密にデーモン無しで動作するわけではなく、実際にはconmonと呼ばれるプロセスをバックグランドで起動しますが、ユーザはconmonの存在を意識しなくて済むように出来ています。

Podmanやconmonのプロセスはコンテナ毎に独立しているため、あるコンテナを担当するプロセスがクラッシュしたり、メモリリークを起こしたりしていても、他のコンテナには影響が出にくい利点があります。なお、Dockerでも live-restore モードを有効化すれば、デーモンのクラッシュによるコンテナへの影響を軽減できることがあります。

使い勝手

ホストOSの起動時にコンテナも自動的に起動させたい場合は、DockerでもPodmanでも、systemdなどのinitシステムの設定が必要です。

Dockerでは dockerd 用のunitファイル ( /usr/lib/systemd/system/docker.service ) 1つのことだけ考慮すればすみますが、Podman (3.0.0-rc1) では次に示す例のように、コンテナ毎にunitファイルを作成する必要があります。

# podman run -d --restart=always --name nginx ...# podman generate systemd nginx > /etc/systemd/system/podman-nginx.service# systemctl enable podman-nginx

したがって、使い勝手に関してはPodmanがDockerより優れているとはいえません。ただし、Podman 3.1以降のバージョンには、unitファイルを1つで済ませる podman system boot (仮称) という仕組みが入る見込みです。この仕組みが入れば、Dockerと互角の使い勝手になりそうです。

ベンチマーク

コンテナを300個起動 ( ntimes -n 300 docker run -d nginx:alpine ) した際の、コンテナ1個あたりの起動所要時間を計測してみました。

ntimes –n 300 docker run –d nginx:alpine

Dockerでは平均275ミリ秒、Podmanでは平均377ミリ秒かかりました。起動済みのコンテナの数 (横軸)が増えるにつれて、Podmanのほうが遅くなる傾向が見られますが、さほど大きな差ではありません。

計測条件など詳細についてはスライドの9枚目~10枚目をご覧ください。なお、Docker社が配布しているバイナリはベンチマークには使用せず、DockerのOSS版であるMobyをソースコードからビルドして使用しました。

比較: リリースサイクル

DockerとPodmanの違いは、技術的な点よりもむしろリリースサイクルなどの非技術的な点が目立ちます。

近年のDockerでは、新機能のpull requestが投稿されてもそれがマージされ、さらにリリースが出るまでにはかなりの時間がかかります。2019年1月~2020年12月の2年間で、Dockerの主要なリリースは2回しかありませんでした。一方のPodmanは、同期間に主要なリリースを13回も出しています。

過去2年間の主要リリース

また、pull requestのMerge Chance についても、下図の通り、Podmanのほうが高い傾向があります。

Moby (DockerのOSS版)、PodmanのMerge Chance

新機能のコードが書かれてからユーザの手元に届くまでの期間については、Podmanのほうが格段に短いといえます。なお、バグ修正を目的とする細かいリリースについては、DockerでもPodmanでも頻繁に公開されています。

比較: API

Podman 1.x はDocker のREST APIを実装していませんでした。Podman 2.0からはDocker互換のREST APIを実装するようになりましたが、実際に高い互換性を備えるのは Podman 3.0からです。Podman 3.0では、環境変数 DOCKER_HOST=unix:///run/podman/podman.sock を設定するだけで docker-compose コマンドをそのまま実行できます。

比較: Kubernetes マニフェスト

Podmanでは podman play kube コマンドでKubernetesのPodマニフェストやDeploymentマニフェストを直接実行できますが、ごく基本的なマニフェストにしか対応していません。

Kubernetesのマニフェストをローカルで実行したい場合は、Dockerを使う場合でもPodmanを使う場合でも、kind (Kubernetes-in-Docker)を使うほうが便利です。kindを使うと、DockerやPodmanのコンテナをノードとして仮想的なKubernetesクラスタを構築できます。本物のkube-apiserverやkubeletのバイナリを使うため、 podman play kube と異なりあらゆるマニフェストに対応します。

結局、Podmanはその名前に反して、実際にはPodの管理に使う場面よりも、コンテナの管理に使う場面の方が多いでしょう。

比較: ネットワーク

コンテナ間ネットワークの実装にDockerがlibnetworkを使っているのに対し、PodmanはKubernetesと同じく CNI (Container Network Interface)を使っています。

docker network create コマンドと同様に podman network create コマンドでカスタムネットワークを作成できますが、Podman (3.0.0-rc1) では複数のネットワーク間での通信が禁止されていません。

$ podman network create foo$ podman network create bar$ podman run -d --network foo nginx$ podman run --network bar busybox wget http://<NGINXのIPアドレス> # 失敗して欲しいが、成功する

したがって、現状のPodmanでは複数のネットワークを作る意味があまりありません。この問題については https://github.com/containers/podman/issues/5805 で議論中です。

比較: イメージビルド

docker build コマンドがBuildKitを使って実装されているのに対し、 podman build コマンドはBuildahを使って実装されています。

RUN --mount=type=(cache|secret|ssh) などの最新のDockerfile syntaxは、docker build(BuildKit) には実装されていますがpodman build(Buildah)には実装されていません。また、 podman build では並列ビルドの対応が不十分です。イメージビルドに関してはDocker (というよりBuildKit)に軍配が上がります。

なお、BuildKitはDockerではなくPodmanと組み合わせて使用することもできます。

$ podman run -d --name buildkitd --privileged moby/buildkit$ buildctl --addr=podman-container://buildkitd \
build --output=type=oci ... | podman load foo

比較: セキュリティ

DockerもPodmanも、非root権限でコンテナエンジンを実行することでセキュリティを強化する機能 (Rootlessモード) を実装しています。実装自体は同時期でしたが、Podmanの方がリリースが頻繁なため、Podman固有の機能であると誤解されることが多いようです (スライド 35枚目参照)。

いずれとも、User NamespacesRootlessKitslirp4netns などの共通の技術基盤を用いているため、機能的、性能的にはほぼ同等です。ただし、Docker 19.03、Podman 2.0 以前のバージョンでは、 docker run --cpus コマンドが使えなかったり、 podman network create コマンドが使えなかったりと相互に欠けている部分がありました。

Docker 20.10、Podman 2.1 以降ではこれらの問題は解決していますが、Podman 3.0.0-rc1のRootlessモードは podman network connect コマンドに相当するAPIに対応していないため、Docker Composeを実行するにはまだ不十分です。近い将来のバージョンでは対応できるでしょう。

ありがちな誤解

DockerやPodmanに関して、以下のような言説を散見しますが、すべて誤りです。

  • 「PodmanはKubernetesが呼び出すランタイムである」
  • 「RHEL/CentOS 8やFedora ではDockerは動かないのでPodmanを使う必要がある」
  • 「RootlessコンテナはPodman固有の機能である」
  • 「PodmanではDocker Composeは使えない」

詳細についてはスライドの31枚目~36枚目にまとめました。

まとめ

デーモンを起動しなくても使えるのがPodmanの最大の特徴ですが、ホストOS起動時にコンテナを起動したい場合は結局、systemdのunitファイルを作成する必要があります。そのため、PodmanがDockerよりも使いやすいとは必ずしも言えません。

Podmanは技術的な点よりもむしろ、リリースサイクルの短さや、pull requestのマージの速さの点で魅力的です。

機能や性能に関しては、DockerとPodmanの間に重要な違いはもはやほとんどありませんが、イメージビルドについては Docker (BuildKit) のほうがPodman (Buildah) よりも先進的であると言えます。

NTT is hiring!

私たちNTTは、Moby (OSS版Docker)とPodmanの両方に対して、Rootlessコンテナlazy-pullingなどの分野で大きくコントリビュートしています。NTTでは、Moby、Podman、Kubernetes、containerd などのオープンソースコミュニティで共に活動する仲間を募集しています。ぜひ弊社採用情報ページをご覧ください: https://www.rd.ntt/sic/recruit/

--

--