DockerとPodmanの比較 [Container Runtime Meetup #3]
Container Runtime Meetup #3 (2021/1/28) で発表した、「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個あたりの起動所要時間を計測してみました。
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回も出しています。
また、pull requestのMerge Chance についても、下図の通り、Podmanのほうが高い傾向があります。
新機能のコードが書かれてからユーザの手元に届くまでの期間については、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 Namespaces、RootlessKit、slirp4netns などの共通の技術基盤を用いているため、機能的、性能的にはほぼ同等です。ただし、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/