Objectif

VMWare du pauvre : permettre un développement de programmes réseau sur les machines de bureau, sans nécessiter de machine physique (les "bacs à sable").

La machine "réelle" du développeur est appelée machine hébergeante et les machines virtuelles sur lesquelles on peut faire tourner les programmes de test sont appelées machines hébergées.

Moyen :
- Jail pour créer des machines virtuelles
- XNested pour afficher les programmes graphiques

Synthèse

Jail a été utilisé pour construire un réseau virtuel hébergé sur une machine physique.

Ce réseau virtuel va être utilisé pour la mise au point des logiciels client/serveur.

La solution a des limitations, par exemple sur la prise en compte des caractères accentués.

Une autre limtation est d'être restreinte à l'exécution de programmes FreeBSD (pas d'exécution de logiciel Windows, par exemple).

Installation de Jail sur une machine FreeBSD

La première source d'information est la man page de Jail.

1/ ajout d'interfaces réseau

Les jails sont démarrés à partir d'adresses IP, et il faut donc des adresses IP sur des interfaces réseau.

Les nouvelles adresses IP ne doivent pas perturber le fontionnement de l'interface rl0 classique configurée automatiquement avec DHCP.

Utilisation de la fonction VLAN pour créer des interfaces virtuelles : ajouter à l'interface rl0 "réelle" des interfaces vlan auxquelles il est possible d'affecter une adresse IP.

Voir la page de manuel vlan.

dans /etc/rc.conf

# creation d'interfaces "bidon"
cloned_interfaces="vlan0 vlan1 vlan2 vlan3"
ifconfig_vlan0="inet 172.31.0.1 netmask 0xffffff00 vlan 1 vlandev rl0"
ifconfig_vlan1="inet 172.31.1.1 netmask 0xffffff00 vlan 2 vlandev rl0"
ifconfig_vlan2="inet 172.31.2.1 netmask 0xffffff00 vlan 3 vlandev rl0"
ifconfig_vlan3="inet 172.31.3.1 netmask 0xffffff00 vlan 4 vlandev rl0"

Avec ces éléments dans /etc/rc.conf, les interfaces virtuelles vlan sont créées et configurées correctement à chaque démarrage de la machine hébergeante.

A faire : vérifier que les VLAN correspondants aux étiquettes 1 à 4 prises pour les vlan0 à vlan3 ne sont pas utilisés par les équipements réseau.

2/ remplissage de l'arborescence de jail

Une machine virtuelle construite avec Jail exécute des processus. L'appel système jail impose à ces processus de vivre dans une sous-arborescence du disque de la machine hébergeante (/new_usr/jails/172.31.0.1/). Les processus de la machine hébergée sont "emprisonnés" (d'où le nom jail = prison en anglais) et ne peuvent pas accéder aux fichiers au-dehors de cette arborescence.

L'ensemble de l'arborescence vue par les machines hébergées est visible depuis la machine hébergeante : le fichier /etc/rc.conf de la machine hébergée est aussi le fichier /new_usr/jails/172.31.0.1/etc/rc.conf dans la machine hébergeante.

En résumé : une machine hébergée ne voit que les ressources qui lui ont été allouées (et en particulier pas les ressources allouées aux autres machines hébergées), mais la machine hébergeante voit tous les fichiers de toutes les machines hébergéees.

Donc tous les programmes exécutés par la machine virtuelle doivent être stockés dans cette arborescence (par exemple sous-arborescence commençant à /new_usr/jails/172.31.0.1/).

L'arborescence système de la machine hébergée est remplie avec le résultat d'une compilation "make buildworld" utilisée pour la machine hébergeante.

dans la machine hébergeante :

cd /usr/src
make buildworld
make installworld DESTDIR=/new_usr/jails/172.31.0.1/
cd etc
make distribution DESTDIR=/new_usr/jails/172.31.0.1/

Upgrade des programmes dans un jail :
mise à niveau des binaires du jail par installation des nouveaux binaires dans le jail
fusion des fichiers de conf avec mergemaster

3/ mise en place d'un serveur DNS sur la machine hebergeante

