📦 Containers on FreeBSD: Podman, OCI Images and Jails
Run standard OCI container images on FreeBSD with Podman. See that a container is a jail, build an image, and even run a Linux container (Alpine) on the FreeBSD kernel
Containers and jails
You have met the two halves of this page already. A jail (jails page) is FreeBSD's way to fence a set of processes into their own file system, hostname and network, on the same kernel. A container, in the Docker sense, is the same idea plus a packaging standard: an image (a stack of file-system layers and a recipe) that you can download from a registry and run anywhere that understands it. The standard is called OCI (Open Container Initiative), and it is the format behind Docker, Podman and Kubernetes.
FreeBSD can run OCI images with Podman (the daemonless container tool) and ocijail, a runtime that starts the container as a jail. So there is nothing new inside: a FreeBSD container is a jail, and you will see that on the host's own jls. What the OCI tooling adds is convenience: pull a ready-made image with one command, build your own from a recipe, and share it. The FreeBSD project publishes official images for this.
An honest caution: the package description of ocijail calls it an "Experimental, proof-of-concept OCI-compatible runtime for jails". It worked well for everything below, but it is younger than jails themselves, so test before you depend on it.
Everything on this page was run for real on FreeBSD 15.0-RELEASE in a virtual machine with 2 GB of memory. We downloaded about 153 MiB of packages and a few small images.
Step 1: install
⚠️ Newer package repository (checked October 2026): the package repository now targets FreeBSD 15.1, while 15.0-RELEASE is end of life. On a 15.0 machine pkg may stop with Newer FreeBSD version for package ... [y/N], and the version numbers in the output below may differ from yours. To carry on, run export IGNORE_OSVERSION=yes first, or better, move to a supported release (see the upgrading guide).
root@practice:~ # pkg install -y podman-suite 2>&1 | grep -E "Number|download|space|podman-suite|ocijail|Installing podman" ocijail: 0.6.1 [FreeBSD-ports] podman-suite: 20260414 [FreeBSD-ports] Number of packages to be installed: 41 The process will require 615 MiB more space. 153 MiB to be downloaded. [ 3/41] Fetching ocijail-0.6.1: .......... done [16/41] Fetching podman-suite-20260414: . done [23/41] Installing ocijail-0.6.1... [23/41] Extracting ocijail-0.6.1: .... done [39/41] Installing podman-5.8.6_4... [41/41] Installing podman-suite-20260414... [41/41] Extracting podman-suite-20260414: ... done Message from podman-suite-20260414: root@practice:~ # podman --version podman version 5.8.6 root@practice:~ # which podman buildah skopeo ocijail conmon /usr/local/bin/podman /usr/local/bin/buildah /usr/local/bin/skopeo /usr/local/bin/ocijail /usr/local/bin/conmon root@practice:~ # pkg info -d podman | head -14 podman-5.8.6_4: conmon-2.2.1_10 containernetworking-plugins-0.6_20 containers-common-0.64.2_4 gpgme-2.1.2 ocijail-0.6.1 gpgme-2.1.2 (libgpgme.so.45)
podman-suite is a "meta" package: 41 packages (153 MiB to download, 615 MiB installed) that bring Podman, Buildah (builds images), Skopeo (inspects and copies images between registries), ocijail (the runtime), conmon (watches the container), the standard container configuration files and the networking plug-ins. We checked the version after: Podman 5.8.4. The package's own notes say you can also add docker-registry (to host your own registry) and qemu-user-static (to build images for other CPUs): from the documentation, not run here.
root@practice:~ # zfs create -o mountpoint=/var/db/containers zroot/containers root@practice:~ # zfs list -o name,mountpoint zroot/containers NAME MOUNTPOINT zroot/containers /var/db/containers root@practice:~ # grep -n fdesc /etc/fstab || echo 'no fdescfs line yet' no fdescfs line yet root@practice:~ # echo 'fdesc /dev/fd fdescfs rw 0 0' >> /etc/fstab root@practice:~ # mount -t fdescfs fdesc /dev/fd; mount | grep fdescfs fdescfs on /compat/linux/dev/fd (fdescfs) fdescfs on /dev/fd (fdescfs) root@practice:~ # ls /usr/local/etc/containers certs.d containers.conf.sample pf.conf.sample policy.json.sample registries.conf.sample storage.conf containers.conf hooks.d policy.json registries.conf registries.d storage.conf.sample root@practice:~ # grep -v '^#' /usr/local/etc/containers/containers.conf 2>/dev/null | grep . | head -5 [containers] default_capabilities = [ "CHOWN", "DAC_OVERRIDE", "FOWNER", root@practice:~ # grep -E 'driver|graphroot|runroot' /usr/local/etc/containers/storage.conf | head -6 driver = "zfs" runroot = "/var/run/containers/storage" graphroot = "/var/db/containers/storage" # If set, it must be different than graphroot. # Storage options to be passed to underlying storage drivers # and vfs drivers.
- Storage on ZFS: we made a dataset, zroot/containers, mounted at /var/db/containers. The storage configuration (storage.conf) already uses driver = "zfs" and keeps its images under graphroot = "/var/db/containers/storage", so every image layer becomes a ZFS dataset. That gives you the snapshot and clone behaviour of the ZFS page for free. (You can see the beginning of the configuration in the listing, and the dataset appears below.)
- fdescfs: Podman's documentation asks for the fdescfs file system on /dev/fd. We added the fstab line and mounted it (mount -t fdescfs). The listing shows two mounts of it: the one we made on /dev/fd, and the one under /compat/linux that the Linux compatibility layer created earlier. (Whether Podman would have worked without it, we did not test.)
- The package also installed a sample pf.conf in /usr/local/etc/containers/: a hint about networking, which comes up in a moment.
Step 2: find and pull an image
root@practice:~ # skopeo list-tags --override-os freebsd docker://docker.io/freebsd/freebsd-runtime 2>&1 | grep -E '"15|latest' | head -12
"15.0",
"15.0.beta2",
"15.0.beta3",
"15.0.beta4",
"15.0.beta5",
"15.0.rc1",
"15.0.rc2",
"15.0.rc3",
"15.0.rc4",
"15.1",
"15.1.beta1",
"15.1.beta2",
root@practice:~ # skopeo inspect --override-os freebsd docker://docker.io/freebsd/freebsd-runtime:15.0 2>&1 | grep -E 'Created|"Architecture"|"Os"|Layers' | head -8
"Created": "2025-11-28T03:43:02Z",
"Architecture": "amd64",
"Os": "freebsd",
"Layers": [
skopeo list-tags asks a registry which versions (tags) of an image exist. We added --override-os freebsd so that the tool asks for the FreeBSD variants of the images: registries hold images for many operating systems. The official image docker.io/freebsd/freebsd-runtime has tags for each FreeBSD release: 15.0, the 15.1 betas and so on. skopeo inspect shows the one we want: amd64, freebsd, created on 2025-11-28, and it has a single layer.
root@practice:~ # podman pull --os freebsd docker.io/freebsd/freebsd-runtime:15.0 2>&1 | tail -6
Trying to pull docker.io/freebsd/freebsd-runtime:15.0...
Getting image source signatures
Copying blob sha256:783aad9bdea10d40706a7f0fea23344c51ad5fb43846077da5a564b7fd494eee
Copying config sha256:d7fa7dafb151d968892c5ce9c8c951ab920e63c0e58434eb6a3d70da682bca75
Writing manifest to image destination
d7fa7dafb151d968892c5ce9c8c951ab920e63c0e58434eb6a3d70da682bca75
root@practice:~ # podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/freebsd/freebsd-runtime 15.0 d7fa7dafb151 10 months ago 34 MB
root@practice:~ # zfs list -r -o name,used,refer zroot/containers | head -6
NAME USED REFER
zroot/containers 21.2M 284K
zroot/containers/9f51934f0c8fadf8d642fa5b96f4744b0b1614288a724c1e2839face8d61718e 20.9M 20.9M
root@practice:~ # podman pull --os freebsd docker.io/freebsd/freebsd-static:15.0 2>&1 | tail -5
Getting image source signatures
Copying blob sha256:017348f62c2bad853dd11d865e7e2e2a4a7d9e95b45ba84e700005b6b4e86ee8
Copying config sha256:1907d01c25d4680e5814a15100948441630ea0e73ee25897b2b9a4588f6322d2
Writing manifest to image destination
1907d01c25d4680e5814a15100948441630ea0e73ee25897b2b9a4588f6322d2
root@practice:~ # podman images --format "table {{.Repository}} {{.Tag}} {{.Size}}"
REPOSITORY TAG SIZE
localhost/techcommune/hello 1 34 MB
docker.io/library/alpine 3.20 8.1 MB
docker.io/freebsd/freebsd-runtime 15.0 34 MB
docker.io/freebsd/freebsd-static 15.0 2.99 MB
- podman pull --os freebsd ... downloaded it: a 34 MB image. --os freebsd is the important switch: it selects the FreeBSD variant of the image.
- zfs list shows what happened on disk: the layer is a ZFS dataset under zroot/containers, 20.9 MB used.
- The project also publishes freebsd-static, for programs that are fully static: at 2.99 MB it is tiny (the last podman images lists all of them). The runtime image carries the C library and a basic set of programs, the static one has just about nothing.
Step 3: run your first container, and the network prerequisite
Podman's default is to give each container its own network on a virtual bridge, with address translation (NAT). Here is what happened:
root@practice:~ # podman network ls NETWORK ID NAME DRIVER 2f259bab93aa podman bridge root@practice:~ # kldstat | grep -c " pf.ko" 0 root@practice:~ # podman run --rm --os freebsd docker.io/freebsd/freebsd-runtime:15.0 uname -a 2>&1 | grep -v "level=warning" Error: plugin type="bridge" failed (add): cni plugin bridge failed: The pf kernel module must be loaded to support ipMasq networks
podman network ls shows the default network, podman, a bridge. And the first run failed: The pf kernel module must be loaded to support ipMasq networks. The default container network on FreeBSD is built on the pf firewall (the module is not loaded here: kldstat finds 0). Our test machine uses ipfw (see the ipfw page), and the two do not mix well. To use the default bridge network you load pf and use rules like the sample file in /usr/local/etc/containers/ (from the documentation, not run here). For our tests we used host networking, where the container simply shares the host's network. It is the jail setting you know as ip4=inherit: --net host.
root@practice:~ # podman run --rm --net host --os freebsd docker.io/freebsd/freebsd-runtime:15.0 uname -a 2>&1 | tail -4 FreeBSD practice 15.0-RELEASE FreeBSD 15.0-RELEASE releng/15.0-n280995-7aedc8de6446 GENERIC amd64 root@practice:~ # podman run --rm --net host --os freebsd docker.io/freebsd/freebsd-runtime:15.0 /bin/sh -c "freebsd-version; hostname; id; ps aux; ls /" 2>&1 | tail -24 15.0-RELEASE practice uid=0(root) gid=0(wheel) groups=0(wheel),5(operator) USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND root 78222 0.0 0.1 14744 2548 - SsJ 17:27 0:00.01 /bin/sh -c freebsd-version; hostname; id; ps aux; ls / root 80412 0.0 0.1 14824 2792 - RJ 17:27 0:00.00 ps aux COPYRIGHT bin boot dev etc lib libexec media mnt net proc rescue root sbin tmp usr var root@practice:~ # podman run --rm --net host --os freebsd docker.io/freebsd/freebsd-runtime:15.0 /bin/sh -c "cat /etc/os-release | head -3; which curl pkg bash fetch" 2>&1 | tail -6 /bin/sh: head: not found cat: /etc/os-release: No such file or directory /bin/sh: which: not found
Now it runs:
- The container reports FreeBSD 15.0-RELEASE with the same kernel string as the host (uname -a). It is not a virtual machine: it shares the host's kernel, like any jail.
- Inside: root (the container's root, a jailed root), the host name is practice (shared with the host, because of host networking), and ps aux shows only two processes, the shell and the ps itself. The J in their status is the jail flag: the processes are in a jail.
- The file tree is a minimal FreeBSD root. And the image is minimal: head and which do not exist. If you need more tools in an image, you add them when you build it.
A container is a jail
Run one in the background and look at it from the host:
root@practice:~ # podman run -d --name box1 --net host --os freebsd docker.io/freebsd/freebsd-runtime:15.0 sleep 600
bd764d8e25ad03a0ab8979554c019b07a607087546e983ad7dc1264735d0df2e
root@practice:~ # podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bd764d8e25ad docker.io/freebsd/freebsd-runtime:15.0 sleep 600 Less than a second ago Up 1 second box1
root@practice:~ # jls
JID IP Address Hostname Path
1 10.0.2.50 web.example.org /jails/web
6 practice /var/db/containers/storage/zfs/graph/324550efeae0040eee73ffff8bb60c0ed9fbe
root@practice:~ # ps -axo pid,jid,stat,command | grep "[s]leep 600"
589 6 SCsJ sleep 600
root@practice:~ # podman exec box1 /bin/sh -c "hostname; ps aux | tail -3"
practice
/bin/sh: tail: not found
- podman run -d --name box1 ... sleep 600 starts a container that just sleeps for ten minutes, and podman ps lists it.
- jls, the plain FreeBSD jail list, shows a new jail, JID 6, whose path is a ZFS dataset under /var/db/containers/storage/zfs/graph/.... (The first jail, JID 1, is the one from the jails page.) The container is that jail.
- On the host, ps -axo pid,jid,stat,command shows the sleep process with jid 6 and the J flag.
- podman exec box1 ... runs another command inside the same container (the tail: not found is the minimal image again).
root@practice:~ # mkdir -p /root/shared && echo "written on the host" > /root/shared/note.txt root@practice:~ # podman run --rm --net host --os freebsd -v /root/shared:/data docker.io/freebsd/freebsd-runtime:15.0 /bin/sh -c "cat /data/note.txt; echo written-in-container >> /data/note.txt" written on the host root@practice:~ # cat /root/shared/note.txt written on the host written-in-container
A volume shares a host folder with the container: -v /root/shared:/data. The container read the file the host had written, and appended a line, and the host sees both lines. (Volumes are done with a nullfs mount, as jails do: from the documentation, not run here.)
root@practice:~ # podman stop box1
box1
root@practice:~ # podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bd764d8e25ad docker.io/freebsd/freebsd-runtime:15.0 sleep 600 2 seconds ago Exited (143) Less than a second ago box1
root@practice:~ # jls
JID IP Address Hostname Path
1 10.0.2.50 web.example.org /jails/web
root@practice:~ # podman rm box1 2>&1 | tail -1
box1
root@practice:~ # podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
podman stop box1 stopped it (the exit code 143 is the normal "terminated" status of a stopped process). The jail is gone from jls: only the jails page's own jail is left. podman rm deleted the stopped container.
Build your own image
An image is built from a recipe, a Containerfile (Docker users know it as a Dockerfile). We wrote one, with a small script that it copies in:
root@practice:~ # cat > /root/hello/Containerfile <<'EOF' > FROM docker.io/freebsd/freebsd-runtime:15.0 > RUN echo "Hello from a FreeBSD container" > /hello.txt > COPY hello.sh /hello.sh > CMD ["/bin/sh", "/hello.sh"] > EOF root@practice:~ # cat > /root/hello/hello.sh <<'EOF' > #!/bin/sh > cat /hello.txt > echo "running on FreeBSD $(freebsd-version)" > EOF root@practice:~ # ls /root/hello Containerfile hello.sh root@practice:~ # podman build --os freebsd --network host -t techcommune/hello:1 /root/hello 2>&1 | tail -14 STEP 1/4: FROM docker.io/freebsd/freebsd-runtime:15.0 STEP 2/4: RUN echo "Hello from a FreeBSD container" > /hello.txt --> 60d2e074e549 STEP 3/4: COPY hello.sh /hello.sh --> 951f4a6ed476 STEP 4/4: CMD ["/bin/sh", "/hello.sh"] COMMIT techcommune/hello:1 --> 1c33bcbf9e34 Successfully tagged localhost/techcommune/hello:1 1c33bcbf9e341ce2278972837434765b9cfd09213554576fddce8b11555edadf root@practice:~ # podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/techcommune/hello 1 1c33bcbf9e34 Less than a second ago 34 MB docker.io/freebsd/freebsd-runtime 15.0 d7fa7dafb151 10 months ago 34 MB root@practice:~ # podman run --rm --net host techcommune/hello:1 Hello from a FreeBSD container running on FreeBSD 15.0-RELEASE root@practice:~ # podman history techcommune/hello:1 2>&1 | cut -c1-110 ID CREATED CREATED BY SIZE COMMENT 951f4a6ed476 Less than a second ago /bin/sh -c #(nop) CMD ["/bin/sh", "/hello.... 0B <missing> Less than a second ago /bin/sh -c #(nop) COPY file:558da96a40f69a... 3.07kB 60d2e074e549 2 seconds ago /bin/sh -c echo "Hello from a FreeBSD cont... 3.07kB FROM docker.i d7fa7dafb151 10 months ago make-oci-image.sh 34MB
- FROM says which image to start from. RUN runs a command during the build and keeps the result as a new layer. COPY puts a file from your folder into the image. CMD is what the container runs when it starts.
- podman build --os freebsd --network host -t techcommune/hello:1 /root/hello ran the four steps. Each step printed a short ID: that is the layer it made.
- The new image, localhost/techcommune/hello:1, is 34 MB, the same as the base: the layers we added are only 3 KB each, and the base layer is shared. That is how images stay small.
- podman run ... techcommune/hello:1 ran our script: Hello from a FreeBSD container and running on FreeBSD 15.0-RELEASE.
- podman history lists the layers: our CMD, the COPY, the RUN, and at the bottom the 34 MB base image.
A Linux container, on FreeBSD
Here is the surprise. Registries are full of Linux images. With the Linux compatibility layer from the previous page switched on, Podman can run those too, as jails, with the Linux programs translated by the layer. --os linux selects the Linux variant:
root@practice:~ # podman pull --os linux --arch amd64 docker.io/library/alpine:3.20 2>&1 | tail -4 Copying blob sha256:25f1d6b1951ac8eb3740558fe94cb83d377bdadf95fd9f98b50d2e1b96130471 Copying config sha256:bf8527eb54c3680e728d5b4b383a8ba730d72dae7236fbc8dff97ed6b224a731 Writing manifest to image destination bf8527eb54c3680e728d5b4b383a8ba730d72dae7236fbc8dff97ed6b224a731 root@practice:~ # podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/techcommune/hello 1 1c33bcbf9e34 10 seconds ago 34 MB docker.io/library/alpine 3.20 bf8527eb54c3 5 months ago 8.1 MB docker.io/freebsd/freebsd-runtime 15.0 d7fa7dafb151 10 months ago 34 MB root@practice:~ # podman run --rm --net host --os linux docker.io/library/alpine:3.20 /bin/sh -c "cat /etc/os-release | head -2; uname -sr; ls /" 2>&1 | tail -20 NAME="Alpine Linux" ID=alpine Linux 5.15.0 bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
- podman pull --os linux --arch amd64 docker.io/library/alpine:3.20 downloaded Alpine Linux, a very small distribution: 8.1 MB.
- The container says NAME="Alpine Linux" and Linux 5.15.0 (the version the compatibility layer reports), and its file tree is Alpine's.
root@practice:~ # podman run -d --name lbox --net host --os linux docker.io/library/alpine:3.20 sleep 300
c8ad7f5d97c6bf800264d002736a9986cca0e2ac5e8a22b4c862a5ab7717c890
root@practice:~ # jls
JID IP Address Hostname Path
1 10.0.2.50 web.example.org /jails/web
11 practice /var/db/containers/storage/zfs/graph/75d1ff51a9539fedbb483e1f5bf8f3d7a73fa
root@practice:~ # ps -axo pid,jid,stat,command | grep "[s]leep 300"
4648 11 SsJ sleep 300 (busybox)
root@practice:~ # podman exec lbox /bin/sh -c "uname -sr; head -1 /etc/os-release"
Linux 5.15.0
NAME="Alpine Linux"
root@practice:~ # podman exec lbox /bin/sh -c "wget -q -O - http://techcommune.org 2>&1 | head -c 120; echo; echo wget-exit=$?"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width
wget-exit=0
root@practice:~ # podman stop lbox >/dev/null; podman rm lbox
lbox
Seen from the host it is the same as before: a jail (JID 11), with its sleep 300 process marked J (and (busybox), the Linux program that Alpine uses for everything). podman exec talks to the Linux system inside. And its wget fetched this very website (http://techcommune.org) and printed the first bytes of the page: a Linux program, in a Linux container, on a FreeBSD kernel, using the host's network.
The limits are the limits of the compatibility layer: there are no cgroups and no namespaces, so a Linux image that needs them, or needs a particular Linux kernel feature, will not run. Test the exact image you need. Simple, self-contained images such as Alpine's tools work nicely.
What Podman says about itself
root@practice:~ # podman info --format 'os={{.Host.OS}} arch={{.Host.Arch}} runtime={{.Host.OCIRuntime.Name}} storage={{.Store.GraphDriverName}} graphroot={{.Store.GraphRoot}}'
os=freebsd arch=amd64 runtime=ocijail storage=zfs graphroot=/var/db/containers/storage
root@practice:~ # podman system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 0 42.07MB 42.07MB (100%)
Containers 0 0 0B 0B (0%)
Local Volumes 0 0 0B 0B (0%)
root@practice:~ # zfs list -r -o name,used zroot/containers | wc -l
6
root@practice:~ # zfs list -o name,used zroot/containers
NAME USED
zroot/containers 27.2M
podman info confirms the setup: the host is os=freebsd, the runtime is ocijail, the storage is zfs, under /var/db/containers/storage. podman system df totals the images (5 entries, 42 MB), and zfs list shows the whole container store takes 27.2 MB on disk.
What we did not do
All from the documentation, not run here:
- Publishing ports (-p 8080:80) and the default bridge network: they need the pf firewall with the container rules from the sample file.
- Resource limits: memory and CPU limits go through FreeBSD's rctl, which has to be switched on with a loader setting (kern.racct.enable).
- Running as an ordinary user ("rootless" Podman) is much more limited on FreeBSD than on Linux.
- Compose-style stacks with several containers, and Kubernetes: possible with extra tools, and not covered here.
- Your own registry, and building images for other CPUs.
Containers, jails and virtual machines
- A plain jail (jails page): the most direct, and you configure it yourself. Best for a service you will run for a long time.
- A container with Podman: the same jail, started from a standard image. Best when you want to pull ready-made software, build repeatable images, or run Linux images on a FreeBSD host.
- A virtual machine (bhyve, vm-bhyve pages): a whole separate kernel. Needed for operating systems that are not FreeBSD or Linux, or for Linux programs that need a real Linux kernel.
- Docker itself is not the usual FreeBSD tool. Podman is the native, daemonless route (from the documentation).
Treat images like any software from the internet: know where they came from. Pull from official sources, pin the version (a tag, or better a digest), and scan what you run (the hardening page's pkg audit covers packages, not the contents of images).
⚠️ A container is not a security boundary you can forget about. It is a jail, and a good one, but a bug in the shared kernel is a bug for all of them. Keep the host patched, give containers only the volumes and network they need, and do not run untrusted images with --net host and a shared folder on a machine that matters.
It had been living in a jail<br>
since long before it was called a container.
🧪 Try it yourself
On a FreeBSD machine with ZFS (a virtual machine is fine):
1. Install podman-suite and make a ZFS dataset for the container store. Check that podman info says ocijail and zfs. 2. List the tags of the freebsd/freebsd-runtime image with skopeo. Pull the 15.0 tag with --os freebsd. 3. Run uname -a and ps aux in a container with --net host. How many processes does it see? 4. Start a container in the background and look at it with jls and ps -axo pid,jid,command. Stop it, and look again. 5. Share a folder with -v, write to it from the container, and read it on the host. 6. Write a Containerfile that adds a file and a command, build it, and run it. Look at podman history. 7. Pull alpine with --os linux --arch amd64 and run it. (You need the Linux compatibility layer.) What does uname -sr say? 8. Try a run without --net host. What does it ask for?
The cheat sheet
- Install: pkg install podman-suite, a ZFS dataset on /var/db/containers, fdescfs on /dev/fd.
- Images: skopeo list-tags --override-os freebsd docker://docker.io/freebsd/freebsd-runtime, podman pull --os freebsd IMAGE:TAG, podman images, podman rmi.
- Run: podman run --rm --net host --os freebsd IMAGE COMMAND. In the background: -d --name NAME. Then podman ps, podman exec NAME COMMAND, podman stop NAME, podman rm NAME.
- See the jail: jls, ps -axo pid,jid,stat,command.
- Volumes: -v /host/path:/container/path.
- Build: a Containerfile (FROM, RUN, COPY, CMD), podman build --os freebsd --network host -t NAME:TAG DIR, podman history NAME:TAG.
- Linux images: podman pull --os linux --arch amd64 IMAGE, then podman run --os linux ... (needs linux_enable="YES").
- Networking: --net host always works; the default bridge needs pf.
- Inspect: podman info, podman system df.
← Hardening FreeBSD: A Tested Baseline · ↑ FreeBSD Corner · FreeBSD in the Cloud: First-Boot Provisioning with nuageinit →