VirtualBox, Ansible, Vagrant

79 views
Skip to first unread message

Laurent Caillette

unread,
Dec 4, 2015, 2:14:01 AM12/4/15
to tec...@googlegroups.com
Avec les offres d'hébergement qui donnent accès -- littéralement -- à
des montagnes de serveurs, l'automatisation des déploiements devient
incontournable. Celle-ci engendre des programmes assez conséquents,
qui méritent d'être traités comme tels, avec bien sûr du versionnage
mais également des tests automatisés. De la même façon qu'on
différencie les tests unitaires, d'intégration, de charge, etc. il
doit être possible de trouver une typologie pour les tests des
programmes de déploiement. Disons qu'au milieu de tout ça il y a la
place pour des tests s'effectuant hors-réseau, dans des environnements
virtualisés, reconstructibles très rapidement.

Concrètement, je veux tester mes scripts Ansible avec des VirtualBoxes
qui démarrent en un clin d'œil, et itérer rapidement, toujours en
partant d'un état connu et reproductible. Si la difficulté théorique
est nulle, dans la pratique on a quelques surprises, qui sont aussi
l'occasion d'apprendre plein de choses passionnantes. Voici donc mes
aventures avec VirtualBox, Ansible, et Vagrant.


== Ansible

Ansible, qu'on peut décrire comme un outil de déploiement, fonctionne
comme un itérateur sur une liste de machines énumérées dans un
inventaire. Il applique, sur chacune d'elles, une séquence de
commandes, en faisant plein de choses utiles concernant les retours
d'erreur, la connexion SSH, etc.

Ansible est un long recueil de choix de conception vraiment bien vus.
Sans les énumérer tous, il y a le support pour des structures de
données complexes à partir de YAML. Bon des fois YAML c'est pas la
fête mais si on veut une liste de tableaux associatifs (map) eh bien
il n'y a qu'à l'écrire sans cérémonie là où on en a besoin. Soulignons
que YAML est beaucoup plus léger que JSON.

Un choix de conception déterminant consiste à se passer d'agent,
hormis un démon SSH sur la machine distante, et si possible du Python
`2.7+` mais c'est le cas d'une majorité de distros Linux en ce début
de millénaire. De plus, Ansible est capable d'exécuter des commandes
en local (y compris du Bash). Si on considère ça, ainsi que les types
de données complexes et la structure d'exécution, Ansible devient une
alternative crédible à Bash et à Python pour orchestrer de grosses
séquences d'opérations.


== Kraksoft vagrant-box-debian

Puisqu'on déploie dans des VirtualBoxes, il faut choisir l'image
initiale. Hélas OVH ne fournit rien qui reproduise la configuration de
départ de ses serveurs, ne serait-ce que pour avoir un noyau et des
paquets Debian dans la même version.

On peut trouver sur Internet une foule d'images avec toutes sortes de
produits préinstallés, mais là c'est une image avec un minimum de
produits qui nous intéresse (à l'instar de ce qu'on a choisi chez
OVH). Bizarrement, pas moyen de mettre là main là-dessus.

Heureusement il y a mieux. Le fantastique projet de Kraksoft
"vagrant-box-debian"
https://github.com/kraksoft/vagrant-box-debian
est un copieux script Bash qui télécharge l'image ISO de l'installeur
de Debian (ou Ubuntu) et lance l'installation dans une VirtualBox
fraîchement créée. À la fin il produit un fichier "box" exploitable
par Vagrant.


== Vagrant

Vagrant est un outil de manipulation de machines virtuelles, qui offre
une interface programmatique unifiée pour VirtualBox et les produits
VMWare. Vagrant propose également un référentiel d'images au format
box. Vagrant est un produit gratuit et de source ouvert pour
l'interfaçage avec VirtualBox (l'accès à VMWare est payant).

Au moins dans le cas d'utilisation qui nous intéresse, Vagrant suscite
un grand nombre d'insatisfactions.