Création d'un domaine DNS "privé", à usage exclusif des machines du développeur : domaine "tfh", avec des adresses dans la plage 172.31.XX.YY ; définition d'un domaine propre pour les machines hébergées (voir le domaine test-vic comme exemple)

configuration du DNS comme cache avec :

forwarders {
191.250.99.1;
191.250.99.2;
};
listen-on { 172.31.3.1; };

L'adresse prise pour la consigne listen-on est la dernière de celles déclarées sur les VLAN.

configuration comme serveur de nom pour le nouveau domaine avec :

zone "tfh" {
type master;
file "tfh.hosts";
};

zone "31.172.in-addr.arpa" {
type master;
file "172.31.rev";
};

Fichiers de configuration du DNS dans la machine hébergeante :
/etc/named/named.conf : configuration du serveur named
/etc/named/172.31.rev : traduction adresse IP -> nom
/etc/named/tfh.hosts : traduction nom -> adresse IP

Accès à ce DNS depuis la machine hébergeante : (dans /etc/resolv.conf)

search mydomain tfh
nameserver 172.31.3.1

L'accès au DNS privé depuis la machine hébergeante permet de conserver une correspondance adresse IP / nom de machine aussi pour la machine hébergeante (et par là même, accepter dans la machine hébergeante du courrier électronique en provenance des machines hébergées).

4/ Configuration de la machine hébergeante

autorisation du routage dans la machine hébergeante

La machine hébergeante est configurée en routeur pour permettre aux machines hébergées de se connecter aux ressources du réseau externe.

Pour ne pas perturber le fonctionnement du réseau externe, une fonction de "masquerading" est mise en place : les connexions réalisées par les machines virtuelles sont maquillées par la machine hébergeante comme si elles avaient été initialisées par la machine hébergeante elle-même :

# connexion sans masquerading/NAT réalisée par une machine jail vers 1923 :
[machine virtuelle @ 172.31.0.1]
paquet de données originel : IP source : 172.31.0.1 - IP dest 191.250.105.213
[routeur = w00-3415]
paquet de données sur le réseau externe : IP source : 172.31.0.1 - IP dest 191.250.105.213
[arrivée du paquet sur unx-1923]
[traitement]
[retour ?]
# unx-1923 ne sait pas où renvoyer la réponse
# donc la connexion n'aboutit pas : les machines hébergées n'ont pas d'accès aux
# serveurs externes

