DockerユーザーのためのPodmanとBuildahの紹介

皆さま、こんにちは。Red Hatの西村(@iamnishipy)です。入社するまでDockerユーザーだった私が、わかりやすいと感じたPodmanの記事を共有いたします。

この記事はRed Hat DeveloperのPodman and Buildah for Docker usersを、許可を受けて翻訳したものです。


:::William Henry 2019年2月21日:::

最近Twitterにて、Dockerに詳しい人のためにPodmanとBuildahをよりよく説明してほしいと頼まれました。ブログやチュートリアル(後ほど紹介)はたくさんありますが、DockerユーザーがどのようにDockerからPodmanやBuildahに移行していくのかについて、私たちコミュニティから一元的な説明を行っていませんでした。Buildahはどのような役割を果たしているのでしょうか?Dockerを置き換えるために、PodmanとBuildahの両方が必要なほど、Podmanには何らかの欠陥があるのでしょうか?

この記事ではそれらの疑問に答え、Podmanへの移行方法を紹介します。

Dockerはどのように動くのか?

PodmanやBuildahを理解するために、まずDockerがどのように動作するのかを明確にしておきましょう。Dockerユーザーであれば、すべてのDockerコマンドを処理するために、デーモンプロセスを実行しなければならないことを理解していると思います。この背景にある動機を理解することはできませんが、当時はDockerが行うことすべてを一箇所で実施し、さらに将来の進化のためにそのプロセスに有用なAPIを提供するのが、素晴らしいアイデアに思えたのではないかと想像しています。下の図を見ると、Dockerデーモンが必要なすべての機能を提供していることがわかります。

  • イメージレジストリからイメージをプルおよびプッシュする
  • ローカルコンテナストレージにイメージのコピーを作成し、それらのコンテナにレイヤーを追加する
  • コンテナをコミットし、ホストリポジトリからローカルコンテナイメージを削除する
  • カーネルに対して、正しい名前空間やcgroupなどを指定してコンテナを実行するように依頼する

基本的には、Dockerデーモンがレジストリ、イメージ、コンテナ、カーネルを利用したすべての作業を実施します。Dockerコマンドラインインターフェイス(CLI)は、あなたの代わりにこれを行うようデーモンに依頼します。

この記事では、Dockerデーモンプロセスの詳細な長所と短所については扱いません。このアプローチに賛成することは多くありますし、Dockerの初期の頃、このアプローチが多くの意味を持っていた理由もわかります。しかしDockerの利用が増えるにつれ、Dockerユーザーがこのアプローチを不安視する理由がいくつかあったことは、言うまでもありません。以下に、いくつか挙げておきます。

  • 1つのプロセスが1つの障害点になる可能性がある
  • このプロセスはすべての子プロセス(実行中のコンテナ)を所有する
  • 障害が発生した場合、孤児(orphan)となるプロセスが存在する
  • すべてのDockerの操作は、同一の完全なroot権限を持つユーザーによって行われなければならなかった

この他にもあるでしょう。これらの問題が修正されたかどうか、この特徴付けに同意できないのかどうかは、この記事では議論の対象ではありません。私たちコミュニティは、Podmanがこれらの問題の多くを解決したと信じています。Podmanの改善点を活用したいのであれば、この記事が役立ちます。

Podmanのアプローチは、単純にイメージレジストリ、コンテナとイメージストレージ、そしてrunCコンテナランタイムプロセス(デーモンではありません)を介してLinuxカーネルと直接対話することです。

動機の一部を説明したところで、Podmanに移行するユーザーにとってそれが何を意味するのかを議論しましょう。 ここで取りあげることはいくつかあり、それぞれに個別に説明します。

  • Dockerの代わりにPodmanをインストールする
  • Dockerでお馴染みのコマンドはPodmanでも同じように動作する
  • PodmanはコンテナとイメージをDockerとは別の場所に保存する
  • PodmanとDockerイメージは互換性がある
  • PodmanはKubernetes環境のためにDockerよりも多くのこと行う
  • Buildahとは何か、なぜ必要なのか?

Podmanのインストール

