Sans DHCP, config-drive à la rescousse

Contexte

Pour un de nos clients, nous avons été amenés à travailler sur une infrastructure cloud OpenStack un peu particulière à plusieurs titres. Il s'agit ici de la version Queens, dernière version stable à date de cet article.

L'objectif de la plateforme est de fournir des instances Compute avec accès à des périphériques matériels particuliers (notamment avec PCI Passthrough). Côté réseau, la création et la gestion de réseaux au sein du cloud n'ont pas été identifiés comme des besoins, nous avons donc privilégié des choix d'architecture allant au plus simple, par exemple en ne dépoyant pas l'agent L3 Neutron et en nous limitant à l'utilisation directe d'un réseau externe connecté au compute node. Le tout avec un nombre de machines réduit au minimum pour commencer, 1 controller et 1 compute node.

Cette simplicité apparente est à contrebalancer avec une contrainte non négligeable : les deux machines (controller et compute) ne sont pas connectées sur un même réseau L2. Le trafic est routé (et est en réalité transporté par VPN).

L'outil de déploiement utilisé ici, OpenStack-Ansible nous permet de manière assez aisée de répondre à ces contraintes : ne pas déployer certains composants et connecter les deux machines au travers d'un réseau routé. Il reste toutefois un point à régler.

Problématique de la fourniture d'adresses IP aux instances

Le mécanisme le plus classique pour distribuer des adresses IP aux instances, c'est DHCP. L'agent DHCP de Neutron se charge de lancer et configurer un serveur DHCP (dnsmasq par défaut) pour faire ce travail. Au vu des contraintes réseau évoquées précédemment, cette solution n'est pas facilement exploitable puisque DHCP fonctionne au sein d'un réseau L2 et ne passe pas au travers d'un routeur.

Nous avons donc décidé de nous passer de DHCP et n'avons donc pas déployé l'agent DHCP de Neutron. Toutefois, sans connectivité, les instances n'ont aucun moyen de communiquer avec l'API de metadata (http://169.254.169.254), ce qui pose une nouvelle question. Ainsi nous avons également fait le choix de nous passer de ce service : nous avons désactivé l'API de metadata exposée par Nova et n'avons pas déployé l'agent de metadata Neutron dont le rôle est normalement de faire proxy entre les instances et cette API.

C'est donc sur les deux points suivants qu'il nous a fallu trouver des solutions :

  • Distribuer des adresses IP aux instances
  • Exposer les metadata aux instances

Solution config-drive

La fonctionnalité config-drive fournie par Nova, le service de Compute, répond à ces deux points.

Config-drive se substitue à l'API de metadata au sens où les informations normalement exposées au travers de cette API sont embarquées dans un disque ("disque de configuration") lui même connecté à l'instance. L'outil cloud-init qu'on retrouve dans la plupart des images cloud sait accéder à ce disque et exploiter les données qu'il contient.

De plus, en activant l'option appropriée, Nova peut fournir les informations réseau de la machine via les metadata. Ces informations seront également exploitées par cloud-init pour configurer l'instance.

Ainsi l'option force_config_drive du nova.conf permet d'activer la fonctonnalité config-drive par défaut sans besoin d'une demande explicite de l'utilisateur lors de la requête de création d'instance au travers de l'API de Compute.

Il suffit ensuite d'activer l'option flat_injected pour que Nova génère et inclut les informations réseau.

Résultat

Dans une instance connectée à un réseau sans DHCP, on monte le config-drive pour constater qu'on y trouve bien la configuration réseau, puis on constate que celle-ci a bien été implémentée par cloud-init afin de founir de la connectivité réseau :

root@myinstance:~# mkdir /mnt/config-drive
root@myinstance:~# mount -oro /dev/sr0 /mnt/config-drive/
root@myinstance:~# cd /mnt/config-drive/openstack/latest/
root@myinstance:/mnt/config-drive/openstack/latest# cat network_data.json
{"services": [], "networks": [{"network_id": "affc4c87-f1d1-4605-afda-3829c4a4cbc9", "type": "ipv4", "services": [], "netmask": "255.255.255.0", "link": "tap2498eebd-35", "routes": [{"netmask": "0.0.0.0", "network": "0.0.0.0", "gateway": "10.42.42.1"}], "ip_address": "10.42.42.6", "id": "network0"}], "links": [{"ethernet_mac_address": "fa:16:3e:62:7c:09", "mtu": 1500, "type": "bridge", "id": "tap2498eebd-35", "vif_id": "2498eebd-3593-49b9-938f-b0380930586b"}]}
root@myinstance:/mnt/config-drive/openstack/latest# cat /etc/network/interfaces.d/50-cloud-init.cfg
# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
auto lo
iface lo inet loopback

auto ens3
iface ens3 inet static
    address 10.42.42.6/24
    mtu 1500
    post-up route add default gw 10.42.42.1 || true
    pre-down route del default gw 10.42.42.1 || true

Conclusion

Se passer de DHCP au sein du service de Compute OpenStack est en réalité très simple grâce à la fonctionnalité config-drive.

Il s'agit ici d'une des solutions mises en œuvre pour répondre aux différentes contraintes spécifiques de ce déploiement d'OpenStack, et il faut noter à nouveau que ceci a été réalisable directement avec OpenStack-Ansible sans avoir recours à des moyens techniques additionnels externes.

La discussion continue !

Nous attendons vos questions, remarques & mots doux sur notre Twitter :