![]() |
![]()
| ![]() |
![]()
NAME
DESCRIPTIONAppJail has a notion of treating jails like cattle, so many of the features are designed with that in mind. Although this is a priority, FreeBSD users are commonly tied to the notion of treating jails like pets, so the result is that AppJail supports both approaches for different users. The “cattle vs. pets” approach is not a formal standard, it's just a convention for how you should treat your servers, which in this case, servers means jails. The article that clearly explains this approach is the following: The History of Pets vs Cattle and How to Use the Analogy Properly In this document I will not explain which approach is best for you as it depends entirely on your needs and how you work, instead I will describe how we can use AppJail following a concept known as “The Ephemeral Concept” that I am applying, practically since AppJail was born. You should know a lot about FreeBSD, AppJail, and the application you're running, so use this approach responsibly. THE EPHEMERAL CONCEPTThe ephemeral concept means that you should treat your jails as ephemeral as possible. This doesn't mean that your jails should disappear after rebooting the system or stopping the jail; What this means is that since you have clearly separated the data that should persist after the jail is created again, from the data that should not persist. What data is ephemeral and what is not? The simplest examples of ephemeral data are binaries and all the elements that make up the jail that are restored after recreating the jail. Data that should not be destroyed is application data, e.g. If we have a DBMS running inside the jail, we should not destroy its database. Configuration files (and similar) may be considered non-ephemeral, but in most cases the main difference compared to application data is how you reinstall them; in the case of configuration files (and similar) they can be copied every time the jail is recreated, but it must happen before the jail, or service running inside the jail, is started, and the application data is probably achieved by mounting it inside the jail using a tool like mount_nullfs(8). IMPLEMENTING THE EPHEMERAL CONCEPTThe simplest way to explain how we can use the ephemeral concept in a jail created by Appjail is top-down instead of bottom-up, or in other words, let's create a jail with a directory mounted on the data directory that is inside the jail. # The result of this session is self-explanatory: we have created a jail with a static web server installed and mounted a directory from the host to the directory that the web server uses. The directory, since it is located on the host, can be used to write files, so that's what we did: we wrote a little HTML code to display Hello! to clients connecting to the web server. We did what the ephemeral concept explains: we separated the data that should persist from the data that should not. Let's destroy the jail to recreate it again: # Amazing! We have successfully implemented the ephemeral concept. So easy, but this doesn't show some problems that we must face in real life, specifically two problems: filesystem permissions and mounting a directory from the host to a directory containing data. Those issues may or may not affect the application inside the jail. In the case of the example above, it is not affected unless the files need to be written with the same UID and GID as the running process, but this is not the case. Filesystem PermissionsThe application running inside the jail assumes it can write its data just fine and the process is probably running using a dedicated user, so we shouldn't mount a directory from the host to the jail without this in mind. We need to know the UID, GID, file mode and mount point in advance. This is very easy to know: just create a jail and install the application inside it, and proceed to inquire the information we need. At this point it is not necessary to configure a directory and we should not do it since we do not have the necessary information to do it correctly. Let's create a jail to clarify: # Of course, I'm cheating since I know in advance which directory the above application uses, but for applications you don't know very well I recommend that you read their documentation and the rc(8) script, if the application comes with one. As a last note: most services start with an empty directory and put files and more directories into it; What you need to know is if that directory is empty or has some files. This is very important because the service may need such files and if you simply mount a directory from the host to the jail, it will overlap and the service will not see those files. See Mounting a Directory from the Host to a Directory Containing Data to see how to fix this problem. Now that we have enough information, let's create the directory but with the properties that the application needs: # The jail can be created again using the same command above but
with the # If we create the jail again using exactly the same command above, we can use the application as if the jail destruction had not occurred. # Mounting a Directory from the Host to a Directory Containing Datamount_nullfs(8), the preferred tool for mounting files or directories from the host to the jail, is very useful, but it gives us a problem if we use it incorrectly: suppose we have two directories, A/ and B/, that have a file in each one, A/foo.txt and B/bar.txt, and we want to mount B/ to A/, so we run “mount_nullfs B/ A/” and run “ls A/” to see that we now have only A/bar.txt. There is nothing wrong with mount_nullfs(8), but we must keep this in mind to use it correctly. This problem means that we need to move the files from the jail to the host and mount the directory from the host to the jail as we normally do. This, of course, must be achieved before the service is started, which in real life means that it must be achieved before the jail is started, since it is common for the service to start just a few seconds after starting the jail. Fortunately for you, the user, AppJail can easily do the above using the <pseudofs> pseudo-filesystem. See appjail-fstab(1) for more details. # Fortunately, most programs are flexible enough to use a custom directory, which in most cases is initially empty or otherwise only has a few files. VOLUMESA volume, at least in AppJail, is a mechanism for keeping data generated by applications inside the jail. A volume is not linked to a specific filesystem, but the preferred one is nullfs(5). However, changing the file mode, UID and GID, and remembering the mount point every time we need to implement the ephemeral concept is repetitive. A script can be created, but if you plan to deploy your application, it is probably best to have a formal way to accomplish such a task. The formal way is known as appjail-volume(1), the utility for creating volumes, although it works in conjunction with appjail-fstab(1). Typically, these specifications are not created by the end user, but by the developer who wrote the Makejail. It is common to use images to distribute volume specifications since they are preserved in this format. # The <volumefs> pseudo-filesystem does all the work for the end user. The user only needs to create a directory, but the file mode, UID, and GID are completely set by appjail-fstab(1) depending on the entries specified by appjail-volume(1). The best part is that it is irrelevant to know where to mount the directory, the user only needs to know the volume name. UPDATE / UPGRADEThis is the part where we see a strong difference between the “cattle vs. pets” debate. FreeBSD users, as mentioned, treat their jails like a cute pet, or in other words, they expect to run freebsd-update(8) on a jail, which is not possible for thin jails, but is possible for thick jails. For thin jails, freebsd-update(8) runs on the release (or the base directory as known on some websites or books); Everything is fine, if you only need to update, the problem is when you want to upgrade. The upgrade process is a bit more complicated than a simple update because you are effectively applying changes to a modified system that can cause conflicts. Thin jails further complicate this process as they are tied to the release directory (or base directory), so it is necessary to create a new jail with the installed application and the data it uses. The newly created thin jail should of course use a release with the new FreeBSD version. Even if you use a thick jail, you have to worry about other things, such as storage (in the modern era, it may not be a problem) and time and resources (bandwidth, storage, CPU consumption, etc.), since that you need to do the upgrade process for each jail. Clearly, treating jails like a pet is not feasible in these cases. How can we use the ephemeral concept to upgrade jails? Suppose we have a jail using a release with FreeBSD 13.3-RELEASE and we want to upgrade it to 14.0-RELEASE, since we follow the ephemeral concept, our data will persist even if we destroy and create the jail again, so let's do it, create the jail again but using a release with 14.0-RELEASE. # The best part is that we don't need to worry about merging files or anything similar, but we do need to take into account the files that need to persist after the jail is created again, especially the files in /etc, /usr/local/etc and the configuration files used by the application running inside the jail, but those files should only be installed at the creation time and if you need to modify one of them, modify it on the host and create the jail again with the modified files. Fortunately, in most cases users do not modify absolutely all configuration files. As a last note, we should keep in mind that old configuration files may or may not make sense for new FreeBSD versions or new versions of the application you want to run inside the jail. Fortunately, backward compatibility in many projects is a priority, but it's worth keeping this note in mind anyway. BACKUP / RESTOREThere is nothing magical about backing up a volume. You only have to worry about a few details:
SEE ALSOappjail(1) appjail-fstab(1) appjail-image(1) appjail-jail(1) appjail-makejail(1) appjail-update(1) appjail-upgrade(1) appjail-volume(1) appjail-makejail(5) mount_nullfs(8) AUTHORSJesús Daniel Colmenares Oviedo <DtxdF@disroot.org>
|