11 validated L1-platform validé 2026-05-21

Tatooine — Rebuild complet from zero

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/appdata mounté 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):

  1. pki (step-ca) — autorité certs *.minfra.in
  2. traefik — reverse proxy + Let’s Encrypt resolver
  3. authentik — SSO (Postgres + Redis + worker + server)
  4. holocron — admin Next.js (forward-auth Authentik)
  5. hors-jeu — magazine football (public)
  6. portainer — Docker UI
  7. vaultwarden — Bitwarden-compatible
  8. 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

  1. Disque < 100G : Docker images Next.js/Astro = ~2GB chacune × 3 services + LE storage + Authentik DB → saturer rapidement. 100G minimum sur template.
  2. dnsmasq DHCP conflit Kea : si reboot OPNsense restore dnsmasq DHCP → port 67 squatté, Kea down. Run task opnsense:config pour disable dnsmasq DHCP via API (idempotent).
  3. Cloud-init user ansible vs SSH packer : template Packer crée user packer (NOPASSWD sudo), cloud-init crée user ansible. host_vars utilise ansible_user: packer pour compat — sudo OK.
  4. Holocron Turbopack : ssh2/dockerode bindings natifs CJS → serverExternalPackages dans next.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 (var debian_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)