docs: premiere creation de documentation

Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
GnomeZworc 2026-08-26 22:59:49 +02:00
commit cb904c4744
Signed by: nicolas.boufideline
GPG key ID: 4406BBBF8845D632
34 changed files with 1896 additions and 30 deletions

14
docs/demarrage/index.rst Normal file
View file

@ -0,0 +1,14 @@
Démarrage
=========
Le parcours court : un hyperviseur, un VPC, un subnet, une VM qui démarre. Tout reste sur le
même nœud — c'est suffisant pour valider une installation et pour découvrir le modèle, pas pour
faire fonctionner un parc.
Pour un cluster, poursuivre avec :doc:`/deploiement/index`.
.. toctree::
:maxdepth: 1
installation
premier-vpc

View file

@ -0,0 +1,147 @@
Installation d'un hyperviseur
=============================
Cette page installe l'agent sur **un** hyperviseur. Le réseau du cluster — routage entre nœuds,
plan de contrôle — est traité à part : voir :doc:`/deploiement/index`.
Prérequis
---------
Un host Linux avec KVM, sur lequel vous avez ``root``. Les opérations réseau (network
namespaces, netlink, VXLAN, ebtables, iptables) et QEMU ne fonctionnent que sous Linux.
Déploiement
-----------
.. code-block:: bash
curl -O https://git.g3e.fr/syonad/two/raw/branch/main/scripts/deploy.sh
bash ./deploy.sh -t 0.1.0 -i
``deploy.sh`` se met à jour lui-même depuis la branche avant toute action — s'il diffère, il se
réécrit et demande d'être relancé. Il télécharge ensuite binaires, units systemd et scripts
depuis la release, et les vérifie contre le manifeste ``SHA256SUMS``.
.. list-table::
:header-rows: 1
:widths: 26 54 20
* - Option
- Effet
- Défaut
* - ``-t <tag>``
- déployer une release donnée
- dernière
* - ``-b <branche>``
- branche utilisée pour l'auto-mise à jour du script
- ``main``
* - ``-p <profil>``
- profil d'host ; seul ``kvm`` installe les units de l'agent
- ``kvm``
* - ``-i``
- préparer l'host : paquets, noyau, réseau
- désactivé
* - ``-u <iface>``
- interface physique d'uplink
- ``eno1``
* - ``-B <bridge>``
- bridge principal, auquel l'uplink est rattaché
- ``br-000000``
* - ``-P <bridge>``
- bridge supplémentaire, créé vide et réservé
- ``br-public``
* - ``-R <secondes>``
- délai avant le redémarrage de secours pendant la migration réseau
- ``120``
* - ``-d``
- dry-run : affiche les commandes sans les exécuter
- désactivé
Les options booléennes actives par défaut se **désactivent** par leur forme longue négative :
``--nopackages``, ``--nonetwork``, ``--noverify``, ``--noup_script``.
.. warning::
``--noverify`` désactive la seule vérification d'intégrité des artefacts téléchargés. Ne
l'utiliser que pour diagnostiquer un manifeste cassé, jamais en déploiement courant.
Ce que fait ``-i``
------------------
**Paquets** — ``qemu-system-x86``, ``ovmf``, ``dnsmasq``, ``ebtables``, ``iptables``,
``nfs-common``, ``jq``, ``curl``. Le service ``dnsmasq`` du système est ensuite désactivé et
**masqué** : il prendrait le port 53 en concurrence des instances ``dnsmasq@`` que l'agent lance
dans les netns.
**Noyau** — chargement de ``br_netfilter``, puis ``net.ipv4.ip_forward = 1`` et
``net.bridge.bridge-nf-call-iptables = 1``. Cette dernière clé est **requise** par la DNAT vers
le serveur de metadata : sans elle, iptables ne voit pas le trafic bridgé des VM et cloud-init
ne se provisionne pas. Contrepartie assumée : tout le trafic inter-VM traverse les tables NAT.
**Réseau** — création du bridge réservé, puis rattachement de l'uplink au bridge principal,
l'adresse et la route par défaut étant déplacées de l'interface physique vers le bridge.
.. danger::
La migration réseau **coupe le réseau de l'host si elle échoue à mi-parcours**, sans console
de secours. Deux garde-fous sont en place : un redémarrage de secours armé avant l'opération
(``-R``, 120 s par défaut) qui ramène la configuration d'origine puisque rien n'est écrit sur
disque, et l'exécution de la séquence sous systemd plutôt que dans la session SSH, pour
qu'une coupure de SSH ne l'interrompe pas.
Le désarmement n'a lieu **qu'après** un ping réussi vers la passerelle. Prévoir un accès
physique ou console avant de lancer un ``-i`` à distance sur un host de production.
Host sans état
--------------
L'hyperviseur est **stateless** : sa racine est en tmpfs, rien de ce que pose ``-i`` ne survit à
un redémarrage. ``deploy.sh --bootstrap`` est donc rejoué à chaque démarrage — c'est le
mécanisme normal, pas une réparation.
Binaires installés
------------------
.. list-table::
:header-rows: 1
:widths: 20 60 20
* - Binaire
- Rôle
- Drapeau de config
* - ``agent``
- processus principal : API, dispatcher, exécution, watchdog
- ``-config``
* - ``metadata``
- serveur de metadata cloud-init, une instance par VM dans le netns du VPC
- ``-conf``
* - ``db``
- inspection de la base clé-valeur en ligne de commande
- ``-conf``
Les trois partagent le même fichier, ``/etc/two/agent.yml`` — voir
:doc:`/exploitation/configuration`.
Mise à jour
-----------
``deploy.sh`` relève les instances ``dnsmasq@`` et ``metadata@`` actives **avant** d'arrêter les
services, et les redémarre ensuite : c'est la seule façon de savoir lesquelles relancer. Arrêter
les services à la main avant de lancer le script fait perdre cette liste.
Vérifier l'installation
-----------------------
.. code-block:: bash
systemctl status agent
curl -s http://127.0.0.1:8080/vpcs
Une liste JSON — vide au premier démarrage — signifie que l'API répond. Passez à
:doc:`/demarrage/premier-vpc`.
.. important::
L'API de l'agent **n'a aucune authentification**. Avant d'ouvrir le port au-delà de la boucle
locale, lisez l'avertissement de :doc:`/exploitation/configuration` : quiconque atteint ce
port pilote la totalité de l'hyperviseur.

