Podmanをやってみよう

Podman(Podマネージャ)は、Redhat社が中心となって開発し、2019年のバージョン1.0.0からオープンソースとして提供されているコンテナ管理ツールです。

コンテナ管理ツールと言えばDockerが有名ですが、RHEL8以降ではDockerのサポートが廃止され、Redhat社はPodmanの利用を推奨しています。

Podmanの基本コマンドは「podman」であり、Dockerの基本コマンド「docker」と互換性があります。例えばコンテナの実行状況を確認する「docker ps」コマンドは「podman ps」のようになります。この他のコマンドもほぼ同様であるため、PodmanはDockerのナレッジを活用できる点で取り組みやすさがあります。

PodmanとDockerの違いについては、大きく2つが挙げられます。

1つ目は「デーモンレス」であることです。Dockerはrootで実行されているデーモン(daemon)を介してカーネル(Kernel)にアクセスしています。

Dockerの関係模式図

一方、Podmanは直接カーネルにアクセスできるため、デーモンを必要としていません。

Podmanの関係模式図

そのため、Dockerはデーモンに異常が発生した場合は、全てのコンテナが悪影響を受けてしまいますが、デーモンレスのPodmanにおいては、そのようなことは起こらないため、Redhat社がPodmanの利用を推奨しています。

2つ目は「ルートレスモード」です。Dockerのコンテナはrootで実行されるDockerデーモンによって制御されているため、もしDockerにセキュリティ上の脆弱性があった場合は、システム全体に悪影響を及ぼす可能性が考えられます。

一方、Podmanはユーザ権限下で実行されており、Linuxの機能であるユーザ名前空間によりユーザの権限以上の操作を抑制することで、rootのようなホストの特権を利用せずにコンテナ管理できる点でセキュリティが高いと言われています。

ただし、Dockerもバージョン19.03からはルートレスモードが標準で利用できようになったので、実質は「デーモンレス」であることがPodmanとDockerの大きな違いと言えるのかもしれません。

Podmanをやってみよう

Podmanの概要を理解したところで、さっそくPodmanをインストールしてみましょう。PodmanはRHEL 7.6及びCentOS 7.6以降でインストール可能です。また、MacやWindows版のPodman Desktopも存在しています。

今回は、以下のOSにPodmanをインストールしてみます。

$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)

インストール

インストールは、yumで行います。

$ yum install podman

Podmanのインストールが完了したら、バージョンを確認してみます。

$ podman -v
podman version 1.6.4

バージョン情報が返ってきたらインストールは成功です。

ルートレスモードで起動する

CentOS 7.8にインストールしたPodmanを、ユーザ(testuser)から操作すると以下のようなエラーに遭遇します。

$ podman ps
cannot clone: Invalid argument
user namespaces are not enabled in /proc/sys/user/max_user_namespaces
Error: could not get runtime: cannot re-exec process

これは、Podmanがルートレスモードで起動するためにLinuxカーネルに実装されている「ユーザー名前空間」を使用しているために発生します。通常、「user.max_user_namespaces」というカーネルパラメータはデフォルトは0となっています。

このカーネルパラメータを0以外の数値に変更します。Redhatによると15,000などの大きな数値に変更することを推奨しています。

ユーザー名空間の完全なサポート

Red Hat Enterprise Linux 7.2 でテクノロジープレビューとして導入されたユーザーネームスペース (userns) が完全にサポートされるようになりました。この機能は、ホストとコンテナー間の分離を改善することにより、Linux コンテナーを実行しているサーバーに追加のセキュリティーを提供します。コンテナーの管理者は、ホスト上で管理操作を実行できなくなり、セキュリティーが向上します。

user.max_user_namespaces のデフォルト値は 0 です。この値をゼロ以外の値に設定すると、誤動作するアプリケーションを停止できます。user.max_usernamespaces は、15000 などの大きな値に設定することが推奨されます。これにより、通常の操作では値に再度アクセスする必要はありません。

第12章 カーネル Red Hat Enterprise Linux 7 | Red Hat Customer Portal

CentOS 7.8では、以下のようにファイルを変更して

$ vi /etc/sysctl.d/42-rootless.conf

user.max_user_namespaces=15000  ← 値を0から15,000に修正

ファイルを修正し保存したら、以下のコマンドでカーネルパラメータの変更を適用します。

