Étude de cas : cloud (IaC)
26 rôles Ansible + App Platform déclaratif
Cloud
Infrastructure-as-Code self-hosted
Projet Ansible complet pour provisionner et maintenir un VPS self-hosted (Ubuntu 24.04). 26 rôles partagés, App Platform déclaratif, observabilité complète. Montre Claude Code comme outil d'infrastructure-as-code.
cloud est un projet Ansible complet pour provisionner et maintenir un VPS self-hosted, illustrant l'utilisation de Claude Code comme outil d'infrastructure-as-code avec 831 sessions.
1. Contexte
Self-hosting complet plutôt que services managés. Philosophie "build don't buy". Un VPS unique (tordu-jardin.fr) héberge tout l'écosystème : applications, bases de données, monitoring, backups, SSO.
Pourquoi le self-hosting ?
Coût maîtrisé
Un seul VPS vs. multiples services cloud managés. Réduction drastique des coûts mensuels.
Souveraineté
Données hébergées sur infrastructure contrôlée. Pas de dépendance à des tiers pour les services critiques.
Flexibilité
Configuration sur mesure pour chaque service. Pas de limites imposées par les plateformes managées.
Apprentissage
Maîtrise complète de la stack infrastructure. Chaque rôle Ansible est un savoir capitalisé.
2. Architecture 26 rôles
Le projet est structuré en rôles Ansible partagés et en instances client. Le framework multi-instance permet de déployer la même infrastructure pour plusieurs clients.
cloud/
├── playbook.yml # 23 rôles + post_tasks
├── Makefile # deploy, dry-run, vault-edit, lint
├── instances/
│ ├── _template/ # Template nouveau client
│ └── tordu-jardin/ # Instance production
│ ├── hosts.yml
│ ├── group_vars/all/
│ │ ├── vars.yml
│ │ └── vault.yml # Secrets chiffrés
│ └── roles/granit-golem/ # Rôle client spécifique
└── roles/ # 26 rôles partagés
├── base-hardening/
├── wireguard/
├── firewall/
├── docker/
├── traefik/
├── authentik/
├── monitoring/
├── backup/
└── app-platform/ Rôles principaux
base-hardening
SSH hardening, UFW, Fail2ban, AppArmor. Sécurisation du système de base avant tout déploiement.
docker + traefik
Runtime conteneurs et reverse proxy avec TLS automatique via Let's Encrypt. Point d'entrée unique.
authentik
SSO centralisée pour les 12 services. OAuth2/OIDC, SAML. Authentification unique pour tout l'écosystème.
monitoring
Prometheus + Grafana + Loki + Promtail + Tempo + cAdvisor + Node Exporter. Observabilité complète.
backup
Restic daily snapshots + WAL-G pour PostgreSQL PITR. Rétention 7d/4w/6m. Notifications via Ntfy.
app-platform
Provisionnement déclaratif des applications. Un fichier YAML suffit pour déployer un nouveau service.
3. App Platform declaratif
Les projets déclarent un .cloud/app.yml et sont auto-provisionnés. Ce pattern permet d'onboarder un projet en un seul fichier YAML : base de données, monitoring, domaine et stratégie de déploiement sont configurés automatiquement.
# .cloud/app.yml — déclaration d'une app
name: granit-golem
type: compose
domain: granit-golem.tordu-jardin.fr
database:
type: postgresql
version: "17"
monitoring:
prometheus: true
alerts: true
deploy:
strategy: blue-green 4. Observabilite
La stack d'observabilité couvre les métriques, les logs, le tracing et les alertes. Tous les composants sont déployés via Docker Compose et configurés par Ansible.
Métriques
Logs
Tracing
Visualisation
Alerting
# roles/monitoring/tasks/main.yml
- name: Deploy Prometheus stack
docker_compose:
project_name: monitoring
definition:
services:
prometheus:
image: prom/prometheus:v2.51.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
grafana:
image: grafana/grafana:11.0.0
environment:
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: "Authentik"
labels:
traefik.enable: "true"
traefik.http.routers.grafana.rule: "Host(`grafana.tordu-jardin.fr`)"
loki:
image: grafana/loki:3.0.0
volumes:
- loki_data:/loki
promtail:
image: grafana/promtail:3.0.0
volumes:
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro 5. Sécurité
La sécurité est appliquée en profondeur avec plusieurs couches complémentaires, du réseau jusqu'à l'authentification applicative.
Réseau
UFW (deny all incoming) + WireGuard VPN pour l'accès SSH. Aucun port exposé sauf 80/443.
Système
Fail2ban (rate limiting) + AppArmor (confinement conteneurs) + SSH key-only.
Applicatif
Authentik SSO pour les 12 services. OAuth2/OIDC avec MFA. Traefik middleware d'authentification.
Secrets
Ansible Vault pour tous les secrets. Aucun mot de passe en clair dans le dépôt.
# roles/base-hardening/tasks/main.yml
- name: SSH hardening
template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
notify: restart sshd
- name: Configure UFW defaults
ufw:
state: enabled
policy: deny
direction: incoming
- name: Allow SSH via WireGuard only
ufw:
rule: allow
port: "{{ ssh_port }}"
interface: wg0
- name: Configure Fail2ban
template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
notify: restart fail2ban
- name: Enable AppArmor profiles
command: aa-enforce /etc/apparmor.d/docker-*
when: apparmor_profiles | length > 0
# roles/authentik/tasks/main.yml
- name: Deploy Authentik SSO
docker_compose:
project_name: authentik
definition:
services:
server:
image: ghcr.io/goauthentik/server:2024.4
environment:
AUTHENTIK_SECRET_KEY: "{{ vault_authentik_secret }}"
labels:
traefik.enable: "true"
traefik.http.routers.authentik.rule: "Host(`auth.tordu-jardin.fr`)" 6. Disaster Recovery
La stratégie de reprise après sinistre combine des snapshots réguliers et la réplication des bases de données pour minimiser la perte de données.
Restic Snapshots
- Backups quotidiens à 3h du matin
- Rétention : 7 daily, 4 weekly, 6 monthly
- Cibles : /opt/docker, /etc/traefik, /etc/wireguard
- Notification Ntfy en cas de succès ou d'échec
WAL-G (PostgreSQL PITR)
- Point-in-Time Recovery pour toutes les bases
- WAL archiving continu vers stockage distant
- Restauration à n'importe quel instant
# roles/backup/tasks/main.yml
- name: Configure Restic backup
template:
src: backup.sh.j2
dest: /opt/backup/backup.sh
mode: '0700'
- name: Setup backup cron (daily 3am)
cron:
name: "restic-backup"
hour: "3"
minute: "0"
job: "/opt/backup/backup.sh >> /var/log/backup.log 2>&1"
# templates/backup.sh.j2
#!/bin/bash
set -euo pipefail
# Restic snapshot
restic backup \
--tag {{ inventory_hostname }} \
--exclude-caches \
/opt/docker /etc/traefik /etc/wireguard
# PostgreSQL WAL-G PITR
for db in {{ postgresql_databases | join(' ') }}; do
wal-g backup-push --pgdata /var/lib/postgresql/data
done
# Retention: 7 daily, 4 weekly, 6 monthly
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
# Notify success
curl -s -d "Backup OK: {{ inventory_hostname }}" \
{{ ntfy_url }}/backup-{{ inventory_hostname }} 7. Claude Code pour l'IaC
Avec 831 sessions, le projet cloud démontre que Claude Code est particulièrement efficace pour l'infrastructure automation.
Patterns d'utilisation
Génération de rôles Ansible
Claude génère des rôles complets avec tasks, handlers, templates Jinja2, defaults et molecule tests. La structure est respectée systématiquement grâce au CLAUDE.md.
Debugging Docker Compose
Résolution de problèmes de networking, volumes, dépendances entre services. Claude lit les logs et propose des corrections ciblées.
Templates Jinja2
Écriture de templates de configuration complexes avec conditionnels, boucles et filtres. Particulièrement efficace pour les configurations Traefik et Prometheus.
Documentation operationnelle
Runbooks, ADR, Architecture Decision Records, post-mortems générés efficacement avec Claude. La documentation suit un format standardisé.
CI/CD Pipeline
# .gitlab-ci.yml
stages:
- lint
- validate
- deploy
lint:
stage: lint
script:
- ansible-lint playbook.yml
- yamllint -c .yamllint.yml .
syntax-check:
stage: validate
script:
- ansible-playbook playbook.yml --syntax-check
- ansible-playbook playbook.yml --check --diff
variables:
ANSIBLE_HOST_KEY_CHECKING: "false"
deploy:
stage: deploy
script:
- make deploy INSTANCE=tordu-jardin
when: manual
only:
- main
environment:
name: production
url: https://tordu-jardin.fr 8. Métriques
9. Enseignements
Claude Code excelle en IaC Ansible
Templates Jinja2, handlers, conditions, variables : Claude produit des rôles Ansible de qualité production avec peu de corrections nécessaires.
App Platform = onboarding en 1 fichier YAML
Le pattern déclaratif permet de provisionner un projet complet, base de données, monitoring, domaine, déploiement, avec un seul fichier de configuration.
Multi-instance framework prêt
Le framework est conçu pour supporter plusieurs clients ou instances. Le template _template/ permet de créer une nouvelle instance en quelques minutes.
Documentation générée efficacement
Runbooks, ADR, post-mortems : Claude Code génère la documentation opérationnelle dans un format standardisé, directement intégrée au dépôt.