View file

@ -0,0 +1,155 @@
Premier VPC, premier subnet, première VM
========================================
Ce tutoriel crée de bout en bout une VM joignable, sur un hyperviseur où l'agent est installé et
répond. Il suppose l'API sur ``127.0.0.1:8080`` et une image disque déjà présente sur l'host.
Tout se passe sur un **seul nœud** : un subnet ne s'étend à d'autres hyperviseurs qu'une fois le
plan de contrôle du cluster en place, cf. :doc:`/deploiement/architecture-cluster`.
Ce que l'on construit
---------------------
.. mermaid::
graph LR
subgraph netns vp-admin
BR["br-sn000001<br/>10.1.1.1"]
MD["metadata@i-web<br/>169.254.169.254"]
end
VM["VM i-web<br/>10.1.1.2"] --- BR
BR --- MD
BR --- VXLAN["VXLAN vni 1<br/>br-000000"]
Le VPC est un network namespace ; le subnet y pose un bridge porteur de la gateway ; la VM s'y
raccroche par un tap, reçoit son adresse en DHCP et son cloud-init depuis le serveur de metadata
du netns.
1. Le VPC
---------
.. code-block:: bash
curl -X POST http://127.0.0.1:8080/vpcs \
-H 'Content-Type: application/json' \
-d '{"name": "vp-admin", "cidr": "192.168.0.0/16"}'
Le ``cidr`` est l'espace d'adressage global du VPC : c'est lui qui sera annoncé aux VM comme
route interne, quel que soit le mode du subnet.
La réponse est un **202** : la création est acceptée, pas terminée.
.. code-block:: bash
curl -s http://127.0.0.1:8080/vpcs/vp-admin
Attendez ``"state": "running"`` avant l'étape suivante — un subnet dont le VPC parent n'est pas
prêt est refusé en **422**. Le modèle d'attente est décrit dans :doc:`/exploitation/api-agent/asynchronisme`.
2. Le subnet
------------
.. code-block:: bash
curl -X POST http://127.0.0.1:8080/subnets \
-H 'Content-Type: application/json' \
-d '{"name": "sn-000001",
"vpc": "vp-admin",
"mode": "vxlan",
"vxlan_id": 1,
"iface_type": "vms",
"interface_ip": "10.1.1.1",
"cidr": "10.1.0.0/23"}'
``iface_type`` est une clé **logique** résolue dans la configuration de l'agent (section
``interfaces``) vers un bridge physique de l'host ; une clé inconnue retombe sur
``default_interface``. ``interface_ip`` est la gateway du subnet, portée par le bridge créé dans
le netns.
Les modes disponibles et leurs conséquences sur le routage sont détaillés dans
:doc:`/concepts/modes-reseau`.
Là encore, attendez ``running`` :
.. code-block:: bash
curl -s http://127.0.0.1:8080/subnets/sn-000001
3. La VM
--------
.. code-block:: bash
curl -X POST http://127.0.0.1:8080/vms \
-H 'Content-Type: application/json' \
-d '{"name": "i-web",
"memory": 2048,
"cpus": 2,
"uefi": true,
"metadata": {"sshkey": "ssh-ed25519 AAAA…",
"user_data": "'"$(base64 < user-data.yml | tr -d '\n')"'"},
"interfaces": [{"subnet": "sn-000001", "ip": "10.1.1.2", "primary": true}],
"storage": [{"path": "/var/lib/two/volumes/i-web.qcow2", "dev": "vda"}]}'
Quatre points qui coûtent du temps quand on les découvre en production :
``user_data`` est **encodé en base64**
Un base64 invalide est rejeté en 400 plutôt que servi vide. L'agent n'interprète jamais ce
contenu.
``password`` est un **hash**, pas un mot de passe
Le champ attend la valeur de la clé ``passwd`` de cloud-config (``$6$…``). Sans ``password``
ni ``sshkey``, aucun compte n'est créé.
Exactement une interface est ``primary``
Elle porte la route par défaut et le serveur de metadata. L'ordre du tableau détermine le
slot PCI (``0x03 + index``), donc le nom de l'interface dans le guest. Tous les subnets d'une
VM doivent appartenir au même VPC.
Un seul disque ``vdX``
Les disques supplémentaires passent par ``sdX``. La carte PCI en dépend — voir
:doc:`/architecture/contraintes`.
4. Vérifier
-----------
.. code-block:: bash
curl -s http://127.0.0.1:8080/vms/i-web
En ``running``, la VM est démarrée et le serveur de metadata est en place. Le provisionnement
cloud-init, lui, se déroule dans le guest ; on l'observe par la console série :
.. code-block:: bash
socat -,raw,echo=0 UNIX-CONNECT:/run/two/vms/serial/i-web.sock
Puis, depuis l'host :
.. code-block:: bash
ssh syonad@10.1.1.2
.. note::
En mode ``vxlan``, la VM vit dans le netns du VPC : elle n'est pas joignable depuis l'host
sans route explicite. En mode ``bridge``, elle l'est directement.
5. Supprimer
------------
Dans l'ordre inverse — un VPC dont il reste des subnets est refusé en **409** :
.. code-block:: bash
curl -X DELETE http://127.0.0.1:8080/vms/i-web
curl -X DELETE http://127.0.0.1:8080/subnets/sn-000001
curl -X DELETE http://127.0.0.1:8080/vpcs/vp-admin
La suppression d'une VM ne touche **jamais** aux fichiers disque.
.. warning::
``instance-id`` vaut le nom de la VM. Recréer une VM du même nom sur le même disque fait que
cloud-init la reconnaît et **n'applique pas** le user-data. Pour rejouer un provisionnement,
changez de nom ou repartez d'un disque neuf.