rootlessコンテナの運用
目標
rootlessでコンテナを実行し、ボリューム・ユーザーマッピング・ポートの制約を直接確認して、Quadletユニットファイルを作成します。
なぜ重要なのか
dockerからpodmanへ移すときに、必ず引っかかることが決まっています。restart: alwaysが起動時の自動開始を意味しないこと(デーモンがないので)、1024未満のポートにバインドできないこと、ボリュームのファイルの所有者が、見慣れないUIDに見えること、SELinux環境では:ZラベルがないとPermission deniedになること。この4つを事前に知っていれば、切り替えは30分で、知らなければ半日です。
そして、起動時の自動開始の、podman流の正解はQuadletです。.containerファイルを置くと、systemdがそれを読んで、サービスユニットを生成します。podman generate systemdは、古い方式になりました。\n\n## このラボは仮想マシン上で動きます\n\nrootless podmanが本当に動きます。Podでは、newuidmapがCAP_SETUIDを要求するため、subuid範囲を渡せず、そのためこのラボが中途半端でした。コンテナが実際に起動しないので、採点も、ファイルだけを見るしかありませんでした。\n\nVMでは、podman runがそのまま動き、ステップ7のQuadletも、本当にサービスに変換されて起動します。systemctl --user status labhub-webで、直接確認できます。初回の起動には、1分あまりかかります。
ステップ
/root/podrunディレクトリを作成して、podsterの権限で/opt/images/labhub-alpine.tarをロードしたあと、イメージ一覧を/root/podrun/images.txtに保存してください。- そのイメージで、コンテナを一度実行して
echo labhub-okを行い、出力を/root/podrun/run.txtに保存してください。 /home/podster/dataをコンテナの/dataにマウントして、コンテナ内で/data/hello.txtを作成し、ホストでそのファイルが見えるかを確認して、/root/podrun/volume.txtに、ファイルのパスと内容を保存してください。- ステップ3で作成したファイルの、ホスト側の所有者UIDを、数字1行で
/root/podrun/owner.txtに書いてください。 - 特権ポートの公開を試みて失敗させ、そのエラーメッセージを
/root/podrun/port-fail.txtに保存してください。そのあと、8090番ポートでもう一度試して成功した結果を、/root/podrun/port-ok.txtに保存してください。 labhub-webという名前で、コンテナをバックグラウンドで実行して、podman psの出力を/root/podrun/ps.txtに保存してください。一覧に、その名前が見える必要があります。/home/podster/.config/containers/systemd/labhub-web.containerを作成してください。[Unit]、[Container]、[Install]の3つのセクションがある必要があり、[Container]にはImage、PublishPort、Volumeの3つのキーが、[Install]にはWantedByがある必要があります。/root/podrun/diff.txtを、次の6行で作成してください。DAEMON=none/STORAGE=<podster 의 graphRoot 절대 경로>/PRIVPORT=denied/RESTART=quadlet/GPUFLAG=--device/SELINUX_LABEL=:Z(プレースホルダーはpodsterのgraphRootの絶対パスです)
参考
- 実行は、
su - podster -c "podman run --rm localhost/labhub-alpine:1 sh -c 'echo labhub-ok'"の形です。 - ボリュームは、
-v /home/podster/data:/data:Zでマウントします。 - バックグラウンド実行は、
-d --name labhub-webです。終了せずに、残しておいてください。 - Quadletファイルは、実行されなくてもかまいません。文法と必須キーだけを採点します。
- このノードでは、コンテナランタイムがブロックされている可能性があります。非特権のuser namespaceの作成がブロックされると、rootless podmanは
cannot re-exec processで終わります。その場合も、コマンドを実際に実行して、その出力(エラーを含む)を、指定されたファイルにそのまま保存してください。採点では、環境を検出して、その記録と作成した設定を基準に判定します。 - よくある間違い1: ステップ3で、ボリュームディレクトリをroot所有で作成して、podsterが書き込めなくなること。
- よくある間違い2: ステップ5で、失敗メッセージを標準出力だけで受け取ろうとしてしまうこと。エラーは、標準エラー出力に出ます。
イメージをロードする
/root/podrunディレクトリを作成して、podsterの権限で/opt/images/labhub-alpine.tarをロードしたあと、イメージ一覧を/root/podrun/images.txtに保存してください。
インターネットがないので、あらかじめ用意されたアーカイブを使います。ロード後、一覧で確認してください。
コンテナを実行する
そのイメージで、コンテナを一度実行してecho labhub-okを行い、出力を/root/podrun/run.txtに保存してください。
1回限りの実行には、終了後に片付けるオプションを付けます。出力を、ファイルに残してください。
ボリュームをマウントする
/home/podster/dataをコンテナの/dataにマウントして、コンテナ内で/data/hello.txtを作成し、ホストでそのファイルが見えるかを確認して、/root/podrun/volume.txtに、ファイルのパスと内容を保存してください。
ホストのパスとコンテナのパスを、コロンでつなぎます。SELinux環境に備えて、ラベルのオプションも付けてください。
ユーザーマッピングを確認する
ステップ3で作成したファイルの、ホスト側の所有者UIDを、数字1行で/root/podrun/owner.txtに書いてください。
ボリュームに作成したファイルをホストで見ると、所有者がマッピングされたUIDに見えます。keep-idオプションを使うと、変わります。
特権ポートの失敗を再現する
特権ポートの公開を試みて失敗させ、そのエラーメッセージを/root/podrun/port-fail.txtに保存してください。そのあと、8090番ポートでもう一度試して成功した結果を、/root/podrun/port-ok.txtに保存してください。
1024未満のポートを公開しようとすると、失敗します。そのエラーメッセージをそのまま保存して、高いポートでもう一度試してください。
実行中のコンテナを確認する
labhub-webという名前で、コンテナをバックグラウンドで実行して、podman psの出力を/root/podrun/ps.txtに保存してください。一覧に、その名前が見える必要があります。
名前を指定して起動すると、管理が楽になります。出力の形式を指定するオプションがあります。
Quadletユニットを作成する
/home/podster/.config/containers/systemd/labhub-web.containerを作成してください。[Unit]、[Container]、[Install]の3つのセクションがある必要があり、[Container]にはImage、PublishPort、Volumeの3つのキーが、[Install]にはWantedByがある必要があります。
拡張子が.containerのファイルです。[Container]セクションにImageが必須で、[Install]も必要です。
dockerとの違いをまとめる
/root/podrun/diff.txtを、次の6行で作成してください。
DAEMON=none / STORAGE=<podster 의 graphRoot 절대 경로> / PRIVPORT=denied / RESTART=quadlet / GPUFLAG=--device / SELINUX_LABEL=:Z(プレースホルダーはpodsterのgraphRootの絶対パスです)
値は、前のステップで実際に確認したものである必要があります。保存先のパスは、絶対パスで書いてください。