現在Dockerを使っているのであれば、移行しようと決めた時点でDockerを削除できます。しかし、Podmanを試している間はDockerを使い続けたいかもしれません。便利なチュートリアルと素晴らしいデモがあるので、移行をより理解するために最初に実行してみるといいでしょう。デモの例では、互換性を示すためにDockerを必要としています。

Red Hat Enterprise Linux 7.6以降にPodmanをインストールするには、以下のようにします。Fedoraを使用している場合は、yumをdnfに置き換えてください。

# yum -y install podman

PodmanコマンドはDockerコマンドと同じ

Podmanを構築する際の目標は、Dockerユーザーが簡単に適応できるようにすることでした。そのため、おなじみのコマンドはすべてPodmanにも存在しています。実際、Dockerを実行する既存のスクリプトを持っていれば、podman用のdockerエイリアス(alias docker=podman)を作成すれば、すべてのスクリプトが動作するはずです。もちろん、最初にDockerを停止(systemctl stop docker)しておく必要があります。podman-dockerというパッケージをインストールすれば、この変換を行ってくれます。/usr/bin/dockerのスクリプトをドロップし、同じ引数でPodmanを実行します。

あなたがよく知っているコマンド、例えばpull、push、build、run、commit、tagなどはすべてPodmanに含まれています。詳細については、Podmanのマニュアルページを参照してください。特筆すべき違いは、Podmanが一部のコマンドにいくつかの便利なフラグを追加したことです。例えば、Podmanでは、podman rmとpodman rmiに--all (-a)フラグが追加されています。便利だと感じるユーザーが多いはずです。

また、Fedora上のPodman 1.0では、通常の非rootユーザーからもPodmanを実行することができます。RHELのサポートはバージョン7.7と8.1以降を対象としています。ユーザースペースのセキュリティが強化されたことで、これが可能になりました。通常のユーザーとしてPodmanを実行すると、デフォルトではPodmanはイメージとコンテナをユーザーのホームディレクトリに保存します。これについては次のセクションで説明します。Podmanを非rootユーザーとして実行する方法の詳細については、Dan WalshさんのHow does rootless Podman work?1をご覧ください。

Pormanとコンテナイメージ

最初にpodman imagesと入力すると、すでにプルされているDockerイメージが表示されていないことに驚くかもしれません。これは、Podmanのローカルリポジトリが/var/lib/dockerではなく/var/lib/containersにあるからです。恣意的な変更ではなく、この新しいストレージ構造はOpen Containers Initiative(OCI)に準拠しています。

2015年、Docker、Red Hat、CoreOS、SUSE、GoogleなどのLinuxコンテナ業界のリーダーたちは、コンテナイメージとランタイムを定義するための標準仕様を管理する独立した組織をとして、Open Container Initiativeを設立しました。その独立性を維持するために、containers/imageプロジェクトとcontainers/storageプロジェクトがGitHub上に作られました。

rootでなくてもpodmanを実行できるため、podmanがイメージを書き込める別の場所が必要です。Podmanはユーザーのホームディレクトリにあるリポジトリを利用します。Podmanはユーザーのホームディレクトリにあるリポジトリ、つまり~/.local/share/containersを利用します。これにより、/var/lib/containersが誰でも書き込み可能になることや、潜在的なセキュリティ問題につながる可能性のあるその他の方法を回避できます。また、これにより、すべてのユーザーが別々のコンテナとイメージのセットを持ち、すべてのユーザーが同じホスト上で、お互いに干渉せずに同時にPodmanを使用できるようになります。ユーザーは作業が終わったら、共通のレジストリにプッシュしてイメージを他の人と共有することができます。

Podmanを使うようになったDockerユーザーは、これらの場所を知っていると、デバッグややり直したいときに重要なrm -rf /var/lib/containersを行う際に、便利だと気付きます。しかし、Podmanを使い始めると、おそらくpodman rmとpodman rmiに対して新しい--allオプションを代わりに使うでしょう。

コンテナイメージはPodmanと他のランタイムの間で互換性がある

