Créer et administrer vos jails par ZFS
La puissance apportée par ZFS va vous simplifier la vie dans la gestion de vos jail. Dans cet article, une base commune est créée dont sera issues toutes les jails que l'on pourra par la suite distribuer pour d'autres machines.
Mise en place
Avant d'utiliser jail(8), vous devez créer un fichier de configuration: jail.conf(5). Ce dernier est composé de deux parties.
- /etc/jail.conf
# variables communes à toutes les jails exec.clean; exec.system_user = "root"; exec.jail_user = "root"; exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.consolelog = "/var/log/jail_${name}_console.log"; path = "/jails/${name}"; R13 { host.hostname = r13; # Hostname ip4 = inherit;# IP address of the jail ip6 = inherit;# IP address of the jail path = "/jails/13.3-RELEASE"; }
Notez que le path
, s'il n'est pas précisé explicitement, prendra automatiquement le nom de la jail.
Vous aurez probablement besoin d'une interface réseau pour faire communiquer les services des jails entre eux.
ifconfig lo1 create
sysrc cloned_interfaces+=lo1
De même, pour assurer un démarrage à chaque reboot, activer le service jail:
sysrc jail_enable="YES"
Et précisez les jails à démarrer dans la variable jail_list
, ou ignorez cette variable pour toute les démarrer.
Consoles
Le paramètre exec.consolelog
va permettre d’enregistrer les messages de console des jails dans un fichier journal, pensez à programmer newsyslog(8) pour des nettoyages réguliers:
- /etc/newsyslog.conf.d/jails.conf
/var/log/jail_d13_console.log 600 7 1000 * JCG /var/run/jail_d13.pid /var/log/jail_git_console.log 600 7 1000 * JCG /var/run/jail_git.pid /var/log/jail_matrix_console.log 600 7 1000 * JCG /var/run/jail_matrix.pid /var/log/jail_pg_console.log 600 7 1000 * JCG /var/run/jail_pg.pid /var/log/jail_php_console.log 600 7 1000 * JCG /var/run/jail_php.pid
Stockage
Créer un dataset pour contenir toutes les jails, puis un dataset par jail.
zfs create -o mountpoint=/jails zroot/JAILS zfs create zroot/JAILS/13.3-RELEASE
deduplication
afin d’économiser de l'espace disque, si vous avez assez de mémoire vive.
zfs set dedup=on zroot/JAILS
Base
Récupérer une release et installons une première jail, qui va servir de point de départ à toutes les autres.
cd /jails fetch http://ftp.freebsd.org/pub/FreeBSD/releases/amd64/13.3-RELEASE/base.txz tar -C 13.3-RELEASE -xf base.txz cp /etc/resolv.conf 13.3-RELEASE/etc/resolv.conf cp /usr/local/etc/pkg/repos/*.conf 13.3-RELEASE/etc/pkg touch 13.3-RELEASE/etc/rc.conf
Dans cet exemple, j'utiliserai ma propre poudriere.
Et réglez votre rc.conf(5) ainsi:
- 13.3-RELEASE/etc/rc.conf
cron_flags="$cron_flags -J 15" # Disable Sendmail by default sendmail_enable="NO" sendmail_submit_enable="NO" sendmail_outbound_enable="NO" sendmail_msp_queue_enable="NO" # Run secure syslog syslogd_flags="-c -ss"
L’entrée pour cron(8) sert à décaler son activation par rapport à l'hôte (jitter), pour éviter que les scripts periodic(8) ne se lancent tous en même temps.Mettez des valeurs différentes pour chaque jail. Sur certaines jails, vous pouvez même le désactiver:
- 13.3-RELEASE/etc/rc.conf
cron_enable="NO"
Enfin, donnez lui un nom:
- 13.3-RELEASE/etc/rc.conf.local
hostname=nepasutiliser
Si votre jail doit pouvoir envoyer des mails, le plus rapide est d'activer le sendmail
de la base sur ce seul service:
- rc.conf
sendmail_enable="NO" sendmail_submit_enable="YES"
Et d'avoir un hostname(1) complet, sur un domaine qualifié (FQDN).
- rc.conf
hostname="diaspora.lapinbilly.eu"
Si vous désactivez complètement sendmail, les mails seront envoyés via l'hôte, si sur ce dernier est réglé pour écouter sur toutes les interfaces et non seulement localhost
.
- rc.conf
sendmail_enable="YES" sendmail_submit_enable="NO"
Attention, si vous avez autorisé cron(8), periodic(8) sera actif et vous allez remplir la base mail de root
.
Assurez vous soit de désactiver les scripts periodic(8) dans /etc/crontab
, soit d'envoyer les rapports dans un fichier:
- periodic.conf
daily_output=/var/log/daily.log weekly_output=/var/log/weekly.log monthly_output=/var/log/monthly.log daily_show_success=NO daily_show_info=NO
ou ajoutez une adresse mail générique pour cron dans /etc/rc.conf
:
- periodic.conf
cron_flags="$cron_flags -m patron@ailleurs.net"
Démarrer
Vous pouvez démarrer:
root@popeye:# jail -c R13 R13: created
Multiplier
A partir de ce point, vous avez préparé une base saine que vous allez pouvoir reproduire facilement.
Faites un cliché, test
, de la base:
zfs snap zroot/JAILS/13.3-RELEASE@test
Attention, ce cliché est dédié à la jail test
, ne prévoyez pas de l'utiliser pour autre chose, puisque qu'en cas de promotion du futur clone, il disparaîtra.
Créons une nouvelle jail, simplement en clonant ce cliché:
zfs clone zroot/JAILS/13.3-RELEASE@test zroot/JAILS/TEST
En fait, vous avez créer un dataset à partir d'un cliché.
C'est aussi simple, vous avez une jail
toute prête sur zroot/JAILS/TEST
.
Réglons là:
- TEST/etc/rc.conf.local
hostname=TEST
- /etc/jail.conf
TEST { host.hostname = TEST; # Hostname ip4.addr = "lo1|192.168.5.2"; # IP address of the jail }
Si vous devez démarrer des jails en cascade, utilisez le mot clef depend pour lier les jails entre elles.
- /etc/jail.conf
TEST2 { host.hostname = TEST2; depend = TEST; }
jail -c TEST2
TEST: created
TEST2: created
Déployer
Il suffit de promouvoir le clone, le rendre indépendant du cliché dont il est issu:
zfs promote zroot/JAILS/TEST
Et voilà.
Montages
Vous pouvez spécifier les points de montages à créer au démarrage de la jail.
Il suffit de créer un fstab
sour le nom fstab.<jail name>
et de le préciser dans jail.conf
- /etc/jails.conf
toto { mount.fstab="/etc/fstab.toto" }
C'est utile pour monter du tmpfs(5) ou du nullfs(5):
- /etc/fstab.toto
tmpfs /jails/toto/tmp tmpfs rw 0
Réseau
Si vous avez attribué une interface réseau avec IP locale sur vos jails,
en d'autre termes, vous n'avez pas utilisé inherit
sur l'un des paramètres ip4
ou ip6
,
n'oubliez pas d'écrire une règle de NAT pour qu'elles puissent accéder à l'extérieur.
Par exemple, pour pf(4):
- /etc/pf.conf
jailnet="192.168.0.0/24" # ... nat on $ext_if from $jailnet to any -> ($ext_if)
DNS
Pensez à vérifier les valeurs de resolv.conf(5). Si vous avez suivi la procédure, ce devrait être une copie de celle de l'hôte, à moins d'utiliser un serveur DNS local comme unbound(8).
Pour donner accès à ce service à vos /jails/, assurez que ce dernier écoute sur des adresses autres que localhost
.
Par exemple, associez une adresse dédiée à unbound
sur votre interface réseau:
- rc.conf
cloned_interfaces="lo1" ifconfig_lo1="inet 192.168.0.1 netmask 255.255.255.0" ifconfig_lo1_ipv6="inet6 fd00::1 prefixlen 64"
voire ajouter d'autres alias:
- rc.conf
ifconfig_lo1_alias0="inet 192.168.10.1 netmask 255.255.255.0" ifconfig_lo1_ipv6_alias0="inet6 fe00::1 prefixlen 64"
ou, à la volée:
ifconfig lo1 inet 192.168.0.1 netmask 255.255.255.0 alias ifconfig lo1 inet6 fd00::1 prefixlen 64 alias
Ensuite configurez unbound(8) pour écouter sur cette addresse:
- unbound.conf
interface: 192.168.0.1 interface: fd00::1 access-control: 192.168.0.1/24 allow access-control: fd00::1/24 allow
ou pour tout l'interface dédiée aux jails:
- unbound.conf
interface: lo1
configurez alors les resolv.conf
de vos jails pour utiliser ces adresses.
Services IP
Nombre de services locaux écoutent par défaut sur localhost
, tel que redis ou php-pfm. Dans une jail, utiliser cette adresse est une très mauvaise idée car elle reste attachée à l'hôte.
Ces services devront écouter l'adresse locale ou sur une socket unix.
routage IP
Pour les services accessibles sur IP depuis l'extérieur que vous ne pourrez pas donner à manger à nginx vous devrez utiliser des règles de redirection. Et, de nos jours, vous devrez de plus le faire pour les adresses IPV6:
- pf.conf
jail_git="fc00::168:13" jail_net="192.168.0.1/24" # ... nat on $ext_if inet from $jail_net to any -> $ext_if:0 nat on $ext_if inet6 from $jail_git to any -> $ext_if:0 rdr pass on $ext_if proto tcp from any to ($ext_if) port 9418 -> 192.168.0.13 port 9418 rdr pass on $ext_if inet6 proto tcp from any to ($ext_if) port 9418 -> $jail_git port 9418
:0
) la première adresse fournie par l'interface pour éviter que pf ne route les paquets vers un des liens locaux.
En cas de doute, préciser l'adresse:
nat on $ext_if inet6 from $jail_git to any → 2a01::
Mettre à jour
Il suffit de demander à freebsd-update(8).
Consultez d'abord les versions en cours à l'aide de freebsd-version(8):
for i in $(jls name); do printf "%-10s- %s\n" $i $(freebsd-version -j ${i}) ; done pg15 - 13.4-RELEASE-p1 php - 13.4-RELEASE-p1 synapse - 13.4-RELEASE-p1 git - 13.4-RELEASE-p1 epee - 13.4-RELEASE-p1 mariadb - 13.4-RELEASE-p1 next - 13.4-RELEASE-p1 d14 - 13.4-RELEASE-p1
configuration
freebsd-update(8) suit par défaut la configuration le fichier /etc/freebsd-update.conf
.
Créez en une plus adapté aux jails en général, en retirant tout ce qui concerne le noyau:
- /usr/local/etc/jail-update.conf
--- /etc/freebsd-update.conf 2018-11-02 03:58:09.000000000 +0000 +++ /usr/local/etc/jail-update.conf 2020-05-05 11:25:40.662419000 +0000 @@ -12,7 +12,7 @@ ServerName update.FreeBSD.org # Components of the base system which should be kept updated. -Components src world kernel +Components world # Example for updating the userland and the kernel source code only: # Components src/base src/sys world @@ -35,7 +35,7 @@ # When upgrading to a new FreeBSD release, files which match MergeChanges # will have any local changes merged into the version from the new release. -MergeChanges /etc/ /boot/device.hints +MergeChanges /etc/ ### Default configuration options: @@ -66,11 +66,11 @@ # When installing a new kernel perform a backup of the old one first # so it is possible to boot the old kernel in case of problems. -# BackupKernel yes +BackupKernel no # If BackupKernel is enabled, the backup kernel is saved to this # directory. # BackupKernelDir /boot/kernel.old # When backing up a kernel also back up debug symbol files? -# BackupKernelSymbolFiles no +BackupKernelSymbolFiles no
Lancer
Utilisez le fichier de configuration et donnez à freebsd-update(8) les bonnes informations:
- la version avec
–currently-running
- le chemin de la base avec
-b
freebsd-update -f /usr/local/etc/jail-update.conf --currently-running 13.3-RELEASE -b /jails/majail fetch install
Notez que vous pouvez automatiser le processus en demandant directement à la jail quelle version elle fait tourner:
jexec jailname freebsd-version -u 13.3-RELEASE
Utilisez automatiquement cette valeur dans un script par:
freebsd-update -f /usr/local/etc/jail-update.conf --currently-running `jexec jailname freebsd-version -u` -b /jails/majail fetch install
En cas de mise à niveau, vers une version majeure plus récente, procédure est un peu plus longue.
jail -r jailname freebsd-update -f /usr/local/etc/jail-update.conf --currently-running `jexec jailname freebsd-version -u` -b /jails/majail fetch -r 13.0-RELEASE upgrade freebsd-update -f /usr/local/etc/jail-update.conf -b /jails/majail fetch install jail -c jailname freebsd-update -f /usr/local/etc/jail-update.conf -b /jails/majail fetch install pkg -j jailname bootstrap -f pkg -j jailname upgrade jail -rc jailname
Ports
Utilisez des poudrieres pour installer des logiciels dans vos jails et afiner ainsi la configuration et le comportement d'une jail.
Par exemple, supprimer tout ce qui ressemble à une documentation, un affichage graphique ou une imprimante:
- /usr/local/etc/poudriere.d/jail-make
OPTIONS_UNSET=DOC DOCS NLS X11 EXAMPLES EXAMPLE XCB WAYLAND DEBUG TEST TESTS OPENGL DTRACE INFO BE_STANDARD OPTIONS_UNSET+=CUPS MANPAGES DEFAULT_VERSIONS+= imagemagick=6-nox11 #DEFAULT_VERSIONS+= imagemagick=7-nox11
En savoir plus
-
jail_update.sh
: mise à jour de la base desjails
en cours de fonctionnement ;portupgrade.sh
: mise à jour des ports installés dans lesjails
en cours de fonctionnement et sur l'hôte.