Tatooine — Rebuild complet
Pipeline 100% auto pour reconstruire tatooine (Platform DMZ) from zero. ~25 min total : template Debian (15min) + VM clone (1min) + services Docker (8min).
Pré-requis
- OPNsense up + DHCP fonctionnel sur DMZ (10.0.2.0/24)
- coruscant Proxmox up
- NAS jedha NFS export
/volume1/nfs/appdatamounté par template debian12 - Secrets SOPS déchiffrables (
~/.config/sops/age/keys.txt) - SSH key minfra (
~/.ssh/id_ed25519_minfra) présente - OVH API tokens dans
infra/ansible/inventory/secrets/ovh.yml(pour.minfra.io)
Étape 1 — Détruire l’existant
# Détruit la VM tatooine (Terraform)
task debian12:vm:destroy NAME=tatooine
# Détruit le template Debian (pour rebuild avec 100GB)
task debian12:template:destroy
Durée: ~30s.
Étape 2 — Rebuild template Debian 12 (100GB)
task debian12:template:deploy
Durée: ~15 min. Workflow Packer:
- Provisionne VM build 9100 (ISO Debian net + preseed)
- Installe Debian + cloud-init + qemu-guest-agent + Docker baked-in
- Disque 100GB (config dans
infra/packer/debian12/debian12.pkr.hcl) - Convert en template VM 9100
Vérif:
ssh root@10.0.1.30 'qm config 9100 | grep -E "scsi0|name"'
# scsi0: local-lvm:base-9100-disk-0,...,size=100G
Étape 3 — Déployer VM tatooine
task debian12:vm:deploy NAME=tatooine
Durée: ~1 min. Workflow Terraform:
- Clone template 9100 → VM 130
- cloud-init: user
ansible+ SSH key minfra - IP statique
10.0.2.10(DMZ vlan 30) - Docker baked → up direct au boot
Vérif:
ssh ansible@10.0.2.10 'docker version; df -h /'
# Doit voir 100G disponible
Étape 4 — Déployer services Docker
# Build images custom (vision/hors-jeu/holocron sur tatooine)
task svc:build HOST=tatooine
# Deploy tous services target=tatooine
task svc:deploy HOST=tatooine
Durée: ~10 min combinés (npm install + docker build + compose up).
Services déployés (ordre auto):
- pki (step-ca) — autorité certs
*.minfra.in - traefik — reverse proxy + Let’s Encrypt resolver
- authentik — SSO (Postgres + Redis + worker + server)
- holocron — admin Next.js (forward-auth Authentik)
- hors-jeu — magazine football (public)
- portainer — Docker UI
- vaultwarden — Bitwarden-compatible
- vision — dashboard DR docs
Vérif:
ssh ansible@10.0.2.10 'docker ps --format "table {{.Names}}\t{{.Status}}"'
Étape 5 — Vérifs accès interne
# DNS interne (Unbound OPNsense)
dig +short auth.minfra.in @10.0.1.1
# Doit retourner 10.0.2.10
# HTTPS interne (cert step-ca)
curl -k https://vault.minfra.in
curl -k https://hors-jeu.minfra.in
curl -k https://vision.minfra.in
Étape 6 — Exposer services public .minfra.io (optionnel)
# Sans auth (page publique)
task svc:expose SVC=hors-jeu
# Avec Authentik forward-auth (admin/SSO)
task svc:expose SVC=holocron AUTH=true
task svc:expose SVC=vault AUTH=true
Génère infra/docker/services/<svc>/traefik/public.yml + redeploy le service.
Vérif:
curl https://hors-jeu.minfra.io # Public, cert Let's Encrypt valide
curl https://vault.minfra.io # Redirect vers Authentik
Étape 7 — Postcheck global
task minfra:postcheck
Check end-to-end :
- SSH tous hôtes
- DNS Unbound
*.minfra.in - HTTPS interne (stepca certs)
- HTTPS public (Let’s Encrypt)
- Containers running
Troubleshooting
Disque saturé sur tatooine
ssh ansible@10.0.2.10 'sudo docker system prune -af --volumes; sudo journalctl --vacuum-size=100M'
Image Docker manquante au deploy
Build raté étape précédente. Re-run :
task svc:build SVC=holocron # build solo
task svc:deploy SVC=holocron
Service container crash
ssh ansible@10.0.2.10 'docker logs <container_name> --tail 50'
LE certs pas générés
ssh ansible@10.0.2.10 'sudo cat /opt/services/traefik/letsencrypt/acme.json | jq ".letsencrypt.Certificates[].domain"'
Si vide ou erreur : check OVH secrets dans /opt/services/traefik/secrets/*.txt + traefik logs docker logs traefik | grep -i acme.
Pièges connus
- Disque < 100G : Docker images Next.js/Astro = ~2GB chacune × 3 services + LE storage + Authentik DB → saturer rapidement. 100G minimum sur template.
- dnsmasq DHCP conflit Kea : si reboot OPNsense restore dnsmasq DHCP → port 67 squatté, Kea down. Run
task opnsense:configpour disable dnsmasq DHCP via API (idempotent). - Cloud-init user
ansiblevs SSHpacker: template Packer crée userpacker(NOPASSWD sudo), cloud-init crée useransible. host_vars utiliseansible_user: packerpour compat — sudo OK. - Holocron Turbopack : ssh2/dockerode bindings natifs CJS →
serverExternalPackagesdansnext.config.ts. Sans ça, build foire.
Annexe — Sources de vérité
- Template Packer :
infra/packer/debian12/debian12.pkr.hcl(disk_size = 100G) - Terraform VMs :
infra/terraform/environments/homelab/variables.tf(vardebian_vms.tatooine) - Services Docker :
infra/docker/services/*/docker-compose.yml(x-meta.target=tatooine) - Apps source :
apps/web/{vision,hors-jeu,holocron}/avec Dockerfile - IPs aliases :
infra/ansible/roles/opnsense/vars/main.yml(HOST_Tatooine, unbound overrides)