$ sysctl --system

* Applying /etc/sysctl.d/42-rootless.conf ...
user.max_user_namespaces = 15000

$ sysctl -a | grep user_namespace

user.max_user_namespaces = 15000

カ-ネルパラメータの修正が適用されましたので、再度、Podmanをユーザ(testuser)から操作してみます。今度は先ほどと異なるエラーが表示されます。

$ podman ps
ERRO[0000] cannot find mappings for user testuser: No subuid ranges found for user "testuser" in /etc/subuid
ERRO[0000] cannot find mappings for user testuser: No subuid ranges found for user "testuser" in /etc/subuid
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES

 Podmanは、「/etc/subuid」と「/etc/subgid」で定義されている代替マッピングのUIDおよびGIDを使用してユーザのプロセスを実行します。RHELやCentOSなどのディストリビューションでは、「/etc/subuid」と「/etc/subgid」が自動的に追加されることがないため、以下のように手動でファイルを修正します。

$ vi /etc/subuid
testuser:100000:65536

$ vi /etc/subgid
testuser:100000:65536

再度、Podmanをユーザ(testuser)から操作してみます。上記の設定により、コンテナ内の特権(root)ユーザは100000というUIDとGIDを持つ一般ユーザとして動作し、ホストの特権(root)ユーザのUIDと別物として取り扱われるため、セキュリティ面で安全性が高くなります。

$ podman ps
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES

$ podman images
REPOSITORY   TAG   IMAGE ID   CREATED   SIZE

上記の設定が適用されエラーがなくなることで、podmanコマンドがルートレスモードにより正常に利用できるようになったことが確認できました。

Podmanのコンテナを起動してみる

ルートレスモードでPodmanのコンテナを起動してみます。

Podmanは、デフォルトではRedhatのレジストリ(registry.access.redhat.com又はregistry.redhat.io)及びDockerのレジストリ(docker.io)からイメージをpullすることができます。

Redhatのリポジトリを利用する場合はRedhatの認証情報が必要になるため、今回はDockerのレジストリ(docker.io)からnginxのコンテナイメージを取得してみます。

$ podman pull docker.io/library/nginx:latest
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob 4f3256bdf66b done
Copying blob 8c767bdbc9ae done
Copying blob 78e14bb05fd3 done
Copying blob 2019c71d5655 done
Copying blob 75576236abf5 done
Copying blob 26c5c85e47da done
Copying config 6efc10a051 done
Writing manifest to image destination
Storing signatures
  Error processing tar file(exit status 1): there might not be enough IDs available in the namespace (requested 0:42 for /etc/gshadow): lchown /etc/gshadow: invalid argument
Error: error pulling image "docker.io/library/nginx:latest": unable to pull docker.io/library/nginx:latest: unable to pull image: Error committing the finished image: error adding layer with blob "sha256:26c5c85e47da3022f1bdb9a112103646c5c29517d757e95426f16e4bd9533405": Error processing tar file(exit status 1): there might not be enough IDs available in the namespace (requested 0:42 for /etc/gshadow): lchown /etc/gshadow: invalid argument

何らかのエラーが発生していて、イメージをpullできませんでした。Podmanをルートレスモードで起動するために「/etc/subuid」と「/etc/subgid」を手動で修正した場合は、その設定を適用するためにpodman system migrateコマンドを実行する必要があります。

$ podman system migrate

特にメッセージが表示されなければ問題はありません。

コンテナイメージをpullする

コンテナイメージは、podman pullコマンドを使用して取得します。

$ podman pull docker.io/library/nginx:latest
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob 78e14bb05fd3 done
Copying blob 75576236abf5 done
Copying blob 26c5c85e47da done
Copying blob 4f3256bdf66b done
Copying blob 8c767bdbc9ae done
Copying blob 2019c71d5655 done
Copying config 6efc10a051 done
Writing manifest to image destination
Storing signatures
6efc10a0510f143a90b69dc564a914574973223e88418d65c1f8809e08dc0a1f

コンテナイメージの取得が完了したら、ローカル上に格納されたコンテナイメージを一覧表示します。

$ podman images
REPOSITORY                TAG      IMAGE ID       CREATED       SIZE
docker.io/library/nginx   latest   6efc10a0510f   2 weeks ago   147 MB