# connexion avec NAT
[machine virtuelle @ 172.31.0.1]
paquet de données originel : IP source : 172.31.0.1 - IP dest 191.250.105.213
[routeur = w00-3415]
[traduction d'adresse : w00-3415 substitue son adresse IP propre 191.250.104.244 à 172.31.0.1
paquet de données sur le réseau externe : IP source : 191.250.104.244 - IP dest 191.250.105.213
[arrivée du paquet sur unx-1923]
[traitement]
[retour vers w00-3415]
paquet de données sur le réseau externe : IP source : 191.250.105.213 - IP dest 191.250.104.244
[traduction d'adresse inverse : w00-3415 substitue 172.31.0.1 à son adresse IP propre 191.250.104.244
[routeur = w00-3415]
paquet de données : IP source : 191.250.105.213 - IP dest 172.31.0.1
[arrivée sur la machine virtuelle @ 172.31.0.1]

Configuration de la traduction d'adresse dans la machine hébergeante - deux solutions possibles : ipfw+natd, mais recompil du noyau ou ipnat sans recompilation

# (en fait, ipfilter est cassé dans 5.2-Release, donc utilisation de ipfw/natd)
# masquerade avec ipfw/natd qui fonctionne mieux
dans /etc/rc.conf :
# masquerading
gateway_enable="YES"
# Lancement du firewall ipfw et paramétrage de natd
firewall_enable="YES"
firewall_type="open" # pas de filtrage sur les paquets
natd_enable="YES"
natd_interface="rl0" # nom de l'interface externe
natd_flags="-dynamic" # prise en compte du DHCP sur rl0

Pour que natd fonctionne, il faut une configuration particulière du kernel FreeBSD :

# passerelle
options IPFIREWALL #firewall
options IPDIVERT #divert sockets

# utilisation de ipfilter en post 5.2-Release
# solution initiale : masquerading avec ipnat/ipf pour accéder à l'extérieur
dans /etc/rc.conf :
gateway_enable="YES"
ipnat_enable="YES" # Set to YES to enable ipnat functionality
# les regles sont dans /etc/ipnat.rules :
map rl0 172.31.0.0/16 -> 0/32 portmap tcp/udp 40000:60000
map rl0 172.31.0.0/16 -> 0/32


# ipnat fonctionne avec GENERIC depuis que le kernel GENERIC a l'option suivante :
options PFIL_HOOKS # pfil(9) framework

Autres éléments de configuration pour la machine hébergeante

Dans la machine hébergeante, il faut arrêter le démon sshd : le démon se "binde" sur toutes les adresses IP affectées conflit avec les machines hébergées tant que les adresses IP sur le réseau externe sont fournies par DHCP.

La machine hébergeante doit être référencée dans un DNS (sinon, sendmail ne démarre pas correctement. La solution technique pour que les machines existent dans un DNS, bien qu'elles soient sous contrôle d'un serveur DHCP, est d'utiliser le procotole d'origine Windows "WINS", qui automatise la mise à jour d'un serveur DNS Windows. D'autres solutions normalisées existent (DDNS : Dynamic DNS), mais ne sont pas utilisées sur le réseau externe.

Un exemple de fichier de configuration de samba est (/usr/local/etc/smb.conf) ici.

De même que pour sshd, samba utilise toutes les interfaces IP d'une machine. La conséquence est que l'adresse IP remontée par WINS est aléatoire, et pas forcément l'adresse IP de la carte réseau publique. Pour forcer Samba à ne s'intéresser qu'à l'interface publique, il faut ajouter la consigne suivante à smb.conf (rl0 étant le nom de l'interface externe de la machine "hébergeante") :

bind interfaces only = yes
interfaces = rl0

5/ configuration de la machine hébergée

Lancement dans la machine hébergeante d'un shell dans le contexte du jail :

jail /new_usr/jails/172.31.0.1/ jail0.tfh 172.31.0.1 /bin/sh

dans /etc/fstab : (fichier vide)

dans /etc/hosts :

127.0.0.1 localhost localhost.tfh jail0 jail0.tfh

Configuration du DNS : forcer à regarder d'abord sur le serveur DNS de la machine hébergeante en remplissant /etc/resolv.conf avec :

search tfh mydomain
nameserver 172.31.3.1

Autres paramètres de configuration dans le fichier /etc/rc.conf :

hostname="jail0.tfh"
sshd_enable="YES"
sendmail_enable="NO" # Run the sendmail inbound daemon (YES/NO).
network_interfaces=

sendmail dans la machine hébergée est uniquement utilisé pour émettre le courrier vers la machine hébergeante (pas de configuration en réception).
A faire : configurer w00-3415 comme smarthost pour les machines hébergées (pour pouvoir émettre du courrier électronique depuis les machines vers d'autres machines que w00-3415).

Configuration du courrier électronique : remplir la correspondance pour root dans /etc/mail/aliases :

root: herbelot@w00-3415.sfim.fr
# le destinataire réel doit avoir un nom DNS valide pour que le courrier arrive

vérification de la connexion au sendmail hébergeant depuis un jail :

telnet w00-3415.mydomain 25
Trying 191.250.104.237...
Connected to w00-3415.mydomain.
Escape character is '^]'.
220 w00-3415.mydomain ESMTP Sendmail 8.12.10/8.12.10; Wed, 14 Jan 2004 11:59:53 +0100 (CET)
^]
telnet> q
Connection closed.

La connexion est acceptés : le courrier électronique pourra être transmis à w00-3415

Dans la machine hébergeante; le serveur sendmail complet est lancé : dans /etc/rc.conf

sendmail_enable="YES"

vérification de la connexion vers un autre serveur :

%telnet unx-1923 ldap
Trying 191.250.105.213...
Connected to unx-1923.mydomain.
Escape character is '^]'.
^]
telnet> q
Connection closed.

La connexion est acceptée : la traduction d'adresse est correctement réalisée.

créeation d'un compte utilisateur de test dans la machine hébergée :

jail0#cat >> /etc/group
users:*:1001:
^D

jail0# adduser
Username: test
Full name: test
Uid (Leave empty for default):
Login group [test]: users
Login group is users. Invite test into other groups? []: wheel
Login class [default]:
Shell (sh csh tcsh nologin) [sh]: csh
Home directory [/home/test]:
Use password-based authentication? [yes]:
Use an empty password? (yes/no) [no]:
Use a random password? (yes/no) [no]:
Enter password:
Enter password again:
Lock out the account after creation? [no]:
Username : test
Password : *****
Full Name : test
Uid : 1002
Class :
Groups : users wheel
Home : /home/test
Shell : /bin/csh
locked : no
OK? (yes/no):

Il faut aussi donner un mot de passe à "root", administrateur de la machine virtuelle, "hébergée avec la commande :

passwd root

Les machines hébergées sont pilotées en se connectant à distance avec la commande ssh. Chaque machine hébergée démarre un démon sshd.

mise a l'heure du jail :

cp /etc/localtime /new_usr/jails/172.31.0.1/etc/localtime

NB : la crontab standard de FreeBSD (/etc/crontab) contient une consigne pour suivre le passage à l'heure d'été. Cette consigne doit être débrayée dans la machine hébergée :

# Adjust the time zone if the CMOS clock keeps local time, as opposed to
# UTC time. See adjkerntz(8) for details.
#1,31 0-5 * * * root adjkerntz -a

6/ démarrage du jail

Dans la machine hébergeante, les jails sont démarrés avec le même mécanisme que les autres services de FreeBSD : paramètres dans /etc/rc.conf et démarrage effectif par un script dans le répertoire /etc/rc.d. Les paramètres utilisés dans /etc/rc.conf pour démarrer les jails sont :

jail_enable="YES" # Set to NO to disable starting of any jails
jail_list="jail0" # Space separated list of names of jails

#
# To use rc's built-in jail infrastructure create entries for
# each jail, specified in jail_list, with the following variables.
# NOTE: replace 'example' with the jail's name.
#
jail_jail0_rootdir="/new_usr/jails/172.31.0.1" # Jail's root directory
jail_jail0_hostname="jail0.tfh" # Jail's hostname
jail_jail0_ip="172.31.0.1" # Jail's IP number
jail_jail0_exec="/bin/sh /etc/rc" # command to execute in jail
jail_jail0_devfs_enable="YES" # mount devfs in the jail

La configuration complète de la machine hébergeante est définie dans /etc/rc.conf

(voir les devfs.rules pour les problèmes de sécurité sur les accès aux périphériques)

Démarrage des jails depuis la machine hébergeante :

w00-3415# /etc/rc.d/jail start
Configuring jails: set_hostname_allowed=YES unixiproute_only=YES sysvipc_allow=NO.
Starting Jails: jail0.tfh
w00-3415#

(NB : voir comment arrêter / démarrer une machine en particulier ; ce ne doit pas être possible)

Vérification du démarrage de la machine hébergée :

w00-3415% ssh test@jail0
test@jail0.tfh's password:
Last login: Wed Jan 21 17:34:54 2004 from 172.31.0.1
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
The Regents of the University of California. All rights reserved.

FreeBSD 5.2-CURRENT-20040108-JPSNAP (GENERIC_NODEBUG) #1: Wed Jan 14 18:49:27 CET 2004

Welcome to FreeBSD!
jail0%

La connexion par ssh aboutit : on vérifie ainsi que le démon ssh dans la machine "jail0" a étécorrectement démarré.

7/ ajout de packages dans la machine hébergée

L'environnement ainsi construit dans la machine hébergée est restreint aux programmes livrés en standard avec FreeBSD. Pour utiliser d'autres programmes tels que PostGres, un serveur LDAP, un agent SNMP ou un serveur web apache, il faut ajouter ces applications avec le mécanisme des packages (applications pré-compilées).

Les packages sont installés à partir du CD-ROM officiel d'installation de FreeBSD pour la release 5.2 . Ce CDROM est monté depuis la machine hébergeante :

w00-3415# mount_cd9660 /dev/acd0 /new_usr/jails/172.31.0.1/cdrom

NB : le CDROM ainsi monté apparaît sous le nom /cdrom dans la machine hébergée.

Les applications sont installées dans la machine hébergée :

cd /cdrom/packages/All
pkg_add XFree86-4.3.0,1.tbz

NB : pb éventuel de cohérence entre les programmes userland de la machine jail qui est en 5.2-CURRENT et les packages issus du CDROM de FreeBSD 5.2-RELEASE.

8/ Configuration de X-Windows

X-Windows (X11) est utilisé pour afficher des programmes avec sortie graphique. X11 est configuré avec des clients graphiques exécutés dans la machine "jail" et un affichage dans la machine hébergeante.

xdm (X11 Display Manager) est utilisé sur la machine jail pour valider les connexions des utilisateurs.
La configuration de xdm est définie dans le fichier : /usr/X11R6/lib/X11/xdm/xdm-config.
L'accès au serveur xdm est défini dans le fichier de configuration : /usr/X11R6/lib/X11/xdm/Xaccess

xdm est démarré dans la machine jail par le script /etc/rc.local. Théoriquement xdm est démarré depuis /etc/ttys, mais ce ne doit pas être possible avec un jail : quel est le script qui utilise /etc/ttys ?

L'affichage des fenêtres graphiques sur la machine hébergeante est réalisé de deux manières distinctes :
- allocation d'un écran X11 complet pour visualiser les fenêtres graphiques : dans un terminal "mode console texte", taper la commande X -query 172.31.0.1 :1, et on retrouve un écran de login xdm dans le terminal Ctrl-Alt-F10,
- utilisation du programme Xnest dans la session KDE pour afficher sur le même écran les fenêtres des sessions locale et "jailée", comme illustré dans la figure suivante. La commande à taper est : Xnest -query 172.31.0.1 :2.

Copie d'écran avec Notes sous Wine (fenêtre en haut à droite, "titre S Lotus Notes") et un Jail (fenêtre en bas à gauche, titre "Xnest")

Un inconvénient majeur de la première méthode est d'obliger à commuter d'écran entre la session KDE locale et la (les) sessions graphiques dans les jail. Un inconvénient commun aux deux méthodes est est de pas pouvoir réaliser de copier/coller entre les sessions.

Autre limitation pour la solution Xnest : les caractères accentués obtenus par la combinaison <AltGr>+<"> ne permet pas d'obtenir le caractère "dièse".
La configuration du clavier pour les touches accentuées est rélisée avec le programme xmodmap, et le fichier de configuration ~/.Xmodmap, déclenché par le fichier de configuration ~/.xsession . Les caractères accentués sont correctement pris en compte avec la méthode "X -query ... :3".

Analyse du problème :
pour un clavier en Français : configuration xmodmap par copie de xmodmap.fr dans ~/.Xmodmap et LC_CTYPE dans ~/.login_conf
Mais la touche AltGr n'est pas prise en compte dans une fenêtre "terminal" (idem dans une fenêtre "éditeur)
ISO_Level3_Shift dans le serveur X hébergeant
Une trace des évènements X11 pour l'utilisation de la touche <AltGr> (dans une fenêtre Xnest) est ici.

La première machine "jail" est accompagnée des packages du projet "Gnome". Les packages ont été installés avec la commande pkg_add à partir du CDROM d'installation FreeBSD pour sa version 5.2-Release.

Une première configuration avec Xnest n'était pas stable (crash régulier de la fenêtre Xnest). Une solution à ce problème est de débrayer l'économiseur d'écran de gnome dans la session X11.

9/ Reste à faire

Installer des binaires d'une release de FreeBSD différente de celle de la machine hébergeante : par exemple, les binaires d'une version FreeBSD 4.9 dans un jail hébergépar un FreeBSD 5.2 . Cette mixité des versions peut être utilisée pour vérifier la compatibilité d'un programme développé dans un environnement FreeBSD 5.2 avec une autre version comme la 4.9 (cas typique pour le logiciel BTE).

NB : l'addition des packages dans une machine "jail" est très lente ! (avec 90% de l'activité en "system", ce doit être les contrôles de debug dans le kernel de la machine hébergeante - virer options WITNESS_SKIPSPIN du kernel).
compilation d'un kernel make buildkernel KERNCONF=GENERIC_NODEBUG, en enlevant l'option WITNESS_SKIPSPIN, pour essayer d'être plus rapide.
Effectivment, avec un kernel dont les options de debug ont disparu, la machine principale et la machine virtuelle est beaucoup plus utilisable.

Le PC hébergeant doit exécuter tous les programmes de la machine hébergeant et de toutes les machines hébergées. Au vu de la consommation mémoire des logiciels utilisés, il faut prévoir une mise à niveau (ajout) de la mémoire RAM dans le PC (fait le 26/01/2004).

Utiliser gdm au lieu de xdm pour contrôler les connexions aux machines jail.
pister le bug dans epiphany (browser web) sur rafraichissement des frames.

Partage des informations utilisateurs avec LDAP : la machine hébergeante et les machines hébergées ne partagent pas les informations "utilisateurs" : nom des comptes utilisateurs, mots de passe, ... La version 5.2 de FreeBSD permet l'utilisation de LDAP pour réliser cet échange d'informations (à mettre en place !)
Dans la même veine : installer la bibliothèque nss_winbind du projet Samba pour utiliser les utilisateurs et mots de passe Active Directory pour les connexions sur FreeBSD.

Installer Apache2 + p5-apache-PageKit (option de compilation pour Apache2 différentes de celles utilisées sur 1923) : jail est ici utilisé pour préparer le développement réel sur 1923.

10/ limitations

Le mécanisme "Jail" est restreint à l'exécution de programmes FreeBSD. Il est donc impossible avec le mécanisme "jail" de simuler un réseau avec des machines sous Linux et des machines sous Windows. Pour Cette utilisation, VmWare est irremplaçable.

Comme indiqué plus haut, Xnest ne permet pas d'utiliser des caractères accentués.

Les programmes exécutés dans le jail semblent mal se comporter (blocages) quand l'adresse IP "publique" de la machine hébergeante change (suite à un renouvellement DHCP) et que la connexion NFS vers unx-1923 (serveur NFS "externe") n'a pas été stoppée avant le changement d'adresse IP.

Une solution serait de monter les partitions NFS depuis l'intérieur d'un jail mais :

jail0# mount unx-1923:/files1/distfiles /mnt
nfs: /mnt: Operation not permitted

On dirait qu'on ne peut pas monter une partition NFS depuis un jail.

BUG de FreeBSD : Le démon sshd n'est pas compatible avec le fonctionnement jail :

# connexion depuis la machine hote vers le jail avec X11 forwarding
w00-3415% ssh -X test@jail0
test@jail0.tfh's password:
Last login: Tue Feb 3 11:53:38 2004 from 172.31.0.1
# pas de serveur factice pour rediriger les requetes X11 dans le jail
jail0% netstat -an -f inet
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
udp4 0 0 172.31.0.1.177 *.*
udp4 0 0 172.31.0.1.514 *.*
# mais un serveur dans la machine hote
w00-3415% netstat -a -f inet | grep jail0
tcp4 0 0 jail0.tfh.x11-ssh *.* LISTEN
w00-3415% sockstat -4 | grep 6010
1002 sshd 8726 9 tcp4 172.31.0.1:6010 *:*
# le process correspondant est pourtant en prison
w00-3415% ps auxww | grep 8726
1002 8726 0,0 0,2 6112 2360 ?? SJ 15:04 0:00,04 sshd: test@ttyp6 (sshd)
jail0# ps auxww | grep 8726
test 8726 0,0 0,2 6112 2360 ?? SJ 15:04 0:00,04 sshd: test@ttyp6 (sshd)

11/ Travaux liés

(lien vers le document sur les vservers Linux)

Mise à jour de /etc/resolv.conf dans le jail

$Id: Jail.html,v 1.5 2004/02/12 09:54:04 herbelot Exp $