How to use Podman with FreeBSD(ocijail)

FreeBSDでは14.2Rより、OCI互換のIMAGEが用意されています。これによってPodmanでOCIフォーマットのイメージを読み込み、それをJailコンテナとして利用することができます。
これはocijailというバックエンドによって動作しています。

まだまだFreeBSDのPodmanは荒削りでありPoCレベルを超えていませんが、それでもdockerのような決定的なインターフェイスがなかなか出なかったJail界においては大きな前進と言えるのではないでしょうか。

このイメージは3つ用意されており、`static`,`dynamic`,`minimal`があります。
これらの詳細は参照元を確認してください。
簡単にいうと、staticではlibcなどもない完全に最小のシステム、dynamicはstatic+libc,shared libs、minimalはdynamic+sh,minimal baseです。

## Install podman
 podmanのインストール自体は`pkg`ですぐにできます。
```sh
# pkg install podman
```
その後、pf.confやfstabの設定等をします。sampleファイルがあるのでそれを基に設定します。
```sh
# pkg list buildah podman conmon ocijail containers-common \ containernetworking-plugins \ |grep /etc/ /usr/local/etc/containers/containers.conf.sample /usr/local/etc/containers/policy.json.sample /usr/local/etc/containers/registries.conf.sample /usr/local/etc/containers/storage.conf.sample /usr/local/etc/containers/pf.conf.sample
```
pf.confは私は以下のように設定しました。
```
$ cat /etc/pf.conf
v4egress_if = "eth0"
v6egress_if = "eth0"

nat on $v4egress_if inet from <cni-nat> to any -> ($v4egress_if)
nat on $v6egress_if inet6 from <cni-nat> to !ff00::/8 -> ($v6egress_if)

rdr-anchor "cni-rdr/*"
nat-anchor "cni-rdr/*"
table <cni-nat>
pass in on cni-podman0
pass out on cni-podman0
$ service pf reload # pfのリスタートはお忘れなく
```

## Make jailed container with podman
では、miminalイメージを取得してpodmanに読み込ませましょう。
```
# export OCIBASE=https://download.freebsd.org/releases/OCI-IMAGES/14.2-RELEASE/amd64/Latest
# podman load -i=$OCIBASE/FreeBSD-14.2-RELEASE-amd64-container-image-minimal.txz
# podman image ls
REPOSITORY                            TAG                 IMAGE ID      CREATED       SIZE
localhost/freebsd14-minimal           14.2-RELEASE-amd64  c5f3e77557a9  5 months ago  35.1 MB
```
以下のようにすることで、jailが作成され、shに入ることができます。
```
# podman run -it localhost/freebsd14-minimal:14.2-RELEASE-amd64 /bin/sh
# freebsd-version -kru
freebsd-version: unable to locate kernel # <- in jails!
# freebsd-version -ru
14.2-RELEASE-p1
14.2-RELEASE <- jailなのでユーザーランドだけ見える
```
さて、このままだとネットワークがうまくいったり行かなかったりします。私は`local-unbound`を使用しているため、ホストのnameserverが 127.0.0.1となっており、jail内の方がnameserverを認識できませんでした。
そのため、jail側の`/etc/resolv.conf`を編集します。viやeeはないのでechoやsedでやりましょう。
```
# echo nameserver <HOST-IP> >> /etc/resovle.conf 
# echo nameserver 8.8.8.8 >> /etc/resovle.conf
```
これでDNS名前解決ができるようになっているはずです。drillもないので、pingなどでいい感じに切り分けましょう。
## Using pkg in jail

さて、これで`pkg`がbootstrapできる段階になりました。
しかし、`pkg -f`してもpkgが見つからないなどと怒られてbootstrapできません。
これはrepoがbaseを参照する設定が入っており、こっちを優先してみてしまうことでpkgが存在せず、エラーとなっています。
そのため、以下のファイルを編集してreleaseにrepoを向けます。
```
# cat /usr/local/etc/pkg/repos/base.conf
FreeBSD-base: {
  url: "https://pkg.FreeBSD.org/${ABI}/base_release_2",
  mirror_type: "srv",
  signature_type: "fingerprints",
  fingerprints: "/usr/share/keys/pkg",
  enabled: yes
}
# sed -i '' 's/enabled: yes/enabled: no/' /usr/local/etc/pkg/repos/base.conf
```
これで`pkg`が利用可能になります。
```
# pkg 
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+https://pkg.FreeBSD.org/FreeBSD:14:amd64/quarterly, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
[8afcf3ac578f] Installing pkg-2.1.0...
[8afcf3ac578f] Extracting pkg-2.1.0: 100%
```
これで、アプリケーションをインストールできるようになりました。
例えば`apache`をインストールしましょう。
```
# pkg install apache24
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Updating database digests format: 100%
The following 20 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        apache24: 2.4.63
        apr: 1.7.5.1.6.3_4
        brotli: 1.1.0,1
        curl: 8.12.1
        expat: 2.7.0
        gdbm: 1.24
        gettext-runtime: 0.23.1
        indexinfo: 0.3.1_1
        jansson: 2.14.1
        libidn2: 2.3.8
        liblz4: 1.10.0,1
        libnghttp2: 1.65.0
        libpsl: 0.21.5_2
        libssh2: 1.11.1,3
        libunistring: 1.3
        libxml2: 2.11.9
        pcre2: 10.45
        perl5: 5.36.3_3
        readline: 8.2.13_2
        zstd: 1.5.7

Number of packages to be installed: 20

The process will require 123 MiB more space.
28 MiB to be downloaded.

Proceed with this action? [y/N]: y
[8afcf3ac578f] [1/20] Fetching indexinfo-0.3.1_1.pkg: 100%    6 KiB   6.0kB/s    00:01
...
[8afcf3ac578f] [20/20] Extracting apache24-2.4.63: 100%

```
これでインストールが成功しました。Apacheを立ち上げて、依存で入ってるcurlで確認してみましょう。
```
# service apache24 onestart
Performing sanity check on apache24 configuration:
[Mon Apr 28 13:20:30.677209 2025] [so:warn] [pid 86066] AH01574: module mpm_prefork_module is already loaded, skipping
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.88.0.14. Set the 'ServerName' directive globally to suppress this message
Syntax OK
Starting apache24.
[Mon Apr 28 13:20:30.730944 2025] [so:warn] [pid 86067] AH01574: module mpm_prefork_module is already loaded, skipping
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.88.0.14. Set the 'ServerName' directive globally to suppress this message
# curl localhost
<html><body><h1>It works!</h1></body></html>
```
これでHTTPサーバーが立ち上がりました。host側からpsでどう見えるか見てみましょう。
```
$ ps aux | grep httpd
root       56269   0.0  0.0    17616    5700  -  SsJ  23:37      0:00.00 /usr/local/sbin/httpd -DNOHTTPACCEPT
www        56270   0.0  0.0    17616    5716  -  SJ   23:37      0:00.00 /usr/local/sbin/httpd -DNOHTTPACCEPT
www        56271   0.0  0.0    17616    5716  -  SJ   23:37      0:00.00 /usr/local/sbin/httpd -DNOHTTPACCEPT
www        56272   0.0  0.0    17616    5716  -  SJ   23:37      0:00.00 /usr/local/sbin/httpd -DNOHTTPACCEPT
www        56273   0.0  0.0    17616    5716  -  SJ   23:37      0:00.00 /usr/local/sbin/httpd -DNOHTTPACCEPT
www        56274   0.0  0.0    17616    5716  -  SJ   23:37      0:00.00 /usr/local/sbin/httpd -DNOHTTPACCEPT
```
stateにJが入っているのでJailで稼働していることがわかります。

## 問題点

- なんかsoが足りないってなったりshスクリプトが動かないよ。 <= baseシステム全体がインストールされているわけではないので、共有ライブラリが足りてなかったり標準のコマンドが入ってなかったりします。うまい事`pkg`をつかってインストールするか(baseをYESにしてごにょごにょ)、ホスト側からコピーしてくるなどの対策が必要です。
- rootlessは？ <= まだFreeBSDでは未実装です。
- 設定とかは？ <=基本はdocker/podmanの手法でできるはずですが、動作確認が完全に取れているわけでもないです。ocijailの方でもいろいろできるのでそっちもあるかも

## 参考文献
https://people.freebsd.org/~dch/posts/2024-12-04-freebsd-containers/