NetBSDでPodmanからLinuxコンテナを動かす

2021年10月30日 初稿

注: 技術検証記事ではありません。


Podmanはコンテナエンジンのひとつです。Red Hat Enterprise Linuxがバージョン7から8にメジャーアップデートしたさい、Dockerから標準のコンテナエンジンとして置き換わった実績があります。Dockerと比べ裏でデーモンを動かすことなく(daemonless)、かつルート権限不要(rootless mode)で動作します。

2021年9月4日、coypuがnetbsd-usersに投稿した『Running docker containers with podman (on NetBSD!)』のとおり、pkgsrc-currentにPodmanパッケージが追加されNetBSDでもPodmanを利用できるようになりました[1]。

pkgsrc自体はNetBSDとは独立したパッケージ管理システムですから、NetBSDカーネルでOCI Runtime準拠のコンテナを動かせられるようになったというわけではありません。Podmanはpodman machineコマンドからコンテナを動かす仮想マシン(VM)を管理できます。NetBSDにインストールされたPodmanはこの機能を活用し、QEMU-NVMMからFedoraが動くVMを用意してコンテナそのものはFedora OSの中で動作させます。

VMを経由させるので、ネイティブなLinuxディストリビューションで動かすより性能面で見劣りする可能性があります。ただしVMはNVMMでハードウェアアクセラレーションしているのでアプリケーションの開発や動作検証用途ならほとんど影響はないでしょう。またこれもほとんど問題にならないとは思いますが、NVMMの都合上アーキテクチャがx86_64に制限されます。

インストールはメールに書いてあるとおり以下の手順で完了します。podman machineのマニュアルはhttps://docs.podman.io/en/latest/markdown/podman-machine.1.htmlで公開されています。

  1. pkgsrc/sysutils/podmanをインストールする
  2. podman machine initしてpodman machine startする

既知の問題として、Podman用のLinux VMがAPIC関連のカーネルパニックを起こすことが知られています。NetBSDカーネルにoptions HZ=1000を設定してビルドするか、VMのGRUBでブートエントリにnoapicを与えることで回避できます。Podman用Linux VMのブートエントリを手動で編集する方法はLeonardo Taccariが返信しているメールから確認できます[2]。大まかには次のようにします。

  1. Podman VMのイグニションファイル(ignition file)を編集してnoapicオプションがブートエントリに存在することを保証させる。
  2. Podman VMを手動で起動しブートエントリにnoapicを追加する。

OCIコンテナのネイティブサポートでないとはいえ、PodmanのインタフェースからDocker/Podmanコンテナを使えるようになったことで別プラットフォームを対象にした開発がやりやすくなったのではないかと思います。なにか即席でアプリケーションを動かしたいときもDocker Hubからダウンロードしてきてすぐに使えるようになったのも便利でしょう。

僕のPCではCPUがNested Virtualizationに対応していないおかげでbhyveから動かしているNetBSDではコンテナの動作確認ができませんでした。というわけでこの話はもう終わりです。

参考文献

netbsd-usersに投稿されたPodmanパッケージ追加を知らせるメール全文


To: netbsd-users%netbsd.org@localhost
Subject: Running docker containers with podman (on NetBSD!)
From: coypu%sdf.org@localhost
Date: Sat, 4 Sep 2021 21:06:02 +0000

Hi all,

I added a package to pkgsrc called Podman.
It's a tool for running OCI containers, and it has the same command line
behaviour as the docker command line argument.

There are some selling points for it over docker, but the most important
for us is the fact it has a mode where it spawns a Linux VM to talk to
for you, so it runs on NetBSD!

One caveat is that NetBSD somewhat struggles running virtualized Linux
by default. The virtualized ticks are just too slow, so it panics with:
  Kernel panic - not syncing: IO-APIC + timer doesn't work! Boot with
  apic=debug and send a report. Then try booting with the 'noapic' option.

One way to work around it, convenient for this purpose, is to rebuild
your kernel with "options HZ=1000" added, then you don't need to edit
the command line arguments in the VM.

Usage instructions:
Install pkgsrc/sysutils/podman from pkgsrc-current
Initialize and start a VM with:
podman machine init
podman machine start

And then you can use it much like the docker command:
> podman run -it alpine sh -c "apk add file; file -L /bin/sh"
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
(1/2) Installing libmagic (5.40-r1)
(2/2) Installing file (5.40-r1)
Executing busybox-1.33.1-r3.trigger
OK: 13 MiB in 16 packages
/bin/sh: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, stripped

Leonardo TaccariによるPodman VMのブートエントリ編集手順


To: netbsd-users%netbsd.org@localhost
Subject: Re: Running docker containers with podman (on NetBSD!)
From: Leonardo Taccari <leot%NetBSD.org@localhost>
Date: Sun, 05 Sep 2021 22:12:53 +0200

  coypu%sdf.org@localhost writes:
> Hi all,
>

Hello coypu!

> I added a package to pkgsrc called Podman.
> It's a tool for running OCI containers, and it has the same command line
> behaviour as the docker command line argument.
>
> There are some selling points for it over docker, but the most important
> for us is the fact it has a mode where it spawns a Linux VM to talk to
> for you, so it runs on NetBSD!
>

That's really nice, thank you very much for working on it!

> One caveat is that NetBSD somewhat struggles running virtualized Linux
> by default. The virtualized ticks are just too slow, so it panics with:
>   Kernel panic - not syncing: IO-APIC + timer doesn't work! Boot with
>   apic=debug and send a report. Then try booting with the 'noapic' option.
>
> One way to work around it, convenient for this purpose, is to rebuild
> your kernel with "options HZ=1000" added, then you don't need to edit
> the command line arguments in the VM.
> [...]

I was tempted to try the other workaround, i.e. append `noapic'
directly at the boot but... that was a bit challenging! :)  So here all
the notes that I have collected.

 1. Download the image via:
     podman machine init
 2. After the image is downloaded and extracted SSH keys will be
    generated under ~/.ssh and there will be a Ignition config in
    ~/.config/containers/podman/machine/qemu/podman-machine-default.ign.
    In order to append `noapic' to the kernel arguments we need to
    adjust the following in podman-machine-default.ign:
	2a. Reindent the JSON to be a bit easier to edit, e.g. via
            `jq .'
	2b. Bump .ignition.version to "3.3.0" (it is "3.2.0")
	2c. At the end, after systemd object add a comma `,' and then
	    another JSON object:
                "kernelArguments": {
                  "shouldExist": ["noapic"]
                }
 3. Manually run the image via QEMU in order to initialize it via the
    ignite config so that `noapic' is appended.  Assuming we are in our
    home directory, e.g.:
     qemu-system-x86_64 -accel nvmm -nographic -m 1G -smp 1 \
	 -fw_cfg name=opt/com.coreos/config,file=.config/containers/podman/machine/qemu/podman-machine-default.ign \
         -drive if=virtio,file=.local/sif=virtio,file=.local/share/containers/podman/machine/qemu/podman-machine-default_fedora-coreos-34.20210821.1.1-qemu.x86_64.qcow2
 4. In GRUB press `e' in order to edit the boot entry.  In the kernel
    line append at the end `noapic' and press Ctrl-x to boot it
 5. The ignition config will be applied and it will reboot
 6. In GRUB press `c' and then `halt' in order to poweroff the machine
    (we're done!)
 7. Start the machine as usual via `podman machine start'