Vagrant est populaire grâce à son catalogue en ligne de machines
virtuelles prêtes à l'emploi. Le format box est un export de machine
virtuelle compressé, avec quelques métadonnées. Dans le cadre d'une
utilisation locale, on se retrouve à compresser la machine construite
par vagrant-box-debian pour la décompresser aussitôt et la cloner. Vu
que les fichiers d'une VirtualBox Debian minimale pèsent dans les 3 Go
ça prend du temps, surtout si on bricole vagrant-box-debian et qu'on
veut voir les résultats rapidement.

Le format box a une autre incidence fâcheuse lorsqu'on souhaite
installer les VirtualBox Guest Additions. Les Guest Additions sont un
ensemble de pilotes qui fonctionnent dans le système hébergé,
notamment pour accéder à des répertoires déclarés sur le système
hébergeant. C'est magique pour éviter la copie de gros fichiers
(l'archive d'un JRE par exemple). Pour Linux, les Guest Additions se
présentent sous la forme de sources à construire sur le système cible,
et donc nécessitent un environnement de développement. Il y a bien une
extension de Vagrant qui sait tout construire en téléchargeant les
bons paquets (elle oublie juste de nettoyer les paquets installés).
Mais comme on part de la box fournie par vagrant-box-debian (qui
n'inclut pas les Guest Additions) il faut installer les Guest
Additions pour chaque clone, ce qui dure quatre minutes à chaque fois.
Pour éviter ça on peut insérer des trucs pas beaux entre l'exécution
de vagrant-box-debian et celle de Vagrant. Mais le plus simple c'est
de modifier vagrant-box-debian pour que ça soit lui qui installe les
Guest Additions. J'ai soumis mon code à Kraksoft mais je n'ai pas eu
de retour.

Donc là on espère que ça va marcher proprement. Mais comme on part
d'un fichier box, le système de clone lié de VirtualBox ne peut plus
fonctionner. Qu'est-ce qu'un clone lié ? Le système de fichier virtuel
de VirtualBox supporte la prise d'instantané. Á partir d'un
instantané, on peut dériver un nouveau système de fichiers qui ne
contient que les modifications. Le clone lié est une VirtualBox basé
sur l'instantané du disque d'une autre VirtualBox. Pour une VirtualBox
originale qui pèse 3 Go, le clone lié pèse 100 Mo et sa création est
presque instantanée. Mais Vagrant nous empêche d'utiliser cette belle
chose.

Comme on veut configurer sa VirtualBox, et déclarer notamment des
Shared Folders, on regarde un peu le langage de description de
machines virtuelles de Vagrant. Pas de bol c'est du Ruby, ça fait un
truc de plus à se traîner sur le projet. Bon écrire une boucle pour
créer ses VirtualBoxes et mettre la liste dans un fichier lu par
Ansible ça ne devrait pas être la mort (faut juste comprendre les
fermetures en Ruby). On se retrouve à dupliquer la définition des
Shared Folders du côté Ruby (Vagrant les déclare, après c'est Ansible
qui modifie le système pour les monter). Une solution consisterait à
lire à partir de Ruby le YAML d'Ansible qui énumère les
caractéristiques des Shared Folders, mais ça semblait plus urgent de
faire fonctionner la solution de bout en bout.

Finalement la magie s'opère. Ensemble, vagrant-box-debian et Vagrant
réussissent la prouesse d'ouvrir une session SSH sur un serveur Debian
qui vient d'être installé, sans qu'on ait besoin de taper quoique ce
soit dans l'interface graphique de VirtualBox, qui affiche la console
Linux. À partir de là on configure tout ce qu'on veut avec Ansible.

Mais cette prouesse s'effectue au prix de modifications obscures du
fichier ``~/.ssh/authorized_keys``. Le problème ce n'est pas la
modification initiale, c'est qu'à chaque fois qu'on fait un ``vagrant
up`` Vagrant remet les doigts dedans et va effacer les autres clés
qu'on a déployées avec Ansible.

Ajoutons que les noms données par défaut aux VirtualBoxes sont moches
et très longs (pas faits pour être tapés en ligne de commande), et que
le format box ouvre une belle faille de sécurité que nous détaillerons
bientôt. On peut d'ores et déjà conclure que Vagrant est un sale truc
dont il est sain de se passer si on veut juste manipuler des
VirtualBox qui restent sur le même poste de développeur. Après tout
c'est vagrant-box-debian, l'outil de Kraksoft, qui se tape l'essentiel
du boulot.


== Quel remplacement ?

Par quoi remplacer Vagrant, qui soit suffisamment expressif pour
manipuler des brochettes de VirtualBoxes, et qui s'interface
correctement avec Ansible ? J'avoue avoit été tenté un instant par du
Bash, tellement le code de vagrant-box-debian est limpide. Ceci dit
les structures de données complexes et les structures de contrôle, en
Bash, c'est trop l'horreur.

Une fois qu'on a vu qu'Ansible pouvait exécuter des commandes locales
et notamment ``vboxmanage``, pas d'hésitation, ça sera lui et comme ça
il y aura un modèle de données cohérent pour gérer les VirtualBoxes de
la même façon que les autres machines ou environnements.

Notons qu'il existe un module "libvirt"
https://libvirt.org
pour Ansible. Libvirtfournit une couche d'abstraction par-dessus tous
les hyperviseurs un peu connus. Ce genre d'outil a toujours les mêmes
défauts :
- On se retrouve avec le plus petit dénominateur commun des produits
qu'on souhaite abstraire.
- Comme ça ne suffit pas on lutte pour contourner la couche
d'abstraction afin de taper dans la fonctionnalité spécifique
indispensable.
- Donc on renonce à l'indépendance vis-à-vis de l'hyperviseur.
- Mais au bout de quelques années on s'aperçoit qu'il n'y a jamais eu
besoin d'en changer.
- Et comme on a fait que remplacer une dépendance par une autre on se
demande pourquoi on n'a pas tapé dans le vrai truc directement.

Bref la couche d'abstraction par-dessus les hyperviseurs, ça fait un
peu projet de mec qui s'ennuie au boulot. Ça reste facile de se
louper, une suite d'appels à ``vboxmanage`` est plus claire que son
équivalent en Ruby pour Vagrant.


== Étude technique de vagrant-box-debian et Vagrant

Pour bien comprendre les quelques trucs réussis par Vagrant, il faut
examiner toute la fabrication de la VirtualBox.

À l'origine il y a le téléchargement de l'image officielle, d'un coup
de curl, si ce n'est pas déjà fait. C'est la version "installation
réseau" qui est récupérée, ce qui réduit les téléchargements au strict
nécessaire.

Après, vagrant-box-debian éclate l'ISO dans un répertoire, et la
reconstruit avec des fichiers modifiés. Ces modifications permettent
principalement :
- Une installation sans interaction avec l'utilisateur grâce à des
choix prédéfinis.
- L'injection d'une clé publique SSH dans le répertoire de
l'utilisateur ``root``.

vagrant-box-debian arrive avec son fichier ``preseed.cfg`` qui donne
accès à tous les choix d'installation. Il se termine par une longue
ligne qui contient quelques commandes à lancer (comme des copies à
partir du CD-ROM et des chmod) avant d'exécuter un fichier de
commandes contenu également dans l'ISO. Ce fichier ``late-command.sh``
va terminer le boulot, et notamment copier la clé publique. C'est
assez difficile d'apporter une modification dans l'installation car à
ce moment précis, les points de montages ne sont pas ceux d'un Linux
en fonctionnement.

Bref, l'installation a lieu, et on se retrouve par défaut avec une
VirtualBox dotée d'une carte réseau de type NAT, c'est à dire qu'elle
accède à Internet (obligé, pour télécharger les fichiers
d'installation) mais que la machine l'hébergeant ne voit pas son
adresse IP. La bonne approche consiste à rajouter une carte réseau
(virtuelle) de type "Host only" qui partage une interface virtuelle
créée sur la machine hébergeante. Cette interface s'appelle par défaut
``vboxnet0`` et on lui donne une adresse non-routable genre
``192.168.100.100/24``. La machine hébergeante possède l'adresse
``192.168.100.100``. Les VirtualBoxes déclarant une carte réseau
attachée à cette même interface virtuelle peuvent déclarer l'adresse
de leur choix au sein de ce sous-réseau, qui se comporte exactement
comme un réseau local.

C'est important d'insister : ce sont les membres du sous-réseau qui
déclarent leur propre adresse (typiquement dans
``/etc/network/interfaces``, dans le cas présent sur ``eth1``). Ça
veut dire qu'il faut effectuer de la configuration, et donc se
connecter en tant que ``root`` par SSH. Mais pour se connecter par SSH
il faut une adresse visible de la machine hébergeante. Euh, on fait
comment, chef ?

Une solution consisterait à monter le disque virtuel d'une façon qui
permette de modifier ``/etc/network/interfaces``. Mais il y a plus
simple. Une carte virtuelle de type NAT possède une option
"redirection de port" (port-forwarding). Pour l'activer, on déclare un
port ouvert sur la machine hébergeante, et le port cible dans la
machine hébergée (je saute des détails). Si par exemple on redirige le
port local 2222 vers le port 22 de la machine hébergée, eh bien il y a
moyen de se connecter par SSH avec ``ro...@127.0.0.1``. Bon pour que ça
fonctionne il faut que le démon SSH soit démarré, sans oublier le
déploiement préalable de la bonne clé, mais c'est ce qu'on a fait
précédemment. Dans les options SSH il faut bien sûr préciser la clé
qu'on utilise, et quelques autres trucs mais finalement ça fonctionne
et on se retrouve connecté en tant que ``root``. C'est ce truc-là
qu'utilise Vagrant pour configurer les machines.

Manque de bol, comme il se connecte à une VirtualBox qui est le clone
d'une box venue de n'importe où (du référentiel Vagrant par exemple)
eh bien il faut que la clé publique soit intégrée d'office. Donc
Vagrant est livré avec toujours la même clé privée. Il semble que le
terme de "faille de sécurité"
http://stackoverflow.com/questions/14715678/vagrant-insecure-by-default
caractérise assez bien ce comportement. Heureusement à partir de la
version `1.7.0`, parue il y a moins d'un an, il n'est possible de se
connecter qu'à partir de ``localhost``. Donc si on change les mots de
passe par défaut ça devrait être bon. Mais ça laisse planer quelques
doutes sur l'importance qu'accordent les auteurs (Hashicorp) à la
sécurité.

Bref, une bonne occasion de se retrousser les manches pour remplacer
Vagrant par un truc bien.


== Nouvelle version

Après une semaine de boulot, voici ce qu'offre la version Ansible par
rapport à Vagrant :

- Injection d'une clé SSH générée avant chaque création d'un nouveau Master.
- Impossibilité d'utiliser un mot de passe pour l'utilisateur
``root``, authentification par clé publique SSH uniquement (ça coupe
court aux mauvaises envies).
- Installation des VirtualBox Guest Additions dans le Master (pour
gagner plusieurs minutes lors de la création de chaque clone).
- Création des clones liés à un instantané du Master.
- Nommage des clones et adresse IP de l'interface Host only définie en
YAML dans Ansible, facile à changer, c'est fait pour.
- Shared Folders définis dans Ansible, une seule définition utilisée
lors de la déclaration dans VirtualBox, et lors du montage Unix (et
plus tard lors de l'assignation de variables d'environnement).
- Automatisation de la création des clones, de leur arrêt, leur
démarrage, et de la réinitialisation dans l'état d'un instantané. (Ce
sont quelques scripts dit "de porcelaine" qui remplacent les commandes
``vagrant up | down | ...``.)
- Les Clones et le Master s'affichent dans le même groupe VirtualBox
(joli et pratique).
- Le seul référentiel des VirtualBoxes est VirtualBox (pas de base de
données miroir facile à désynchroniser).
- Tout est administrable à partir du VirtualBox Manager (l'interface graphique).

Pas la peine d'insister sur le gain de lisibilité,.

Le code Bash de vagrant-box-debian est conservé en l'état, ça ne cause
pas de grand souci pour l'instant.

La création du Master (hors téléchargement de l'ISO) prend 10 minutes
avec un Intel Quad-Core i7 et un SSD. La création de 2 clones en
parallèle prend une minute. La réinitialisation d'un clone prend moins
de 2 secondes.

Que de la joie, reproductible à l'infini.

Julien Kirch

unread,
Dec 4, 2015, 3:19:40 AM12/4/15
to tec...@googlegroups.com
Hello,

une idée : la prochaine fois envoie un mail avant de passer une semaine dessus, j’aurais pu te donner de suite la conclusion sur la manière de préparer l’image

ce n’est pas très clair dans ta conclusion quel montage tu fais à la fin mais ici on utilise https://docs.vagrantup.com/v2/provisioning/ansible.html ansible + vagrant avec un vaguant qui sert à créer la box puis qui délègue le boulot à ansible

Ma grosse critique sur ansible c’est que le modèle « 0 code 100% yaml » demande de faire parfois des contournements long car il n’y a pas le helper qui va bien.

Limiter les choses possibles pour assurer une baseline c’est une approche que je comprends, mais quand on a l’habitude de chef Ansible c’est comme de revenir à Maven ou à Ant (même si je comprends que pour des javaiste c’est une approche acceptable :-) ).

Julien

la grosse limite que j’y vois c’est le fait de « coder » en yaml qui oblige parfois à des circonvolutions pour des choses simples, le même genre de chose qu’on avait avec Ant
--
Vous recevez ce message, car vous êtes abonné au groupe Google Groupes techos.
Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse techos+un...@googlegroups.com.
Pour envoyer un message à ce groupe, adressez un e-mail à tec...@googlegroups.com.
Visitez ce groupe à l'adresse http://groups.google.com/group/techos .
Pour plus d'options, visitez le site https://groups.google.com/d/optout .

Laurent Caillette

unread,
Dec 4, 2015, 5:39:21 AM12/4/15
to tec...@googlegroups.com
Hé hé, quand tu commences quelque chose qui prend une semaine, tu ne
sais pas forcément jusqu'à quand ça va durer.

C'est vrai que j'ai loupé l'aspect passage de variables de Ansible
vers Vagrant. Mais je n'ai aucun regret. Tiens, dans la longue liste
de mes griefs j'avais oublié le montage des Shared Folders assez
pourri (pas les droits que je veux, noms pas beaux).

Pour le codage en YAML je reconnais que ça peut être bizarre. Pour
l'instant je suis dans la zone de presque-confort. C'est la visibilité
des variables entre les groupes, l'échappement dans les templates
Jinja2 et le déréférencement qui me cassent les pieds. C'est étrange
mais leur système pour faire des boucles sur des structures YAML est
bien.

Après sur ces sujets on a vite fait de rouvrir la bataille sans fin du
déclaratif contre l'impératif. À la fin c'est l'impératif qui gagne,
baïonnette au canon. Mais avant d'en arriver là on essaye de mettre un
maximum de déclaratif. Les mecs qui ont fait Ansible ont du constater
que la gestion de conf trimballe énormément de structures
arborescentes un peu molles et plus ou moins intégrées à l'aspect
impératif. Pour que l'impératif ne soit pas trop toxique, ils
proposent des commandes idempotentes.

Ant est juste impératif, avec du XML pour être sûr de faire bien mal.
Pour Maven on oublie la syntaxe encore plus méchante, le déclaratif
marche plutôt bien. J'ai des projets, des dépendances, des numéros de
version que je mets à jour. Où est le problème ? Quand il y a de la
génération de code ou des dépendances un peu vicieuses, Maven t'incite
à ne pas à laisser la poussière sous le tapis. Sur Novelang, le
passage de Ant à Maven a débouché sur 40 projets Maven (il y a de la
génération Antlr et d'autres machins). Que les plugins soient bien
fastidieux à écrire te motive aussi pour rester du côté déclaratif.

Je dirais qu'Ansible a trouvé un équilibre intéressant avec du
"déclaratif mou". Ça m'étonnerait pas que d'ici deux ans des mecs
sortent un outil de construction qui reprenne les principes d'Ansible,
notamment l'utilisation du YAML et la distribution sur plein de
machines.
> Pour envoyer un message à ce groupe, envoyez un e-mail à l'adresse
> Pour obtenir davantage d'options, consultez la page
> https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages