Kleene on FreeBSD: Docker-Like Container Management with Jails and ZFS
():Kleene is a container management (jail manager) platform designed specifically for FreeBSD, bringing familiar concepts from Docker while fully embracing FreeBSDs native tools and philosophy. Instead of reinventing the wheel, Kleene follows the KISS (Keep It Simple, Stupid) principle, leveraging FreeBSD’s built-in features to simplify application deployment, maintenance, and upgrades without unnecessary complexity or abstraction.
By using FreeBSD’s core technologies like jails, ZFS, and PF (Packet Filter), Kleene provides a streamlined way to build, run, and manage containerized applications while maintaining transparency and control. Key functionalities include:
- Jailed Applications: Running lightweight, isolated environments using ZFS for storage efficiency.
- Native Networking: Automatically setting up necessary network devices and configurations.
- Firewall Integration: Managing connectivity securely with FreeBSD's PF firewall.
Unlike some container solutions that introduce heavy layers of abstraction, Kleene stays true to FreeBSD’s “Power to Serve” motto, ensuring users retain full visibility and control over their system. If you’re familiar with Docker, many of the ideas will feel familiar, but Kleene is built exclusively with FreeBSD’s native tools where no further rocket science is involved.
For those new to containers, reading Docker’s high-level overview is a good starting point, though it’s important to note that Kleene has some fundamental differences from Linux-based containerization.
Kleene makes container management on FreeBSD simpler, more transparent, and more efficient and you as you can already see – it’s more a jail manager on steroids adapting the ideas of Docker.
Architecture
Kleene is built on a client-server model. Therefore, Kleene mainly consists of two main components: The client, called Klee (written in Python), sends instructions to the server. The server, Kleened (mostly written in the Elixir programming language using the underlying OTP-framework and the BEAM VM of Erlang), which handles all the tasks related to building and running containers.
Both Klee and Kleened can operate on the same computer, or Klee can connect to a remote Kleened server. The communication is then handled by a REST API, using either UNIX sockets or a network interface.
However, we need to interact with some objects and therefore, we can also add a third component: The Kleene objects which can be images, container, network, volumes and other objects.
Requirements
Kleene has minimal requirements on FreeBSD, needing only FreeBSD 13.x or 14.x, along with the ZFS and PF firewall kernel modules. With these components enabled, Kleene can be used without additional dependencies or complex setup.
In fact, it simply requires:
- FreeBSD 13.x or 14.x
- ZFS kernel module
- PF firewall kernel module
Installation: Kleened
Kleene components are not yet included in the official FreeBSD ports and packages. However, everything is already in place in dedicated repositories to make the usage and installation as easy as possible for users by simply installing it by pkg.
In this HowTo we will run the kleened and the client tool klee on the same host.
FreeBSD 14.x
fetch https://github.com/kleene-project/kleened/releases/download/v0.1.0-rc.1/kleened-0.1.0rc1_FreeBSD14-amd64.pkg
pkg install kleened-0.1.0rc1_FreeBSD14-amd64.pkg
FreeBSD 13.x
fetch https://github.com/kleene-project/kleened/releases/download/v0.1.0-rc.1/kleened-0.1.0rc1_FreeBSD13-amd64.pkg
pkg install kleened-0.1.0rc1_FreeBSD13-amd64.pkg
Ports
git clone https://github.com/kleene-project/ports.git kleene-ports
cd kleene-ports/sysutils/kleene-daemon
make install
Post-Configure
After installation, you should first validate the generated config in /usr/local/etc/kleened/config.yaml where you can adjust some minor things, like the root ZFS dataset where Kleened stores images, containers and volumes, but also the pf firewall config template and some other things.
Afterwards, we need to do the typical service management related things, like enabling the service etc.
sysrc kleened_enable=YES
# Dry-run: service kleened dryinit (see below)
service kleened init
With the command service kleened dryinit you can also simply get an overview of things that need to be done to make kleened work properly on your system.
root@gyptazy-kleene01:~ # service kleened dryinit
Verifying kernel module zfs is loaded...OK
Verifying kernel module pf is loaded...not loaded, trying to load..OK
Verifying kernel module pflog is loaded...not loaded, trying to load..OK
Verifying if 'zfs_load' is set to "YES" in /boot/loader.conf...OK
Verifying if 'zfs_enable' is set to "YES" in /etc/rc.conf...OK
Verifying if 'pf_load' is set to "YES" in /boot/loader.conf...not enabled, enabling...OK
Verifying if 'pf_enable' is set to "YES" in /etc/rc.conf...not enabled, enabling...OK
Verifying if 'pflog_enable' is set to "YES" in /etc/rc.conf...not enabled, enabling...OK
Verifying if zfs dataset zroot/kleene exists...does not exist, creating...OK
Verifying if zfs dataset zroot/kleene/image exists...does not exist, creating...OK
Verifying if zfs dataset zroot/kleene/container exists...does not exist, creating...OK
Verifying if zfs dataset zroot/kleene/volumes exists...does not exist, creating...OK
Verifying rctl is enabled...error!
Rctl does not seem to be enabled, so container resource limiting will not work.
Set kern.racct.enable=1 in /boot/loader.conf and reboot the system to enable rctl.
Installation: Klee
After installing the Kleened service as the backend application, we also need to install our client management tool, called Klee.
Klee can not only be used on FreeBSD based systems but also on other ones, such like Debian. In all ways, this is installed by pipx since the application is not yet available in the regular distribution repositories.
FreeBSD
pkg install py311-pipx
pipx install kleene-cli
pipx ensurepath
Debian
apt-get install pipx
pipx install kleene-cli
Usage
We’ve finished setting up all the necessary tools for both the backend and frontend, allowing us to begin containerizing applications. In this case, we’ll be working on containerizing Nginx.
Prepare Container Host
First, we prepare the container host node where kleened is running.
klee image create fetch-auto
klee network create --subnet 10.11.12.0/24 dev01-gyptazy-nginx01
Build Container Image
Finally, we can create our container image.
mkdir -p /opt/kleene/nginx && cd $_
vi Dockerfile
We will fill the Dockerfile with the following content, which uses FreeBSD 14.1 as our image:
FROM FreeBSD-14.1-RELEASE:latest
RUN pkg install -y nginx
WORKDIR /app
COPY . .
RUN echo "hello from the container served by klenee" > /usr/local/www/nginx/index.html
CMD service nginx enable && service nginx start
Afterwards, we can build the container image and will simply name it nginx:
klee build -t nginx .
Image Validation
We can simply validate and list the present images on our system by running:
klee image ls
Run an Image
Finally, we can start our newly created image and assign it to the previously generated network.
klee run -n dev01-gyptazy-nginx01 -d nginx
Access the Container
To check which containers are running along with their IP addresses, use the jls command.
jls
curl 10.11.12.1
Conclusion
The Kleene project brings a Docker-like experience to FreeBSD, making containerization more accessible while staying true to the system’s core strengths. For those transitioning from Linux, Kleene simplifies the learning curve while still retaining the flexibility and security benefits of jails. Overall, the project looks promising, especially for users who appreciate a more user-friendly approach to managing jails without sacrificing FreeBSD’s security and efficiency.