This section demonstrates a minimal, reproducible workflow using
jailmgr, jailctl, and NetBSD base components.
The example provisions a constrained HTTP service inside a jail, starts
it, inspects runtime state, and exposes metrics.
1. Bootstrap
Prepare the host for jail operation.
This step:
- Loads the
secmodel_jail kernel module
- Ensures it is configured for automatic loading on boot
- Prepares base filesystem layers
- Creates default configuration files
- Initializes the jail data directory layout
2. Create Jail
Create a jail named web with:
- HTTP daemon bound to port 8080
- CPU quota
- Memory limit
- File descriptor limits
- Socket buffer limits
- Structured logging
vhost# jailmgr create -a -x '/usr/libexec/httpd -I 8080 -X -f -s /var/www/mysite' -q 200 -c 1000000 -m 536870912 -p 512 -d 8192 -s 134217728 -l medium -r 8080 -f local3 -o info -e err -t jail-web web
Created jail web
vhost#
3. Ephemeral Provisioning
Execute commands inside the jail from the host, without altering
its persistent configuration.
The jail is entered temporarily, the commands are run,
and control returns to the host.
vhost# jailmgr apply --ephemeral web <<'APPLY'
mkdir -p /var/www/mysite
echo "<html>Hello NetBSD!</html>" > /var/www/mysite/index.html
APPLY
4. Start All Jails
Each jail configuration contains an autostart setting
that can be enabled or disabled individually.
The --all option operates only on jails where autostart is active.
vhost# jailmgr start --all
Started jail web
vhost#
5. Supervision Model
When started in supervise mode, jailctl daemonizes itself on the host
and becomes the parent process for the workload running inside the jail.
All processes started within the jail are descendants of the
jailctl supervise process.
From the host perspective, these processes remain fully visible in the
standard process table. There is no hidden runtime or separate process namespace.
Host process tree:
vhost# ps axd
....
8252 ? Ss 0:00.00 |-- jailctl: jailctl supervise jail=web jid=3
6488 ? Ss 0:00.01 | `-- /usr/libexec/httpd -I 8080 -X -f -s /var/www/mysite
Enter jail context:
vhost# jailctl exec web
vhost# whoami
root
vhost# ps axd
PID TTY STAT TIME COMMAND
6488 ? Is 0:00.01 /usr/libexec/httpd -I 8080 -X -f -s /var/www/mysite
7117 pts/1 S 0:00.01 /bin/sh -i
5572 pts/1 O+ 0:00.00 - ps -axd
vhost#
Inside the jail context, even the root user can only see
processes belonging to that jail.
Cross-jail process visibility is denied by the kernel.
The host context (jid 0) remains the only global view.
6. Runtime Statistics
Resource accounting per jail is maintained inside the kernel
and exposed through the control interface.
vhost# jailctl stats
ID NAME CPU PROC FD SOCKBUF MEMORY THROTTLE
3 web 0 1 3 0 154025984 0
7. Prometheus-Compatible Metrics Endpoint
jailctl stats can emit Prometheus-compatible metrics.
The -P flag switches to Prometheus exposition format.
The -h flag prepends a minimal HTTP header.
This makes it possible to expose the metrics endpoint using only
base system facilities (for example via inetd), without requiring
a dedicated exporter daemon.
vhost# jailctl stats -P -h
HTTP/1.1 200 OK
Content-Type: text/plain
# TYPE jail_cpu_usage_ticks gauge
# TYPE jail_processes_current gauge
# TYPE jail_processes_max gauge
# TYPE jail_fd_current gauge
# TYPE jail_fd_max gauge
# TYPE jail_sockbuf_current gauge
# TYPE jail_sockbuf_max gauge
# TYPE jail_memory_current_bytes gauge
# TYPE jail_memory_max_bytes gauge
# TYPE jail_deny_process_total counter
# TYPE jail_deny_fd_total counter
# TYPE jail_deny_sockbuf_total counter
# TYPE jail_deny_memory_total counter
# TYPE jail_throttle_cpu_total counter
jail_cpu_usage_ticks{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
jail_processes_current{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 1
jail_processes_max{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 512
jail_fd_current{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 3
jail_fd_max{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 8192
jail_sockbuf_current{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
jail_sockbuf_max{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 134217728
jail_memory_current_bytes{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 154025984
jail_memory_max_bytes{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 536870912
jail_deny_process_total{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
jail_deny_fd_total{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
jail_deny_sockbuf_total{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
jail_deny_memory_total{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
jail_throttle_cpu_total{jid="3",name="web",root="/var/jailmgr/jails/web/root"} 0
Result
- Base-system HTTP daemon
- Hard resource limits
- Supervised execution
- Ephemeral provisioning
- Observable via structured metrics
- No container runtime
- No UID remapping
- No full virtualization
This is process isolation as a disciplined, inspectable system
primitive.