Working with packages in an isolated environment. Using zfs datasets and jails

In the previous article, we described how the plug-in distribution system works in the new ICS version. Today we will talk about how to deploy a single plugin in the system.

It is best to run each plugin in a sandbox that is tailored specifically to the requirements of the plugin. Moreover, in an environment that will allow the system to interact with the plugin and plugins with each other. In the following, to understand that this applies to standard package handling, we will use the term “package”.



What to choose?



What is used for this in most cases? Docker, of course!



pkg install docker



pkg: No packages available to install matching 'docker' have been found in the repositories







Docker does not have official FreeBSD support, and of course there is no such package in the repository. In the previous version of IKS, we used an unofficial self-written port of docker, but its support is quite laborious, and besides, a lot of pitfalls emerge when using it.







But FreeBSD has its own native support for isolated environments. It is called jail and is no worse for our purposes than docker. It is worth noting that it appeared much earlier than containers in Linux. Let's see how a typical container is configured (a cell in bsd terminology).



Preparing the dataset and installing the package



First of all, you need to create a dataset on which the package cell will be configured. Our system uses the ZFS file system, which allows us to create any number of inherited datasets.



By default, the system has a dataset with the FreeBSD base world, from which we create a snapshot (snapshot):



zfs snapshot zp000111 / freebsd @ snap



zp000111 is the name of our root file system pool. We can see it through the zfs mount command . zp000111 / freebsd is the name of the dataset that stores the world. The name of the snapshot is indicated through the @ symbol . We create this snapshot once and in the future all datasets for packages will be inherited from it.



From this snapshot, we create a clone in which our package will live:



zfs clone zp000111 / freebsd @ snap zp000111 / packets / <packet_name>



First, we will mount the dataset to the current system:



mount -t zfs zp000111 / packets / <packet_name> / mnt / packets / <packet_name>



And now we can install the required package into it:



pkg -r / mnt / packets / <packet_name> install -y <packet_name> The



-r switch ensures installation inside the specified directory.



If necessary, we can install other necessary packages, for example mc for convenient work inside the package.



We perform unmounting. This is not necessary, but it is useful to go all the way to start the cell in the future:



umount / mnt / packets / <packet_name>



Cell preparation



First, you need to decide on the storage of the package data in the production system. Let it be the directory / usr / local / share / packets.



Add the directory <packet_name>



mkdir / usr / local / share / packets / <packet_name> to it



Now create a file with mount point <packet_name> .fstab. It contains information for the jail about which directory in the mounted dataset is synchronized:



/ usr / local / share / packets / <packet_name> / mnt / packets / <packet_name> / usr / local / share / data nullfs rw 0 0



This is how we we inform that the directory / usr / local / share / data will be connected to the directory in our working system in our mounted package. This is a jail (file system nullfs), both read and write are allowed for exchanging data with an external system (rw), saving information about the file system and checking its integrity is not required (0 and 0).



We save the file in a convenient place, for example, in /usr/local/etc/packets/<packet_name>/<packet_name>.fstab



Now we need to set up the configuration file for the jail of our package.



A typical config with minimal settings looks like this
host.hostname = "<packet_name>";

path = " /mnt/packets/<packet_name>";

interface = «em0»;

ip4.addr = 192.168.0.1;

allow.raw_sockets = 1;

exec.start = "/bin/sh /etc/rc";

exec.stop = "/bin/sh /etc/rc.shutdown;";

exec.clean;

enforce_statfs = 0;

mount.devfs;

mount.fstab = /usr/local/etc/packets/<packet_name>/<packet_name>.fstab;



We specify one of the network cards in the system as the interface. We assign it an ip-address, which will be available from the outside. Also, enable the allow.raw_sockets option for network functions such as ping or traceroute to work.



The exec command section specifies which commands to execute to start and shut down the system inside the jail. Since this is the standard FreeBSD world, we specify the base paths for turning the system on and off.



With the last three options, we allow mounting external systems, connect physical devices and mount our data folder inside the jail to an external folder according to the created fstab file.



We save our file in a convenient place, for example, in the same directory /usr/local/etc/packets/<packet_name>/<packet_name>.jail.conf





We are all set to launch the package in the cage. Let's start by mounting the package dataset:



mount -t zfs zp000111 / packets / <packet_name> / mnt / packets / <packet_name>



Now we can run the



jail : jail -f / usr / local / etc / packets / <packet_name> / < packet_name> .jail.conf -c <packet_name>



With the -r option, we specify the path to the configuration file, and -c that it is necessary to create a new jail with the specified name.



Our cell has started, we can check it:



jls -j <packet_name>



A line with the name of the cell and its id in the jail system will be displayed.



Now, if we need to enter the working system of the package, run the command:



jexec <jail_id>/ bin / tcsh



To stop the



jail



and unmount the package, execute the reverse commands: jail -f /usr/local/etc/packets/<packet_name>/<packet_name>.jail.conf -r <packet_name> umount / mnt / packets / <packet_name>



Moreover, all data that were saved by the package in the / usr / local / share / data folder of its file system will be available under the path / usr / local / share / packets / <packet_name> on the external system.



Total



Thus, we have created an isolated environment for our package.



The cell outside will ping to the specified address, and, accordingly, all network services raised in it will also be available on it. And since user data is stored in an external folder on the production system, it is easy to store and back up.



A similar system will work in new versions of IKS , which will make its use even easier and more enjoyable.



That's all for today, thanks for your attention!



All Articles