ローカルリポジトリの場所が新しくなったにも関わらず、DockerやPodmanで作成されたイメージはOCI標準と互換性があります。Podmanはプライベートレジストリだけでなく、Quay.ioやDocker hubのような一般的なコンテナレジストリへのプッシュやプルも可能です。例えば、Docker hubから最新のFedoraイメージをプルして、Podmanを使って実行することができます。レジストリを指定しないと、Podmanはデフォルトでregistries.confファイルにリストされているレジストリを順番に検索することになります。registries.confファイルが変更されていない場合は、最初にDocker hubを検索します。

$ podman pull fedora:latest
$ podman run -it fedora bash

Dockerでイメージレジストリにプッシュしたイメージは、Podmanでプルして実行することができます。以下の例のように、Dockerを使って作成したイメージ(myfedora)をDockerを使ってQuay.ioのリポジトリ(ipbabble)にプッシュしたものは、以下のようにPodmanでプルして実行することができます。

$ podman pull quay.io/ipbabble/myfedora:latest
$ podman run -it myfedora bash

Podmanのコマンドラインでは、pushコマンドとpullコマンドで、イメージを/var/lib/dockerから/var/lib/containersに、またはその逆に適切に移動させる機能を提供します。 例えば、次のようにできます。

$ podman push myfedora docker-daemon:myfedora:latest

上記のdocker-daemonを除外すると、デフォルトでDocker hubにプッシュされます。quay.io/myquayid/myfedoraを使うと、イメージをQuay.ioレジストリにプッシュします。但し、myquayidは、個人のQuay.ioアカウントです。

$ podman push myfedora quay.io/myquayid/myfedora:latest

Dockerを削除する準備ができたら、デーモンをシャットダウンしてからパッケージマネージャを使ってDockerパッケージを削除してください。但し、Dockerで作成したイメージを保持しておきたい場合は、それらのイメージがレジストリにプッシュされていることを確認して、後でそれらをプルできるようにしておく必要があります。もしくは、Podmanを使って、ホストのDockerリポジトリからPodmanのOCIベースのリポジトリに各イメージ(例えばfeedora)を引っ張ってくることもできます。RHELでは以下のように実行できます。RHELでは以下のように実行できます。

# systemctl stop docker
# podman pull docker-daemon:fedora:latest
# yum -y remove docker  # optional

Podmanは、Kubernetesへの移行を支援する

Podmanは、Kubernetes環境での開発者や運用者を支援するいくつかの追加機能を提供しています。これには、Dockerでは利用できないものが含まれます。Dockerに慣れ親しんでいて、コンテナプラットフォームとしてKubernetes/OpenShiftの使用を検討している場合、Podmanが役立ちます。

Podmanは、podman generate kubeを使用して実行中のコンテナに基づいてKubernetesのYAMLファイルを生成できます。podman podというコマンドは、標準のコンテナコマンドとともに、実行中のKubernetesポッドのデバッグを支援するのに役立ちます。PodmanがどのようにKubernetesへの移行を支援するかの詳細については、Brent BaudeさんのPodman can now ease the transition to Kubernetes and CRI-Oを参照ください。

Buildahとは何か?なぜ使うのか?

実はBuildahが先に出てきました。一部のDockerユーザーは少し混乱してしまうのは、そのためかも知れません。「なぜこのPodmanエバンジェリストたちもBuildahの話をしているんだろう?Podmanはビルドをしないのか?」

Podmanはビルドを行いますし、Dockerに詳しい人にとってはビルドのプロセスは同じです。podman buildを実行してDockerfileを使ってビルドするか、コンテナを実行して多くの変更を加え、その変更を新しいイメージタグにコミットするかのどちらかです。Buildahはコンテナイメージの作成と管理に関連したコマンドのスーパーセットと表現することができ、イメージに対してより細かい制御を行うことができます。PodmanのbuildコマンドにはBuildahの機能のサブセットが含まれています。ビルドにはBuildahと同じコードを使用します。

Buildahを使う最も強力な方法は、Dockerfileを書くのと同じようにイメージを作成するためのBashスクリプトを書くことです。

次のように進化したと考えるとよいです。KubernetesがOCIランタイム仕様に基づいたCRI-Oに移行したときに、Dockerデーモンを実行する必要がありません。そのため、Kubernetesクラスタ内のどのホストについても、ポッドやコンテナを動かすためにDockerをインストールする必要がありませんでした。KubernetesはCRI-Oを呼び出すことができ、runCを直接呼び出すことができました。これにより、コンテナプロセスが起動します。しかし、OpenShiftクラスタを使う場合などで、同じKubernetesクラスタを使ってビルドを行う際に、Dockerデーモンを必要とせず、その後にDockerのインストールを必要としないビルド用の新しいツールが求められました。そのようなツールは、containers/storageプロジェクトとcontainers/imageプロジェクトをベースにしており、多くのユーザーが懸念していたビルド時のオープンなDockerデーモンソケットのセキュリティリスクも排除することができます。

Buildah(「builder」を発音するときのDan Walshさんのボストンアクセントが面白いからいう理由で名付けられた)は、この要望に合致しました。Buildahの詳細についてはbuildah.ioを参照し、特にブログやチュートリアルのセクションをご覧ください。

実務者がBuildahについて理解しておくべきことは、いくつかあります。

  1. イメージレイヤーの作成をより細かく制御できるようになります。これは多くのコンテナユーザーが長い間求めていた機能です。1つのレイヤーに多くの変更をコミットすることが望ましいです。
  2. Buildahのrunコマンドは、Podmanのrunコマンドとは異なります。Buildahはイメージをビルドするためのものなので、runコマンドは基本的にDockerfileのRUNコマンドと同じです。実際、私はこれを明示されたときのことを覚えています。試していたポートやマウントが思ったように動かないと愚痴っていました。Danさん(@rhatdan)は、Buildahはそのような方法でのコンテナ実行をサポートすべきではないと意見を述べました。ポートマッピングもしないし、ボリュームマウントもありません。これらのフラグは削除されました。 代わりに buildah runはコンテナイメージの構築を支援するために特定のコマンドを実行するためのもので、例えばbuildah run dnf -y install nginxのようになります。
  3. buildah はゼロからイメージを構築することができます。ゼロからです。実際、buildah from scratchコマンドの結果として作成されたコンテナストレージを見ると、空のディレクトリが表示されます。これは、アプリケーションを実行するために必要なパッケージだけを含む、非常に軽量なイメージを作成するのに便利です。

スクラッチビルドの良い使用例は、Javaアプリケーションの開発用イメージとステージング用イメージ、または本番用イメージを比較することです。開発中のJavaアプリケーションコンテナイメージは、JavaコンパイラやMavenなどのツールを必要とすることがあります。しかし、本番環境では、Javaランタイムとパッケージだけでいいかもしれません。ちなみに、DNF/YUMやBashなどのパッケージマネージャも必要ありません。Buildahはこのユースケースのための強力なCLIです。下の図を参照してください。詳しくは、Building a Buildah Container Image for Kubernetesや、こちらのBuildahのデモを参照してください。

進化の話に戻ります。CRI-OとrunCでKubernetesのランタイム問題を解決し、Buildahでビルド問題を解決した今でも、Kubernetesホスト上でDockerがまだ必要とされている理由が1つありました。デバッグです。デバッグするためのツールがない場合、どうやってホスト上でコンテナの問題を確認できるでしょうか?Dockerをインストールする必要があれば、ホスト上でDockerデーモンを使用していた時のような状態に戻ってしまいます。しかし、Podmanはこの問題を解決します。

Podmanは2つの問題を解決するツールになります。運用者が使い慣れたコマンドで、コンテナやイメージを調べることを可能にします。そして、開発者にも同じツールを提供します。つまり、Dockerユーザーでも開発者でも運用者でも、Podmanに移行して、Dockerで慣れ親しんだ楽しいタスクをすべて行うことができ、さらに多くのことができるようになります。

結論

この記事が役に立ち、自信を持って無事にPodman(および Buildah)へ移行できることを願います。

より詳細な情報は、以下をご覧ください。

  • Podman.ioプロジェクトとBuildah.ioプロジェクトのWebサイト
  • github.com/containersプロジェクト: 参加したり、ソースを入手したり、開発中のものを見たりできます
    • libpod (Podman)
    • buildah
    • image: OCI コンテナイメージを扱うためのコード
    • storage: ローカルイメージおよびコンテナストレージのためのコード

関連記事


  1. 日本語版の記事「ルートレスのPodmanはどのように動作しますか?」もあります

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。