Déployer des VM VMware avec Ansible – part 2

Posted by

Où est ce qu’on en était ?

La dernière fois qu’on a parlé de machines virtuelles déployées à l’aide d’Ansible sur une infrastructure VMware, on avait un playbook fonctionnel, mais il me manquait encore un petit quelque chose.

En fait, à l’issue du déploiement de la VM, je n’avais pas encore trouvé la possibilité d’enchaîner sur l’exécution d’autres playbooks permettant de configurer la VM. L’objectif ultime étant de faire en une seule étape de :

  • déployer la VM (que j’appellerai « déploiement »)
  • et de la configurer, c’est à dire modifier les fichiers de configuration de la VM, installer les logiciels, etc… (que j’appellerai « configuration »).

Premier problème, connection:local

Pour rappel, le premier problème quand on veut déployer une VM qui n’existe pas encore… est justement le fait qu’elle n’existe pas encore !

Si j’exécute un playbook deploy_vm.yml sur une VM « ma-vm » tel quel, je vais me prendre un message d’erreur (pour plus de détails, lire l’article précédent) car Ansible tente de se connecter à la machine pour récupérer des informations sur elle.

La méthode pour s’affranchir de ce genre de problèmes est de feinter Ansible en lui disant :

  1. de ne pas récupérer les informations de la machine
  2. d’exécuter le playbook sur une autre machine (le plus simple c’est localhost)

Pour le premier point, la solution est mettre en haut du playbook l’option gather_facts: false. Cela aura un impact mais on verra ça plus loin.

Pour le second point, il existe 2 solutions. La première, que je préconisais dans l’article précédent, consiste à utiliser en haut du playbook l’option connection: local. Cette option permet d’exécuter l’ensemble du playbook sur la machine locale et non pas la machine qu’on déploie.

En réalité, il est en fait plus simple d’utiliser l’option delegate_to, qui se limite à une seule tâche ou à un rôle, ce qui permet de déléguer la partie déploiement à localhost, puis tenter d’exécuter les autres playbooks sur la VM qu’on veut configurer.

Un problème de nom … pas si facile à résoudre

Vous avez vu le jeu de mot ? Ok, je sors…

Bien sûr, on va se heurter à plusieurs problèmes… Le premier est la résolution de nom. A moins d’avoir réalisé la mise à jour de votre DNS à l’avance (à la main du coup… c’est nul), dès que le déploiement sera terminé et qu’on passera à la partie configuration de la VM, Ansible essayera de contacter votre nouveau serveur.

Le plus propre serait d’ajouter à la partie « déploiement » une tâche permettant de mettre à jour le DNS. Dans mon environnement professionnel, le service DNS est géré par un serveur Windows Active Directory. La simple mise à jour du DNS depuis Linux est un vrai casse tête et le plus simple est d’intégrer la machine (qu’elle soit Windows ou Linux) dans le domaine Active Directory qui se charge alors de mettre à jour le DNS lui même.

C’est un gros sujet et je ferai un article à part dessus. Dans un premier temps on peut se contenter de juste mettre à jour le fichier /etc/hosts de la machine localhost.

- name: add to /etc/hosts file
  lineinfile:
    dest: /etc/hosts
    line: '{{ custom_ip }} {{ inventory_hostname }} {{ inventory_hostname }}.zwindler.fr'
  with_items: '{{play_hosts}}'
  when: "hostvars[item].inventory_hostname == inventory_hostname"
  delegate_to: localhost

Accès concurrents

Si vous vous y connaissez un peu en Ansible, vous remarquerez que je ne me suis pas contenté d’un simple lineinfile, mais que j’ai utilisé un with_items et un when.

En fait, on peut utiliser mon playbook pour déployer en parallèle un grand nombre de VMs en même temps. Le souci que j’ai rapidement eu a été un accès concurrent sur le fichier, et des noms de VMs ont alors manqué.

