Having fun with zfs snapshots and jails on freebsd : updgrading the zfs template of thinjails.

C'est en faisant n'importe quoi qu'on devient n'importe qui !
-- Rémi Gaillard (Montpellierain célèbre)
Since I decided to respin freeBSD servers since I have an allergy to systemd resulting in obfuscating simple things behind complex layers I put my fingers in my mouth : I set my actions with my words and do experimentations.

One of these experimentaiton is about playing with chroot (jails), zfs snapshot, and pkg. The frustration I have following the Freebsd handbook regarding creating thinjail is that you clone a BARE freebsd, and, as a sysadmin I am pecularly proefficient with bash... I want BASH installed in all my jails. Hence, I want to updgrade the base wich lies per manual advice in /usr/local/jails/templates/14.0-RELEASE and which is snaphoted with zfs without polluting the base with the install of pkg.

First thing let's check we being in a clean state :
#zfs diff zroot/jails/templates/14.0-RELEASE@base  zroot/jails/templates/14.0-RELEASE 
Let's add the local DNS to resolv.conf and see what happens :
# zfs diff zroot/jails/templates/14.0-RELEASE@base  zroot/jails/templates/14.0-RELEASE 
M	/usr/local/jails/templates/14.0-RELEASE/etc
-	/usr/local/jails/templates/14.0-RELEASE/etc/resolv.conf
+	/usr/local/jails/templates/14.0-RELEASE/etc/resolv.conf
Nice ! We want THIS to become the snapshot named « base ». How do we do per freeBSD zfs handbook ?
And well, I guess we take the safe path :
  • we modify the filesystem, add bash
  • we snaphost it
  • we check a new thinjail is up to date
Modifying /etc/resolv.conf is nice, but what about adding new packages to the base WITHOUT installing pkg cleanly ?

Let's jailify our template !

# more /etc/jail.conf.d/base.conf 
base {
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";
  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;
  host.hostname = "${name}";
  path = "/usr/local/jails/templates/14.0-RELEASE";
  ip4 = inherit;
  interface = wlan0; 
}
# service jail start base
Starting jails: base.

# pkg -j base install bash
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 4 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
	bash: 5.2.26_1
	gettext-runtime: 0.22.5
	indexinfo: 0.3.1
	readline: 8.2.10

Number of packages to be installed: 4

The process will require 12 MiB more space.
2 MiB to be downloaded.

Proceed with this action? [y/N]: y
....

#zfs diff zroot/jails/templates/14.0-RELEASE@base  zroot/jails/templates/14.0-RELEASE
M	/usr/local/jails/templates/14.0-RELEASE/etc
...
M	/usr/local/jails/templates/14.0-RELEASE/var/spool/lock
+	/usr/local/jails/templates/14.0-RELEASE/var/log/utx.lastlogin
...
+	/usr/local/jails/templates/14.0-RELEASE/etc/motd


The new « template » is a tad polluted, but it's nice.

It deserve to be kept as a base for a new jail template !
# zfs snapshot zroot/jails/templates/14.0-RELEASE@bash_base
And delete the jail we made to upgrade the package :
#service jail stop base
Stopping jails: base.
#mv /etc/jail.conf.d/base.conf /etc/jail.conf.d/base.conf.disabled

Now time to TEST !

# zfs clone zroot/jails/templates/14.0-RELEASE@bash_base zroot/jails/containers/testjail

# cat /etc/jail.conf.d/testjail.conf 

testjail {
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;

  # HOSTNAME/PATH
  host.hostname = "${name}";
  path = "/usr/local/jails/containers/${name}";
  # NETWORK
  ip4 = inherit;
  interface = wlan0;
}
# service jail start testjail
Starting jails: testjail.
# jexec testjail bash --version
GNU bash, version 5.2.26(1)-release (amd64-portbld-freebsd14.0)
#jexec testjail pkg
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: 

Well, it is a success ! We successfully made an update of the base we cloned and checked it was taken into account at new jails instanciation, WITHOUT having to install pkg in the jail !

Un bon ouvrier se reconnaît à son plan de travail propre » (a clean workplace is the mark of a good craftsman)

Cleaning is as important as doing : we have to remove the test jail and the jails used for updating the base :
# service jail stop test
Stopping jails: testjail.
# rm /etc/jail.conf.d/testjail.conf
# zfs destroy zroot/jails/containers/testjail

Conclusion

There is a lot of nice solution to play with jails on freeBSD : ezjail (that I was using), iocage, AppJail listed in the handbook.
However, I really like the idea of working with the bare minimum from the handbook since it is well documented. It builds up a good intuition that framewoks like application will opinionate sometimes in different ways than mine. Before eventually switching to AppJail or iocage I want to have an understanding of the low level coupling between the operating system, the networks stack, zfs and jails works.

So far, the handbooks and documentation are very helpful, I did not even need to look at archlinux wiki pages, and my intuition seems to give results.
Freebsd compared to linux has become for me a way to get a grasp back at reality, I profoundly understand again the founding layers of the system.
As such I would rate BSD experience as rejuvanting and dispelling the churn of technology.

Why use docker when I have jails ? AppJail even propose a deployment process that is a functional copy of docker. I have linuxlator and debbootstrap to install debian based linux jails, and bhyve as the equivalent of qemu.

I have been burnt with k8s mammothesque software defined stack making both DNS resolution and routing an obscure task, making a friction to deploy containers. Right now, I spin clean containers for everything that I want to contain and none of the containers are used for containerisation (like windows that actually MUST spin a linux VM or WSL2 to handle docker). It does make things less bloated.

No comments: