Infra as Code
Toute l'infrastructure est décrite dans le dépôt infra/infra. On ne crée plus une VM à la main dans Proxmox : on l'ajoute dans le code, et le pipeline GitLab la crée.
| Outil | Rôle | Dossier |
|---|---|---|
| OpenTofu | Crée les ressources : VMs Proxmox, puis règles OPNsense et projets GitLab | tofu/ |
| Ansible | Configure l'intérieur des machines et passe les mises à jour | ansible/ |
| Renovate | Ouvre une merge request à chaque nouvelle version d'un outil | renovate.json |
Faire un changement
- Crée une branche et modifie le code. Par exemple, pour une nouvelle VM, ajoute une entrée dans
tofu/envs/prod/main.tf. - Ouvre une merge request. Le pipeline lance fmt, validate et plan.
- Ouvre le job plan et lis ce qui va être créé, modifié ou détruit.
- Fais relire, puis merge sur
main. - Dans le pipeline de
main, lance le job apply à la main.
Une ligne destroy dans le plan supprime la VM et son disque. Si tu ne comprends pas pourquoi elle est là, n'applique pas.
L'état OpenTofu
OpenTofu garde la liste de ce qu'il gère dans un état. Il est stocké dans GitLab, dans le projet infra, menu Operate → Terraform states, et chiffré.
Les secrets du pipeline sont des variables CI masquées et protégées (Settings → CI/CD → Variables) :
| Variable | Contenu |
|---|---|
TF_VAR_state_passphrase | Phrase de passe de chiffrement de l'état et des plans |
PROXMOX_VE_ENDPOINT | Adresse de l'API Proxmox |
PROXMOX_VE_API_TOKEN | Jeton d'API Proxmox de l'utilisateur tofu |
OPNSENSE_URI, OPNSENSE_API_KEY, OPNSENSE_API_SECRET | Accès à l'API d'OPNsense (https://10.194.24.56:8443) |
Tant que PROXMOX_VE_ENDPOINT n'est pas définie, les jobs plan et apply ne tournent pas.
L'emplacement de la phrase de passe de l'état et du jeton Proxmox dans Vaultwarden, une fois créés.
L'état chiffré est illisible sans sa phrase de passe. Range-la aussi hors ligne, comme les secrets des sauvegardes.
L'état est verrouillé
Un job plan ou apply verrouille l'état pendant qu'il tourne. Si un pipeline est annulé en cours de route (par exemple quand on pousse un nouveau commit), le verrou peut rester et les jobs suivants échouent avec Error acquiring the state lock.
- Vérifie dans Build → Pipelines qu'aucun job OpenTofu ne tourne.
- Va dans Operate → Terraform states, menu ⋮ de la ligne
prod→ Unlock. - Relance le job qui a échoué.
Les deux actions sont dans le même menu. Remove state file supprime l'état et tout son historique : le prochain apply repart de zéro et tente de recréer toute l'infrastructure. C'est arrivé le 2026-11-09 : rien n'a été détruit (Proxmox et OPNsense ont refusé les doublons), mais l'état a dû être reconstruit à la main.
Reconstruire un état perdu
Si l'état disparaît, on rattache les ressources existantes avec des blocs import, sans rien recréer :
- Retrouve l'identifiant de chaque ressource dans le journal d'un ancien job plan (lignes
Refreshing state... [id=…]). Les journaux des pipelines restent disponibles même quand l'état est perdu. - Écris un bloc
importpar ressource (exemple :tofu/envs/prod/imports-restauration.tf, à supprimer une fois l'apply passé). - Lis le plan : il ne doit contenir que des
importet des modifications sur place, 0 to destroy. Une ressource importée peut vouloir être remplacée à cause d'un attribut qui ne sert qu'à la création (lecloned'une VM, l'URL d'une ISO) : ajoute-le danslifecycle { ignore_changes = [...] }plutôt que d'appliquer.
Le plan attend 15 minutes sur une VM
OpenTofu attend que l'agent invité QEMU d'une VM publie ses adresses IP, pendant 15 minutes au maximum. Si l'agent n'est pas installé dans la VM, chaque plan et chaque apply qui touche cette VM attend ces 15 minutes sans rien afficher, puis continue avec un simple avertissement. Le rôle Ansible common installe l'agent (qemu-guest-agent).
Si GitLab est en panne
GitLab héberge le code de l'infra qui le fait tourner. Pour pouvoir tout reconstruire sans lui :
- le dépôt est copié automatiquement ailleurs (miroir) ;
- l'état OpenTofu est sauvegardé régulièrement hors de GitLab ;
- le script
scripts/tofu-init.shpermet de lancer OpenTofu depuis un laptop.
L'emplacement du miroir et de la sauvegarde de l'état, et la procédure de reconstruction testée pas à pas.
Runner
Les jobs tournent sur le runner de l'instance (10.194.24.34, exécuteur Docker), qui ne prend que les jobs avec le tag formule. Le pipeline l'ajoute déjà à chaque job.
- Il est installé depuis le dépôt apt officiel de GitLab Runner :
sudo apt install --only-upgrade gitlab-runnerle met à jour. - Dans
/etc/gitlab-runner/config.toml, la ligneextra_hosts = ["gitlab.formuleets.ca:142.137.247.115"]force l'IP de GitLab dans les conteneurs des jobs. Sans elle, le DNS échouait une fois sur deux au clonage (Could not resolve host). Si l'IP de GitLab change, mets cette ligne à jour.
Le runner tourne avec privileged = true (nécessaire pour Docker-in-Docker). Un job peut donc prendre le contrôle de la machine du runner : ne donne le droit de lancer des pipelines qu'à des personnes de confiance.