Il existe une fonction « serial » qui permet de désactiver la parallélisation des tâches, mais malheureusement, on ne peut l’appliquer qu’au playbook entier. Peut être qu’un jour la fonctionnalité sera ajoutée (la demande est référencée sur Github à l’adresse suivante : https://github.com/ansible/ansible/issues/1217)

J’ai donc du passer par une boucle pour enregistrer tous les serveurs du play courant.

Clé SSH

OK, maintenant, on sait résoudre la (ou les) machine(s) qu’on vient d’ajouter. Cependant on est pas sorti de l’auberge !

En partant du principe que vous n’avez pas oublié de déposer la clé SSH du serveur localhost pour qu’Ansible puisse se connecter sur votre nouvelle machine, voilà ce qui va se passer :

TASK [gather facts] *************************************************************************************************************************************************************************
The authenticity of host 'zwindler01 (x.x.x.x)' can't be established.
Are you sure you want to continue connecting (yes/no)? The authenticity of host 'zwindler02 (x.x.x.x)' can't be established.
Are you sure you want to continue connecting (yes/no)? The authenticity of host 'zwindler03 (x.x.x.x)' can't be established.

Ansible bloque à la première connexion SSH vers votre VM nouvellement crée car il faut accepter l’empreinte de chaque VM manuellement au préalable. Même si on essaye de renseigner yes à toutes les questions, ce n’est clairement pas idéal et encore moins automatisé !

La solution temporaire, host_key_checking=False

Il existe un paramètre dans Ansible qui permet de passer outre la vérification de l’empreinte de la machine, soit en modifiant le fichier de configuration ansible.cfg, soit ajouter un flag à l’exécution de playbook, soit configurer une variable d’environnement.

ansible-playbook -l zwindler* -i hosts_deploy -e 'host_key_checking=False' deploy_vmware_guest.yml
#OU
export ANSIBLE_HOST_KEY_CHECKING=False
ansible-playbook -l zwindler* -i hosts_deploy deploy_vmware_guest.yml

Vous trouverez plus d’informations sur cette solution de contournement sur les sites suivants :

Cette solution de contournement est à proscrire en production, car elle va ignorer l’empreinte de TOUTES les machines et pour TOUS vos playbooks. Au delà du problème évident de sécurité que ça pose, si vous enlevez l’option à un moment donné, c’est retour à la case départ. Vous aurez de nouveau la question sur tous les serveurs dont vous n’avez pas explicitement accepté l’empreinte.

ssh-keyscan à la rescousse

On va donc ajouter la tâche suivante à notre playbook de déploiement :

- name: accept new ssh fingerprints
  shell: ssh-keyscan {{ custom_ip }},{{inventory_hostname}} >> ~/.ssh/known_hosts
  with_items: '{{play_hosts}}'
  when: "hostvars[item].inventory_hostname == inventory_hostname"
  delegate_to: localhost

Je sais… c’est terrible : la solution que j’ai à l’heure actuelle, bien que fonctionnelle, N’EST PAS IDEMPOTENTE… :-( mais elle fonctionne.

Et on fini par un petit setup pour récupérer les facts.

- name: gather facts
  setup:

Et maintenant ?

Et bien ! Maintenant, ça marche ! Vous pouvez enchainer d’autres tâches (ou des rôles) en ne mettant plus delegate_to, et ces tâches de « configuration » seront bien lancées sur le serveur que vous venez de déployer, dans un seul et même playbook.

---
- hosts: all
  gather_facts: false

  vars_prompt:
    - name: "vsphere_password"
      prompt: "vSphere Password"
    - name: "esxi_host"
      promt: "ESXi host"
      private: no
    - name: "notes"
      prompt: "VM notes"
      private: no
      default: "Deployed with ansible"

  roles:
     - deploy_vmware_guest
     - other_role_for_configuration

Pari réussi !

Et le playbook, il est où ?

Une fois de plus, je suis sympa, je vous donne un exemple de code sur mon Github !

20 comments

  1. hello zwindler,

    très très bon tuto. j’essaie actuellement de passer le provisionning de nos infra vsphere avec ansible et ça m’aide beaucoup.
    Du coup, est-ce que c’est possible avec des VMs avec plusieurs cartes réseaux/disques? Comment on s’y prend?

  2. Bonne question ! Je n’en ai pas eu besoin personnellement mais un coup d’oeil à la documentation du module me laisse penser que c’est possible :

    A list of networks (in the order of the NICs).
    One of the below parameters is required per entry:
    – name (string): Name of the portgroup for this interface.
    – […]

    Il faut donc déclarer les NICs dans une liste, chaque élément de la liste disposant de toutes les entrées nécessaires (désolé l’indentation de passe pas dans les commentaires).


    networks:
    - name: VM Network
    mac: aa:bb:dd:aa:00:14
    - name: VM Network2
    mac: aa:bb:dd:aa:00:16

    Je n’ai pas le moyen de tester (plus d’infra VMware sous la main) mais je suis pratiquement certain que c’est possible.

  3. Hello !
    Merci pour ces tutos vraiment encourageants. Penses-tu qu’il soit possible de remplacer le ssh avec winrm justement afin de configurer une la VM une fois déployée ?
    Merci

  4. @Enuma : Oui tout à fait ! Je n’ai personnellement pas essayé mais voilà comment je m’y prendrai :
    – modifier le playbook de déploiement de la VM pour qu’elle s’intègre au domaine Windows dès la création (c’est une option du module Ansible de mémoire)
    – créer un template qui autorise par défaut la connexion WinRM (pas activé par défaut)

    Pour le 2ème point je montre comment faire dans cet article : https://blog.zwindler.fr/2016/11/15/administrer-des-serveurs-windows-avec-ansible/

    N’hésites pas à me faire un retour si tu y arrives, ça m’intéresse !

  5. Super tuto.J’ai fais presque la meme chose mais plutot que de pointer sur des templates vmare j’utilise un serveur kickstart mais effectivement j’ai passer beaucoup de temp sur les GATHER FACTS :(

  6. Merci pour le retour ! Effectivement c’est une bonne idée le kickstart. Si tu as un exemple n’hésites pas à le poster je suis sûr que ca peut en intéresser d’autres :-)

  7. Salut, j’ai un soucis! quand j’exécute le playbook j’obtiens une erreur qui me dis qu’il n’arrive pas à trouver le dossier /A_DEPLOYER

    « msg »: « No folder /A_DEPLOYER matched in the search path : /Datacenter Test/vm/A_DEPLOYER »}

    Une idée ?

    Merci

  8. De ce que je devine de ta capture d’écran, tu as créé le dossier dans la vue Datastore. Est ce que tu peux le créer dans la vue « Serveurs », directement sous ton cluster ?

  9. Pardon, je voulais dire dans la vue où on trie les VMs dans des dossiers. Du coup ça doit s’appeler « VMs and Templates » de mémoire (je sais plus trop car je n’ai plus VMware à disposition)

    Ca peut aussi être du au fait qu’on a un espace dans le nom du datacenter (Datacenter Test). Peut être que le module le gère mal.

    Dans tous les cas, il me semble que cette option Folder est optionnelle. On pourra la supprimer, ça sert juste à trier les VMs quand on en a beaucoup

  10. Ah oui et il faut pas faire un dossier « vm », ce « vm » dans le message d’erreur est ajouté par VMware justement pour dire qu’on est dans la vue des VMs et des templates.

    Donc il faut aller dans la vue VMs et templates, puis créer directement à la racine du cluster le dossier A_DEPLOYER

  11. Tant mieux

    Et merci pour le retour, j’ajouterai l’info comme quoi c’est optionnel le FOLDER

  12. Hello, j’ai tout testé et tout est nickel, j’ai modifié un peu e ssh-keyscan pour qu’il soit idempotent.
    Par contre, on a l’habitude de créér des vms à partir d’une liste csv sous powershell.
    Est-ce que tu n’a pas un script pour au moins extraire le hostname et l’ip du csv puis l’inserer dans le host inventory?

  13. Je veux bien une PR ou un détail des motifs pour le ssh-keyscan idempotent ;-)
    Pour la question, je n’ai pas déjà fais ca non, mais c’est sur que c’est faisable. Il me semble même qu’il y a des modules qui facilitent ce genre de chose (la constitution d’inventaires a partir de données externes).
    A vérifier donc avant de s’embêter à faire des choses complexes, si ça se trouve c’est déjà nativement possible

  14. Bonjour,
    désolé de déterrer le sujet mais j’ai quelques questions…
    Je connais Ansible mais vsphere c’est une autre affaire.
    Du coup j’ai installer un esxi de test, donc je n’ai pas de datacenter, vcenter etc..
    j’ai un client vsphere mais pour moi c’est la même chose que esxi
    Je veux juste déployer une machine de A à Z avec Ansible.

    Déjà j’ai pas mal galéré avec les folder (dans mon cas fallait juste mettre vm pour qu’il mette les vm à la racine et non dans ha-datacenter/vm/mavariable)

    J’ai réussi à créer une vm mais … Etant donné que je n’ai jamais créer de vm avant j’ai pas de template (et je vois pas l’intérêt puisqu’on veut créer et gérer les vm via ansible )
    Du coup je suis bloqué au niveau de la création de la vm qui … ba forcément n’a pas d’iso puisqu’on lui a jamais spécifié quand elle allait en avoir, et du coup boot sur rien et le playbook reste bloqué forcément.
    Alors je voudrais bien qu’on m’explique les templates (où on les mets, comment ils se gérent) car du peu que je sais pour moi c’est des .ovf qu’on peut mettre un peu partout. Donc des machines déjà configurées mais nous on veut des différentes à chaque fois.
    Je sais pas à quoi sert le guest_id, je pensais que ça allait trouver une image correspondant à l’OS justement pour l’installation mais apparemment non
    ansible 2.7.5, VMware ESXi 6.0

  15. Un peu de terminologie du coup : ESXi, c’est l’OS. vSphere c’est le produit (la suite, comprenant plus ou moins de logiciels, dont l’OS, mais aussi la console, le clustering, etc).

    Comme je l’explique dans l’article, ESXi gratuit est bridé. Il existe beaucoup de fonctionnalités qui ne sont (ou n’étaient, à minima) présentes QUE si tu as vSphere, et donc payantes.

    Pour ce qui est de l’intérêt des templates, et bien ça dépend du usecase forcément, mais tu avouera que disposer d’une VM de base, avec l’OS installé et préconfiguré quand tu en as des dizaines à créer, c’est quand même plutôt pratique. A noter, je ne parle pas des templates OVF (VMs exportées) mais bien des templates qu’on peut créer dans l’interface, à partir d’une VM qu’on a précédemment installée.

    Pour le guest_id, c’est majoritairement informatif. ESXi s’en sert pour éventuellement tweaker les paramètres de la machine virtuelle et surtout du hardware virtuel à créer. Ca peut n’avoir aucun rapport avec l’OS qui est réellement installé dans la VM.

    Si tu ne souhaites pas utiliser les templates, il existe dans le module Ansible une option pour monter un ISO, appelée cdrom, ajoutée en 2.5. Nécessairement, tu vas devoir réécrire le playbook pour prendre en compte cette modif. De plus, vu que tu vas installer manuellement l’OS avec ton CD, tu ne pourrais pas « enchainer » comme je le montre dans l’article (voir part 1 où je ne le faisais pas)

    Pour rappel : https://docs.ansible.com/ansible/latest/modules/vmware_guest_module.html#vmware-guest-module

Leave a Reply

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.