podman pullコマンドで取得したNginxのコンテナイメージがローカル上に格納されていることが確認できました。

Nginxをコンテナ起動してみる

NginxをPodmanのコンテナで起動してみます。

$ podman run -d -p 8080:80 --name test_nginx nginx
02596cf111d61469d0eca6d13ec1bea0ffc662697dbe71cd47b4ad3a09816873

$ podman ps
CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS                 NAMES
02596cf111d6  docker.io/library/nginx:latest  nginx -g daemon o...  5 seconds ago  Up 4 seconds ago  0.0.0.0:8080->80/tcp  test_nginx

test_nginxというコンテナが起動しましたので、curlからアクセスしてみます。

$ curl http://localhost:8080

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Nginxのデフォルトのhtmlが返ってきました。

ルートレスモードで起動したPodmanのコンテナが問題なく動作していることが確認できました。

コンテナの停止とイメージの削除

稼働中のtest_nginxコンテナを停止します。コンテナの停止はpodman stopコマンドを使用します。

$ podman stop test_nginx
02596cf111d61469d0eca6d13ec1bea0ffc662697dbe71cd47b4ad3a09816873

$ podman ps -a
CONTAINER ID  IMAGE                           COMMAND               CREATED         STATUS                         PORTS                 NAMES
02596cf111d6  docker.io/library/nginx:latest  nginx -g daemon o...  25 minutes ago  Exited (0) About a minute ago  0.0.0.0:8080->80/tcp  test_nginx

$ podman rm test_nginx
02596cf111d61469d0eca6d13ec1bea0ffc662697dbe71cd47b4ad3a09816873

$ podman ps -a
CONTAINER ID  IMAGE  COMMAND  CREATED  STATUS  PORTS  NAMES

最後にコンテナイメージを削除します。コンテナイメージの削除は、podman rmiコマンドを使用します。

$ podman images
REPOSITORY                TAG      IMAGE ID       CREATED       SIZE
docker.io/library/nginx   latest   6efc10a0510f   2 weeks ago   147 MB

$ podman rmi 6efc10a0510f
Untagged: docker.io/library/nginx:latest
Deleted: 6efc10a0510f143a90b69dc564a914574973223e88418d65c1f8809e08dc0a1f

$ podman images
REPOSITORY   TAG   IMAGE ID   CREATED   SIZE

まとめ

いかがでしたでしょうか。Podmanのインストール、ルートレスモード(ユーザ空間名前)の設定、コンテナイメージの取得及びPodmanのコンテナに関する基本的な操作方法について解説しました。

今回の解説で登場したPodmanコマンドは、以下の表のとおりです。しっかりと理解しておきましょう。

Podmanコマンド概要
podman -vPodmanのバージョン表示
podman psPodmanのコンテナを一覧表示する
podman ps -a停止中のPodmanのコンテナを含むすべてのコンテナを一覧表示する
podman pullレジストリからコンテナイメージをローカル上に取得する
podman system migrateユーザ名前空間など設定変更した内容をPodmanに適用する
podman imagesローカル上に格納されているコンテナイメージを一覧表示する
podman runコンテナイメージをコンテナ起動する
podman stopコンテナを停止する
podman rm停止中のコンテナを削除する
podman rmiコンテナイメージをローカル上から削除する
Podmanコマンドの概要

PodmanのコマンドはDockerとほとんど変わりがないため、Dockerを既に経験した人にとってPodmanの学習コストは低いと言えるかもしれません。

2023年5月時点における筆者の感想は、PodmanとDockerの大きな差はデーモンレスかどうかの差でしかないため、PodmanがDockerにとって代わるということではなく、両方のコンテナ管理ツールを自由に使いこなせることの方が重要だと感じました。

ただし、DockerとPodmanではリリースの頻度が異なり、Podmanの方が頻繁に最新リリースが提供されることを考えると、将来的にPodmanの市場が拡大してくる可能性が十分に考えられます。

使い勝手にほとんど差がないPodmanとDockerの行方に注目していきたいとおもいます。

参考になれば幸いです。

システムのお悩みについてご相談ください

本サイトの掲載内容に関するお問い合わせは、こちらから承ります。
SOHOのシステム運用管理に関するお悩みごとについて、なんでもお気兼ねなくご相談ください。
現役システムエンジニアのスタッフが、ボランティアでご相談にご対応させていただきます。