Zones - Solaris
Présentation
Les zones sont une solution de virtualisation intégré à Solaris. Elles sont à mi-chemin entre un chroot et un serveur virtuel. C'est à dire qu'on a un système d'exploitation hôte (appelé zone globale) dans lequel on fait tourner des process chrootés (donc qui ne voient pas les autres process de la zone globale ou des autres zones) qui sont en quelque sorte des "super process", car ils font tourner un système d'exploitation complet. Une partie des bibliothèques système sont communes entre les zones et la zone globale. C'est exactement le même principe que les jails BSD.
On peut créer des zones solaris 10 sparse (le type par défaut) ou big. Une zone sparse partage avec la zone globale les répertoires /usr, /lib, /sbin et /platform. Une big a une arborescence entièrement indépendante. La sparse va donc consommer moins d'espace disque, et lorsqu'on va patcher le système de la gloable, ça va patcher également les zones sparse. Ҫa peut-être soit un avantage soit un inconvénient. Il faut décider dès la création si on veut une sparse ou une big, car on ne peut pas changer après.
L'avantage de cette façon de virtualiser est qu'il n'y a pas besoin d'émuler la partie matérielle, gourmande en ressources. D'ailleurs, une zone qui ne fait pas tourner de process, ne consomme qu'une quarantaine de Mo. L'inconvénient est qu'il faut adapter les systèmes d'exploitation pour qu'ils puissent tourner en tant que zone. Dans les premières versions de Solaris 10, on ne pouvait faire tourner que des zones solaris 10. Plus tard, on a introduit le concept de "branded zones", qui permettent de faire tourner d'autres systèmes d'exploitation en les adaptant. Depuis solaris 10 8/07, il existe des branded zones Solaris 8 et 9 (uniquement sur Sparc). Il existe aussi des branded zones opensolaris (et des solaris 10 pour opensolaris) et des linux. Les branded zones linux ne peuvent faire tourner que des Redhat et CentOS 3.5 à 3.8, donc un noyau 2.4.
Les zones sont gérées par deux daemons : zoneadmd pour la supervision et zsched qui est l'ordonnanceur.
Les zones et le NFS
Il faut noter qu'une zone ne peut pas être serveur NFS, il n'y a que la zone globale qui peut jouer ce rôle. Un astuce peut donc consister à monter le serveur NFS sur la globale et à partager un répertoire qui appartient à la zone (car la globale accède librement à tous les filesystems des zones via le zonepath – voir chapitre "Installation/configuration d'une zone Solaris 10)".
Par contre, n'importe quelle zone peut sans problème être client NFS.
Mise à jour : il paraît, mais je n'ai pas eu l'occasion de vérifier, qu'une zone peut être serveur NFS si elle a une interface réseau dédiée.
Installation/configuration d'une zone Solaris 10
Prérequis
Avant de créer une zone, il est nécessaire d'avoir prévu :
- un répertoire pour mettre son système (par exemple /zones/zone1), appelé "zonepath". Ce répertoire doit obligatoirement avec les droits 700, sans quoi l'installation échouera.
- une adresse ip
- l'interface réseau physique sur laquelle on va connecter cette ip (par exemple bge0)
- éventuellement les filesystems à créer, sinon on peut les rajouter après
Création du fichier de configuration
Pour créer/configurer une zone, on utilise l'outil zonecfg qui est un outil en mode texte avec un prompt particulier. L'exemple ci-dessous montre assez clairement comment utiliser zonecfg :
# zonecfg –z zone1 create set zonepath=/zones/zone1 set autoboot=true add net :set physical=bge0 :set address=10.36.210.56/22 :end add fs :set dir=/data :set type=vxfs :set raw=/dev/vx/rdsk/datadg/datalv :set special==/dev/vx/dsk/datadg/datalv :end verify commit exit
Remarques :
- on peut ajouter autant de filesystems (FS) qu'on veut ; on peut également n'en mettre aucun.
- pour créer une zone big, il suffit de faire "create –b" au lieu de "create".
- verify et commit sont facultatifs. Verify sert à vérifier qu'il n'y a pas d'erreur ; il est conseillé de le faire. Commit sert à forcer l'enregistrement ; il est plutôt déconseillé de s'en servir, car il va enregistrer même s'il y a des erreurs. Exit va enregistrer et quitter.
En quittant, zonecfg créé un fichier /etc/zones/zone1.xml. Il est fortement déconseillé de modifier ce fichier directement, sans passer par zonecfg, sauf si on sait parfaitement ce qu'on fait.
Installation de la zone
Maintenant que le fichier de configuration est créé, on peut passer à l'installation de la zone (la création de tous les fichiers).
Attention : tous les filesystems déclarés à l'étape précédente avec "add fs" doivent être créés avant de passer à l'installation !
Pour installer la zone, une seule commande suffit :
# zoneadm –z zone1 install
Cette étape dure une dizaine de minutes (en fonction de la puissance du serveur). Ҫa va être un peu plus long pour une zone big.
Booter et paramétrer la zone
A ce stade, la zone est créée, mais est arrêtée. On va donc la démarrer. Au premier démarrage, on arrive dans l'utilitaire de configuration classique de Solaris, dans lequel on va choisir le type de clavier, la langue, le fuseau horaire, etc…
Pour booter la zone :
# zoneadm –z zone1 boot
Pour se connecter dessus en mode console :
# zlogin –C zone1
Pour quitter le mode console : taper "~.".
Notre zone "zone1" est maintenant accessible comme n'importe quel serveur.
Installation/configuration de zones Solaris 8 et 9
Prérequis
L'installation de containers Solaris 8 et 9 nécessite l'ajout de packages supplémentaires :
- SUNWs8brandk, SUNWs8brandr et SUNWs8brandu pour Solaris 8
- SUNWs9brandk, SUNWs9brandr et SUNWs9brandu pour Solaris 9
Création d'une flash archive
Une zone Solaris 8 ou 9 s'installe depuis une archive flash (fichier .flar). On peut trouver des archives de ce type sur le web, mais la plupart du temps, ces zones sont destinées à remplacer des serveurs physiques existants. On va donc créer une image flash depuis un serveur existant.
Voici un exemple de création d'image flash (à lancer depuis le serveur à sauvegarder) :
# flarcreate –S –c –n sol8_204 –x /u01 –x /u02 –x /backup /backup/sol8_204.flar
Explications :
- -S : évite de verifier l'espace dispo sur le disque de destination, et écrit l'image directement sur le disque (passe par la RAM sinon)
- -c : compresse l'image
- -n : label
- -x : filesystems à ne pas inclure. Attention : une image flash intègre par défaut l'ensemble des filesystems locaux et distants, il faut donc bien penser à exclure (ou préalablement démonter) les montages NFS et autres lecteurs DVD.
- à la fin de la commande, on met le nom du fichier de destination
Création du fichier de configuration
La création du fichier de configuration se fait également avec zonecfg.
A noter, quelques petites différences :
- lors du create, il faut taper respectivement pour des Solaris 8 et 9 :
create –t SUNWsolaris8 create –t SUNWsolaris9
- on peut ajouter les attributs suivants (utiles pour la migration d'un serveur existant, principalement pour des questions de licences :
> add attr set name=hostid set type=string set value=<hostid du serveur à migrer> end > addattr set name=machine set type=string set value=sun4u end
ATTENTION : depuis les dernières versions de Solaris, cette méthode ne fonctionne plus pour le hostid. Il faut juste faire "set hostid=<valeur>". C'est encore plus simple.
Installation de la zone
On va maintenant procéder à l'installation, en utilisant l'archive flash, qu'on aura déposé au préalable sur la zone globale (par exemple /var/tmp/sol8_204.flar)
# zoneadm –z zone2 install –u –a /var/tmp/sol8_204.flar
L'option "-u" fait un unconfigure pour forcer la reconfiguration au boot.
Booter et paramétrer la zone
Ici, c'est exactement comme les zones Solaris 10.
# zoneadm –z zone2 boot # zlogin –C zone2
Gestion des zones
Lister
Pour voir la liste des zones, on utilise "zoneadm list", de préférence avec les options "-cv" pour plus de détails.
Exemple :
root@uirgs37 # zoneadm list global uirgs39 uirgs40 uirgs41 uirgs42 uirgs43 uirgs44 uirgs45 uirgs46 uirgs85 uirgs38 root@uirgs37 # zoneadm list -cv ID NAME STATUS PATH BRAND IP 0 global running / native shared 12 uirgs39 running /zones/uirgs39 native shared 13 uirgs40 running /zones/uirgs40 native shared 14 uirgs41 running /zones/uirgs41 solaris8 shared 15 uirgs42 running /zones/uirgs42 solaris9 shared 16 uirgs43 running /zones/uirgs43 solaris9 shared 17 uirgs44 running /zones/uirgs44 native shared 18 uirgs45 running /zones/uirgs45 native shared 19 uirgs46 running /zones/uirgs46 native shared 20 uirgs85 running /zones/uirgs85 solaris8 shared 21 uirgs38 running /zones/uirgs38 solaris8 shared root@uirgs37 #
On voit que la globale apparait comme une zone dans la liste.
L'option "-cv" permet également de voir l'état d'une zone. Voici les principaux états que peut avoir une zone :
- configured : configurée, mais pas encore installée
- installed : installée et arrêtée
- running : elle fonctionne
Connexion
Pour se connecter à une zone, on utilise zlogin, suivi du nom de la zone.
# zlogin zone1
Pour se connecter comme si on était sur la console (permet par exemple de voir les messages au boot) :
# zlogin -C zone1
Pour quitter on fait ~. en tapant rapidement. Il est parfois nécessaire d'appuyer plusieurs fois sur ".". Il ne peut y avoir qu'une seule personne connectée en mode console.
Arrêt/reboot
Pour arrêter, démarrer ou rebooter une zone, on utilise :
# zoneadm –z zone1 halt # zoneadm –z zone1 boot # zoneadm –z zone1 reboot
Forcer l'arrêt
Il arrive parfois qu'une zone refuse de s'arrêter et reste dans l'état "down" ou "shutting down". Il est difficile de déterminer quel est ou quels sont les process qui refusent de mourir. Dans ce cas, la commande suivante peut nous sauver :
# pkill -9 -z zonename
Si même cette commande ne fonctionne pas, on est mal barré ! Il est probable qu'on soit obligé de rebooter la globale.
A noter que parfois il est nécessaire de relancer un "zoneadm -z zone halt" après le pkill.
Supprimer une zone
Pour supprimer une zone, il faut d'abort la passer à l'état "configured" :
# zoneadm –z zone3 uninstall
Puis on la supprime définitivement :
# zonecfg –z zone3 delete
Cloner une zone
Le clonage permet de dupliquer une zone existant sans avoir à refaire une archive flash.
Dans l'exemple qui suit, on va cloner la zone "zoneA" vers "zoneB".
- exporter la configuration de la zone zoneA
# zonecfg –z zoneA export –f /tmp/zoneB.zonecfg
- éditer le fichier /tmp/zoneB.zonecfg et modifier tout ce qu'il faut adapter (adresse ip, zonepath, etc)
- créer les systèmes de fichiers qui seront utilisés par la zone zoneB
- modifier les droits du zonepath du futur clone
# chmod 700 /zones/zoneB
- créer la nouvelle zone
# zonecfg –z zoneB –f /tmp/zoneB.zonecfg
- arrêter zoneA (indispensable pour que la copie des fichiers soit cohérente)
# zlogin zoneA init 0
- cloner les contenus
# zoneadm –z zoneB clone zoneA
- redémarrer zoneA
# zoneadm –z zoneA boot
- on peut maintenant démarrer et configurer la nouvelle zone
# zoneadm –z zoneB boot # zlogin –C zoneB
Dans certains cas, il peut être nécessaire de forcer la nouvelle zone à passer de l'état "configured" à "installed". On le fait avec la commande suivante :
# zoneadm –z zoneB attach -F
Flying zones
Présentation
Flying zone est le terme commercial employé par Sun/Oracle pour décrire la procédure qui consiste à migrer une zone d'une globale vers une autre. En réalité, tout se fait manuellement, rien n'est automatique, c'est 100 fois moins bien que vmware, mais le terme "Flying zone", ça pète !
Pour pouvoir migrer les données de la zone, il faut soit copier les données de la globale de départ vers celle d'arrivée, soit avoir ces données accessibles par les deux serveurs (par exemple un SAN).
Nous allons ici prendre l'exemple de la zone zone1 qui se trouve sur la globale zglobale1 et qu'on va migrer sur la zglobale2. Les données de la zone sont dans deux zpools "zp_zone1" et "zp_zone1_data". Les zpools sont sur un SAN connecté aux deux globales. Ils sont actuellement montés sur la première ; ils sont visibles de la deuxième, mais pas importés (on ne peut pas importer des zpools sur deux serveurs à la fois).
Procédure
La procédure se fait en 7 étapes.
Sur la première globale :
- éteindre la zone :
zglobale1# zlogin zone1 init 5
- detacher la zone
zglobale1# zoneadm -z zone1 detach
- exporter les zpools
zglobale1# zpool export zp_zone1 zglobale1# zpool export zp_zone1_data
Sur la deuxième globale :
- importer les zpools
zglobale2# zpool import zp_zone1 zglobale2# zpool import zp_zone1_data
- récuperer la configuration de la zone
zglobale2# scp zglobale2:/etc/zones/zone1.xml /etc/zones/
- attacher la zone
zglobale2# zglobale2# zoneadm -z zone1 attach
- démarrer la zone
zglobale2# zoneadm -z zone1 boot
Remarque : il se peut que l'attachement de la zone ne fonctionne pas la première fois, même en forçant avec l'option "-F". Dans ce cas, il faut ajouter une ligne dans le fichier /etc/zones/index, puis refaire le attach :
zglobale2# echo 'zone1:configured:/zones/zone1:' >> /etc/zones/index zglobale2# zglobale2# zoneadm -z zone1 attach
Retour arrière
On fait l'inverse, tout simplement...
- éteindre la zone
zglobale2# zlogin zone1 init 5
- détacher la zone
zglobale2# zoneadm -z zone1 detach
- exporter les zpools
zglobale2# zpool export zp_zone1 zglobale2# zpool export zp_zone1_data
- importer les zpools
zglobale1# zpool import zp_zone1 zglobale1# zpool import zp_zone1_data
- récuperer la configuration de la zone
zglobale2# scp /etc/zones/zone1.xml zglobale1:/etc/zones/
- attacher la zone
zglobale1# zoneadm -z zone1 attach
- démarrer la zone
zglobale1# zoneadm -z zone1 boot
Gestion des ressources
Présentation
Par défaut, les ressources RAM, swap et CPU sont communes à toutes les zones, y compris la globale. C'est-à-dire qu'une zone qui a un problème peut s'attribuer toutes les ressources, écrouler toutes les autres zones et même planter la globale. Il existe des moyens de limiter les ressources de chaque zone pour empêcher ça.
Toutes ces manipulations se font depuis la zone globale.
Limitation de la RAM
Pour voir la RAM actuellement attribuée aux zones :
# rcapstat -z id zone nproc vm rss cap at avgat pg avgpg 1 uirgs50 - 833M 921M 8192M 0K 0K 0K 0K 2 uirgs52 - 712M 767M 8192M 0K 0K 0K 0K 3 uirgs49 - 2789M 2816M 8192M 0K 0K 0K 0K […]
Ҫa va afficher les valeurs pour toutes les zones. Il faut regarder la colonne "cap".
Pour modifier la valeur à chaud (attention, la modification sera perdue au prochain reboot) :
# rcapadm –z zone1 –m 4g
Il faut attendre quelques secondes pour que ce soit pris en compte.
Pour limiter la RAM dans la configuration (pour qu'elle soit permanente à chaque reboot), suivre l'exemple suivant :
# zonecfg –z zone1 > add capped-memory > set physical=4g > end > exit
La limitation ne sera effective qu'au prochain boot de la zone.
Si le paramètre "capped-memory" existe déjà, on peut le modifier de la manière suivante :
# zonecfg –z zone1 > select capped-memory > set physical=4g > end > exit
Limitation du swap
Pour voir la quantité de swap actuellement allouée :
# prctl -n zone.max-swap -i zone zoneB zone: 21: zoneB NAME PRIVILEGE VALUE FLAG ACTION RECIPIENT zone.max-swap privileged 4,00GB - deny - system 16,0EB max deny -
Il faut lire la ligne "privileged".
Pour modifier la valeur à chaud (attention, la modification sera perdue au prochain reboot) :
# prctl -r -n zone.max-swap -i zone -v 6g zone
Pour limiter le swap dans la configuration (pour qu'il soit permanent à chaque reboot), suivre l'exemple suivant :
# zonecfg -z zone1 > add capped-memory > set swap=4g > end > exit
La limitation ne sera effective qu'au prochain boot de la zone.
Si le paramètre "capped-memory" existe déjà, on peut le modifier de la manière suivante :
# zonecfg -z zone1 > select capped-memory > set swap=4g > end > exit
Limitation du CPU
Il y a trois méthodes possibles pour limiter l'utilisation CPU :
- le Fair Share Scheduler (FSS) : on attribue une part minimale de CPU à une zone
- les Ressource Pools : dédie exclusivement des CPUs à une zone
- les CPU caps : alloue statiquement des pourcentages de CPU à une zone
On alloue un certain nombre de parts de CPU à une zone. Il n'y a pas de nombre de parts prédéfini à partager. Le principe est que plus une zone a de parts, plus elle aura de temps CPU attribué. Par exemple, une zone qui a 20 parts aura deux fois plus de temps CPU qu'une zone à 10 parts. Peu importe le nombre total de parts, il ne représente rien de physique. Donc en fait, on attribue une priorité à chaque zone, et cette priorité ne sert que en cas de conflit. C'est à dire que si tous les cpus sont à 100%, les priorités s'appliquent, mais si les zones les plus prioritaires ne consomment pas de cpu, alors la totalité des cpus physiques peut être utilisé par une zone de petite priorité. C'est donc la manière la plus souple de gérer l'attribution cpu et celle que je recommande.
Par défaut, une zone possède une part.
Mise en œuvre :
# zonecfg –z zone1 > set cpu-shares=20 > exit
Remarque : on peut utiliser d'autres schedulers que le FSS, mais c'est celui qui est recommandé par Sun/Oracle.
Les Ressource Pools
On attribue exclusivement des CPUs à une zone.
Pour "donner" 3 cpus à la zone zone1 :
# zonecfg –z zone1 > add dedicated-cpu > set ncpus=3 > end > exit
L'utilisation des ressource pool peut être intéressante en cas d'utilisation de logiciels dont la licence est fonction du nombre de processeurs.
Les CPU caps
Les CPUs caps définissent un pourcentage d'utilisation maximum d'un CPU pour une zone. Par exemple, une valeur de 3 signifie qu'une zone pourra utiliser au maximum 3 CPUs ; une valeur de 0.37 signifie qu'elle ne pourra utiliser que 37% d'un CPU.
Mise en œuvre :
# zonecfg –z zone1 > add capped-cpu > set ncpus=0.37 > end > exit
Pour changer la valeur à chaud :
prctl -r -n zone.cpu-cap -i zone -v 37 zone1
A noter que pour avoir 37% d'un cpu, il faut mettre 0.37 dans zonecfg, alors qu'avec prctl il faut mettre 37.
Monitoring
Les zones étant des process de la zone globale, il est difficile de distinguer la part de ressources utilisée par une zone.
On trouve quand même quelques commandes capable de donner des informations fiables :
- prstat –Z : pour afficher la quantité de mémoire et le pourcentage de CPU utilisés par zone
# prstat -Z PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP 17147 1303 1184M 1171M sleep 59 0 10:31:35 2,5% oracle/258 17137 1303 1184M 1166M sleep 39 0 11:12:27 2,5% oracle/258 17144 1303 1184M 1171M cpu10 19 0 12:33:59 2,5% oracle/258 […] 1069 root 6752K 3048K sleep 59 0 0:00:13 0,0% top/1 9511 4109 46M 20M sleep 47 4 0:15:55 0,0% LINT/1 ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE 20 73 1394M 1417M 4,3% 69:11:11 11% uirgs85 12 129 3466M 3407M 10% 20:46:52 1,7% uirgs39 0 75 222M 228M 0,7% 39:42:54 0,9% global 21 86 2887M 2911M 8,9% 23:52:49 0,6% uirgs38 17 58 2417M 2490M 7,6% 1:57:15 0,0% uirgs44 19 76 1403M 1462M 4,5% 1:35:22 0,0% uirgs46 13 45 703M 761M 2,3% 1:16:57 0,0% uirgs40 18 69 857M 931M 2,8% 1:44:56 0,0% uirgs45 14 46 351M 155M 0,5% 2:09:13 0,0% uirgs41 16 46 3194M 3209M 9,8% 8:46:48 0,0% uirgs43 15 29 18M 19M 0,1% 0:12:19 0,0% uirgs42 Total: 732 processes, 7586 lwps, load averages: 5,23, 5,53, 5,50
- prctl : pour afficher les paramètres actuels d'une zone
# prctl -i zone uirgs69 zone: 21: uirgs69 NAME PRIVILEGE VALUE FLAG ACTION RECIPIENT zone.max-swap privileged 8,00GB - deny - system 16,0EB max deny - zone.max-locked-memory system 16,0EB max deny - zone.max-shm-memory system 16,0EB max deny - zone.max-shm-ids system 16,8M max deny - zone.max-sem-ids system 16,8M max deny - zone.max-msg-ids system 16,8M max deny - zone.max-lwps system 2,15G max deny - zone.cpu-cap system 4,29G inf deny - zone.cpu-shares privileged 1 - none - system 65,5K max none -
- pour voir la consommation cpu en temps réel, et la valeur du cappage, on peut utiliser kstat. Par contre, la valeur retournée est affichée avec l'id de la zone, pas son nom. Il faudra donc faire la correspondance. Exemple :
kstat -p 'caps::/^cpucaps_zone/:' |egrep ":usage|:value" caps:1:cpucaps_zone_1:usage 114 caps:1:cpucaps_zone_1:value 770 caps:3:cpucaps_zone_3:usage 5 caps:3:cpucaps_zone_3:value 400 caps:26:cpucaps_zone_26:usage 1 caps:26:cpucaps_zone_26:value 50 caps:34:cpucaps_zone_34:usage 5 caps:34:cpucaps_zone_34:value 50 caps:36:cpucaps_zone_36:usage 146 caps:36:cpucaps_zone_36:value 800 caps:42:cpucaps_zone_42:usage 3 caps:42:cpucaps_zone_42:value 80
A noter que "value 770" correspond à un "ncpu 7.7". "zone_26" correspond à la zone dont l'id est 26 (visible avec "zoneadm list -cv".
- il y a également les utilitaires habituels vmstat, iostat, mpstat et sar qui fonctionnent à l'intérieur de zones, mais il faut être très méfiant avec leur résultat : certaines informations concernent uniquement la zone, d'autres concernent le serveur (la zone globale).
Automatiser/scripter la configuration des zones
Il est possible de scripter la configuration des zones, plutôt que d'aller systématiquement dans le shell interractif de zonecfg. Ceci est particulièrement utile pour configurer un grand nombre de zones.
- Première méthode : zonecfg sur une seule ligne
On peut passer tous les paramètres désirés à zonecfg pour que tout tienne sur une seule ligne. Voici un exemple :
# zonecfg –z zone2 'add capped-memory ; set swap=4g ; set physical=4g; end'
Ainsi, on peut facilement faire un script avec une ou quelques lignes par zone.
- Deuxième méthode : créer un fichier de configuration et l'injecter dans zonecfg (principe utilisé pour les clones)
D'abord, on créé un fichier de configuration. Par exemple :
# vi zoneC.conf create set zonepath=/zones/zoneC set autoboot=true set ip-type=shared add inherit-pkg-dir set dir=/lib end add inherit-pkg-dir set dir=/platform end add inherit-pkg-dir set dir=/sbin end add inherit-pkg-dir set dir=/usr end add fs set dir=/opt set special=/dev/vx/dsk/datadg/zoneC-opt set raw=/dev/vx/rdsk/datadg/zoneC-opt set type=vxfs end add net set address=10.36.209.207/22 set physical=bge0 end add rctl set name=zone.max-swap add value (priv=privileged,limit=8589934592,action=deny) end add capped-memory set physical=8G end
Ensuite on insère le tout dans la conf de zoneC :
# zonecfg –z zoneC –f zoneC.conf