diff --git a/README.md b/README.md index 4d2140f..a2323d8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Infrastructure qpismont.fr -Infrastructure self-hosted complète hébergée sur serveur dédié, fournissant une plateforme DevOps avec Git, CI/CD, reverse proxy, VPN et monitoring. +Infrastructure self-hosted complète hébergée sur serveur dédié, fournissant une plateforme DevOps avec Git, CI/CD, reverse proxy, VPN et observabilité. **Domaine :** qpismont.fr **Stack :** Docker Swarm @@ -14,35 +14,53 @@ Cette infrastructure héberge l'ensemble des services nécessaires pour le déve - **Hébergement Git** avec interface web (Gitea) - **CI/CD automatisé** pour builds et déploiements (Woodpecker) +- **Agent IA de review** de code sur webhooks Gitea (Herald) - **Reverse proxy** avec HTTPS automatique (Caddy) -- **Accès VPN sécurisé** pour l'administration (WireGuard) -- **Monitoring** des services et ressources (Prometheus + Perses) -- **Backups automatisés** quotidiens vers serveur FTP +- **Accès VPN sécurisé** pour l'administration (WireGuard + CoreDNS) +- **Observabilité** : métriques, traces et dashboards (Prometheus, Tempo, Perses) +- **Alerting** temps réel avec notifications push (Alertmanager + ntfy) --- ## Services déployés -### Production +### Stack `core` -| Service | Version | Description | URL | -|---------|---------|-------------|-----| -| **Gitea** | 1.24.7 | Hébergement Git (alternative GitHub) | https://gitea.qpismont.fr | -| **Woodpecker CI** | 3.11.0 | Plateforme CI/CD (fork de Drone) | https://woodpecker.qpismont.fr | -| **Caddy** | 2-alpine | Reverse proxy + HTTPS automatique | - | -| **WireGuard** | latest | Serveur VPN pour accès distant | UDP:51820 | -| **Prometheus** | 3.7.2 | Collecte de métriques | (interne) | -| **Perses** | latest | Dashboards de monitoring | (via VPN) | -| **cAdvisor** | latest | Métriques des containers | (interne) | -| **Backup** | latest | Sauvegarde quotidienne (4h00) | (interne) | +| Service | Image | Description | Exposition | +|---------|-------|-------------|------------| +| **reverse_caddy** | `caddy:2.11-alpine` | Reverse proxy, HTTPS auto, HTTP/3 | `80`, `443/tcp`, `443/udp` | +| **wireguard_server** | `linuxserver/wireguard:latest` | VPN d'accès distant + CoreDNS | `51820/udp` | + +### Stack `git` + +| Service | Image | Description | URL | +|---------|-------|-------------|-----| +| **gitea** | `docker.gitea.com/gitea:28.2` | Hébergement Git | https://gitea.qpismont.fr · https://git.qpismont.fr | +| **woodpecker_server** | `woodpeckerci/woodpecker-server:v3.19-alpine` | Serveur CI/CD | https://woodpecker.qpismont.fr | +| **woodpecker_agent** | `woodpeckerci/woodpecker-agent:v3.19-alpine` | Agent d'exécution (Docker socket) | (interne) | +| **herald** | `tintounn/herald:1.2` | Agent IA de review sur webhooks Gitea (Docker socket) | (interne, métriques `:9100`) | + +### Stack `observability` + +| Service | Image | Description | Exposition | +|---------|-------|-------------|------------| +| **prometheus** | `prom/prometheus:v3.13.3` | TSDB + remote-write receiver | (interne) | +| **otel-collector** | `otel/opentelemetry-collector-contrib:0.164.0` | Collecte métriques + traces | (interne) | +| **docker-proxy-otel** | `tecnativa/docker-socket-proxy:0.4.0` | Proxy socket Docker (lecture seule) | (interne) | +| **tempo** | `grafana/tempo:3.0.3` | Stockage de traces (OTLP) | (interne) | +| **perses** | `persesdev/perses:latest` | Dashboards | (via VPN) | +| **alertmanager** | `prom/alertmanager:v0.34.1` | Routage des alertes | (interne) | +| **blackbox_exporter** | `prom/blackbox-exporter:v0.28.0` | Probes HTTP externes | (interne) | +| **ntfy** | `binwiederhier/ntfy:latest` | Notifications push | https://ntfy.qpismont.fr | ### Configuration - **Timezone** : Europe/Paris - **OAuth** : Gitea ↔ Woodpecker intégré - **Admin** : qpismont -- **Backup retention** : 14 jours -- **Monitoring scrape** : 10 secondes +- **Scrape interval** : 10 secondes +- **Rétention Tempo** : 48 h +- **Rétention Prometheus** : par défaut (15 j), volume persistant --- @@ -58,57 +76,63 @@ Cette infrastructure héberge l'ensemble des services nécessaires pour le déve ▼ ▼ ▼ [Caddy Proxy] [HTTP/3] [WireGuard VPN] │ │ - ┌───────────┼──────────┐ │ - │ │ │ │ - gitea:3000 woodpecker:8000 │ [Perses] - │ │ - www.qpismont.fr [Prometheus] - (désactivé) │ - [cAdvisor] + ┌───────────┼───────────┬──────────┐ │ + │ │ │ │ │ + gitea:3000 woodpecker:8000 │ ntfy:80│ + │ │ + www.qpismont.fr [CoreDNS] + (portfolio) │ + [Perses] + [Prometheus] + [Tempo] ┌──────────────────────────────────────────────────────────────┐ -│ CI/CD Pipeline │ +│ Stack git (CI/CD) │ │ │ │ [Gitea] ←──── OAuth ────→ [Woodpecker Server] │ -│ │ │ -│ ▼ │ -│ [Woodpecker Agent] │ -│ │ │ -│ ▼ │ +│ │ │ │ +│ │ webhook ▼ │ +│ ▼ [Woodpecker Agent] │ +│ [Herald] │ │ +│ (review IA) ▼ │ │ [Docker-in-Docker] │ │ (build containers) │ └──────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────┐ -│ Monitoring Stack │ +│ Stack observability │ │ │ -│ [Prometheus] ←─ scrape ─┬─ prometheus:9090 (self) │ -│ │ ├─ reverse_caddy:2019 (metrics) │ -│ │ └─ cadvisor:8080 (containers) │ -│ │ │ -│ └──→ [Perses] (visualisation via VPN) │ -└──────────────────────────────────────────────────────────────┘ - -┌──────────────────────────────────────────────────────────────┐ -│ Backup System │ -│ │ -│ [Backup Service] ──→ rclone/FTP ──→ [Serveur FTP distant] │ -│ │ │ │ -│ └─ Volumes Docker: └─ /backups/infra/│ -│ • giteadata Format: .tar.gz │ -│ • woodpeckerdata (désactivé) Rétention: 14j │ -│ • caddy configs (désactivé) Cron: 4h00 │ -│ • wireguard (désactivé) │ +│ [OTel Collector] ──┬─ hostmetrics (CPU/RAM/disk/net) │ +│ │ ├─ docker_stats (métriques containers) │ +│ │ ├─ prometheus scrape: │ +│ │ │ reverse_caddy:2019 │ +│ │ │ herald:9100 │ +│ │ │ alertmanager:9093 │ +│ │ │ blackbox_exporter:9115 │ +│ │ └─ OTLP (4318) │ +│ │ │ +│ ├── remote_write ──→ [Prometheus] ──→ [Perses] │ +│ └── OTLP ──────────→ [Tempo] │ +│ │ │ +│ [Prometheus] ── alertes ──→ [Alertmanager] ──→ [ntfy] │ └──────────────────────────────────────────────────────────────┘ ``` +### Stacks Docker Swarm + +| Stack | Fichier compose | Services | +|-------|-----------------|----------| +| `core` | `docker-compose.core.yml` | Caddy, WireGuard | +| `git` | `docker-compose.git.yml` | Gitea, Woodpecker (server + agent), Herald | +| `observability` | `docker-compose.observability.yml` | Prometheus, Perses, Tempo, Alertmanager, Blackbox, OTel Collector, proxy socket, ntfy | + ### Réseaux Docker Swarm | Réseau | Type | Services | |--------|------|----------| -| `reverse` | overlay | Caddy, Gitea, Woodpecker | -| `wireguard_network` | overlay | WireGuard, Perses | -| `prometheus_network` | overlay | Prometheus, Perses, cAdvisor, Caddy, Backup | +| `reverse_network` | overlay | Caddy, Gitea, Woodpecker (server + agent), Herald, ntfy | +| `wireguard_network` | overlay | WireGuard, Prometheus, Perses, Tempo | +| `prometheus_network` | overlay | Caddy, Herald, Prometheus, Perses, Tempo, Alertmanager, Blackbox, OTel Collector, docker-proxy-otel, ntfy | --- @@ -121,7 +145,7 @@ Cette infrastructure héberge l'ensemble des services nécessaires pour le déve - **Docker Configs** pour configurations versionnées ### Infrastructure as Code -- Configuration : `docker-compose.yml` +- Configuration : `docker-compose.core.yml` (Caddy, WireGuard), `docker-compose.git.yml` (Gitea, Woodpecker, Herald), `docker-compose.observability.yml` (Prometheus, Perses, Tempo, ntfy…) - Déploiement : `./deploy.sh` (génère timestamp pour versioning) - Contexte Docker distant : `prod` @@ -132,21 +156,21 @@ Cette infrastructure héberge l'ensemble des services nécessaires pour le déve - **VPN** : WireGuard pour services internes ### Storage -- **Volumes Docker** : giteadata, woodpeckerdata, reversecaddydata, reversecaddyconfig, backuptemp -- **Host mounts** : /home/user/wireguard-config, /var/run/docker.sock (CI/CD) +- **Volumes Docker** : `reversecaddydata`, `reversecaddyconfig` (core) · `giteadata`, `woodpeckerdata` (git) · `prometheusdata`, `tempodata`, `persesdata`, `alertmanagerdata`, `ntfydata` (observability) +- **Host mounts** : `/home/user/wireguard-config`, `/lib/modules` (WireGuard) · `/var/run/docker.sock` (Woodpecker agent, Herald, `docker-proxy-otel`) · `/` en lecture seule (OTel Collector) ### Monitoring -- **Métriques** : Prometheus avec 10s scrape interval +- **Collecte** : OTel Collector (hostmetrics + scrape Prometheus + OTLP) +- **Stockage métriques** : Prometheus (remote-write receiver activé) +- **Stockage traces** : Tempo (OTLP HTTP `:4318`, rétention 48 h) - **Dashboards** : Perses (accessible via VPN) -- **Container metrics** : cAdvisor -- **Proxy metrics** : Caddy admin API (:2019) +- **Container metrics** : receiver `docker_stats` de l'OTel Collector (labels Swarm `service_name` / `task_name`) +- **Proxy metrics** : Caddy admin API (`:2019`) +- **Probes externes** : blackbox_exporter (`http_2xx` sur les URLs publiques) +- **Alerting** : Prometheus → Alertmanager → ntfy (`http://ntfy:80/alerts`) ### Backups -- **Solution** : docker-volume-backup avec rclone -- **Fréquence** : Quotidien à 4h00 -- **Destination** : Serveur FTP distant -- **Rétention** : 14 jours -- **Format** : .tar.gz compressé +- ⚠️ **Aucun service de backup n'est déployé actuellement.** L'ancien service `docker-volume-backup` a été retiré (commit `041eb51`). Les sauvegardes sont à refaire manuellement ou à réintroduire. --- @@ -166,6 +190,13 @@ Cette infrastructure héberge l'ensemble des services nécessaires pour le déve - Limite : 1 workflow concurrent, CPU core 1 - Support multi-architectures +### Herald +- Agent IA de review de code, déclenché par webhooks Gitea +- Modèle via OpenRouter (`openai/gpt-5.6-luna-pro`) +- Sandbox d'exécution limitée à 32 itérations +- 5 jobs concurrents max, timeout Gitea 60 s / OpenRouter 600 s +- Métriques Prometheus exposées sur `:9100` + ### Caddy - HTTPS automatique avec Let's Encrypt - HTTP/3 (QUIC) support @@ -177,38 +208,44 @@ Cette infrastructure héberge l'ensemble des services nécessaires pour le déve - VPN moderne et rapide - Configuration : 1 peer (extensible) - Accès sécurisé aux services internes +- CoreDNS embarqué pour résoudre `perses.internal`, `prometheus.internal`, `tempo.internal` - Faible overhead ### Monitoring -- **Prometheus** : Collecte et stockage des métriques -- **Perses** : Visualisation moderne (alternative Grafana) -- **cAdvisor** : Métriques CPU, RAM, I/O des containers +- **OTel Collector** : hostmetrics (CPU, RAM, disque, réseau, load, process) + `docker_stats` (métriques containers) + scrape Prometheus + réception OTLP +- **Prometheus** : stockage des métriques, remote-write receiver +- **Tempo** : stockage des traces OTLP +- **Perses** : visualisation moderne (alternative Grafana) +- **blackbox_exporter** : probes HTTP sur les URLs publiques +- **Alertmanager** : routage des alertes vers ntfy - Scrape automatique toutes les 10 secondes -### Backups -- Sauvegarde automatique quotidienne -- Support FTP/SFTP via rclone -- Compression gzip -- Notifications optionnelles (Discord, Slack, Email) -- Rétention configurable +### Alerting +- Règles : `ServiceDown` (probe blackbox), `OtelCollectorDown`, `CaddyDown` +- Seuil : 1 minute +- Inhibition : `CaddyDown` supprime les `ServiceDown` (évite le bruit) +- Notification : webhook ntfy avec template `alertmanager`, `send_resolved: true` --- ## URLs et accès ### Services publics -- **Gitea** : https://gitea.qpismont.fr +- **Gitea** : https://gitea.qpismont.fr (alias https://git.qpismont.fr) - **Woodpecker** : https://woodpecker.qpismont.fr -- **Portfolio** : ~~https://www.qpismont.fr~~ (désactivé) +- **Portfolio** : https://www.qpismont.fr (`qpismont.fr` redirige vers `www`) +- **ntfy** : https://ntfy.qpismont.fr ### Services internes (VPN requis) -- **Perses** : http://perses:8080 (via WireGuard) -- **Prometheus** : http://prometheus:9090 (via WireGuard) +- **Perses** : http://perses.internal:8080 (via WireGuard/CoreDNS) +- **Prometheus** : http://prometheus.internal:9090 +- **Tempo** : http://tempo.internal:3200 - **Caddy Admin** : http://reverse_caddy:2019 (métriques) ### VPN - **Protocole** : WireGuard - **Port** : 51820/udp +- **Sous-réseau** : `10.13.13.0/24` - **Config** : `/home/user/wireguard-config/peer1/` --- @@ -221,12 +258,12 @@ Le déploiement se fait via un contexte Docker distant vers le serveur de produc ./deploy.sh ``` -Le script génère un timestamp pour versionner les configs et secrets, puis déploie le stack `core` sur le contexte `prod`. +Le script génère un timestamp pour versionner les configs et secrets, puis déploie les trois stacks (`core`, `git`, `observability`) sur le contexte `prod`. **Prérequis :** - Contexte Docker `prod` configuré -- Réseaux overlay créés (`reverse`, `wireguard_network`, `prometheus_network`) -- Secrets configurés dans `./secrets/` +- Réseaux overlay créés (`reverse_network`, `wireguard_network`, `prometheus_network`) +- Secrets configurés dans `./secrets/` (dossier ignoré par Git) --- @@ -234,156 +271,30 @@ Le script génère un timestamp pour versionner les configs et secrets, puis dé ### Secrets Docker -| Secret | Usage | -|--------|-------| -| `woodpecker_agent_secret` | Communication server/agent Woodpecker | -| `woodpecker_gitea_client` | OAuth client ID Gitea | -| `woodpecker_gitea_secret` | OAuth client secret Gitea | -| `backup_ftp_config` | Configuration rclone pour FTP | +| Secret | Fichier source | Usage | +|--------|----------------|-------| +| `woodpecker_agent_secret` | `./secrets/woodpecker_agent_secret` | Communication server/agent Woodpecker | +| `woodpecker_gitea_client` | `./secrets/woodpecker_gitea_client` | OAuth client ID Gitea | +| `woodpecker_gitea_secret` | `./secrets/woodpecker_gitea_secret` | OAuth client secret Gitea | +| `herald_gitea_token` | `./secrets/herald/herald_gitea_token` | Token API Gitea pour Herald | +| `herald_openrouter_token` | `./secrets/herald/herald_openrouter_token` | Clé API OpenRouter | +| `herald_gitea_header_secret` | `./secrets/herald/herald_gitea_header_secret` | Vérification signature webhook Gitea | +| `herald_sentry_dsn` | `./secrets/herald/herald_sentry_dsn` | DSN Sentry | ### Configs Docker -| Config | Fichier source | -|--------|----------------| -| `caddy_config` | `./Caddyfile` | -| `prometheus_config` | `./prometheus.yml` | +| Config | Fichier source | Stack | +|--------|----------------|-------| +| `caddy_config` | `./Caddyfile` | core | +| `caddy_portfolio_html` | `./portfolio/index.html` | core | +| `wireguard_coredns_config` | `./wireguard/CoreDns` | core | +| `prometheus_config` | `./prometheus/prometheus.yml` | observability | +| `prometheus_rules_config` | `./prometheus/alert.rules.yml` | observability | +| `alertmanager_config` | `./prometheus/alertmanager/alertmanager.yml` | observability | +| `blackbox_config` | `./blackbox/blackbox.yml` | observability | +| `otel_collector_config` | `./otel-collector/config.yaml` | observability | +| `tempo_config` | `./tempo/tempo.yml` | observability | -Les configs et secrets sont versionnés avec `${DATETIME}` pour forcer les mises à jour lors du déploiement. +Les configs et secrets sont versionnés avec `${DATETIME}` pour forcer les mises à jour lors du déploiement. Ils s'accumulent donc à chaque déploiement : voir la section [Nettoyage](#nettoyage). --- - -## Problèmes connus - -### ⚠️ Service my_cv désactivé -Le Caddyfile contient des routes vers `my_cv:80` mais le service n'existe plus dans docker-compose.yml (retiré dans commit f047317). - -**Impact :** Routes `qpismont.fr` et `www.qpismont.fr` ne fonctionnent pas. - -### ⚠️ Prometheus non-persistant -Prometheus n'a pas de volume Docker, les métriques sont perdues à chaque redémarrage du container. - -**Impact :** Pas d'historique des métriques sur le long terme. - -### ⚠️ Volumes backup partiellement désactivés -Seul `giteadata` est actuellement sauvegardé. Les autres volumes (woodpecker, caddy, wireguard) sont commentés dans docker-compose.yml. - -**Impact :** Perte de données possible en cas d'incident sur ces volumes. - ---- - -## Documentation - -### Fichiers de documentation - -- **[README.md](./README.md)** : Ce fichier - présentation générale -- **[ANALYSE.md](./ANALYSE.md)** : Analyse détaillée de l'infrastructure + recommandations d'amélioration -- **[BACKUP.md](./BACKUP.md)** : Documentation complète du système de backup (configuration, utilisation, restauration) - -### Documentation externe - -- [Docker Swarm](https://docs.docker.com/engine/swarm/) -- [Caddy](https://caddyserver.com/docs/) -- [Gitea](https://docs.gitea.io/) -- [Woodpecker CI](https://woodpecker-ci.org/docs/) -- [WireGuard](https://www.wireguard.com/) -- [Prometheus](https://prometheus.io/docs/) -- [Perses](https://perses.dev/docs/) - ---- - -## Maintenance - -### Routine - -- **Quotidien** : Backup automatique à 4h00 -- **Hebdomadaire** : Vérification logs et backups -- **Mensuel** : Mise à jour des images Docker -- **Trimestriel** : Test de restauration des backups - -### Monitoring - -```bash -# Status des services -docker --context prod ps - -# Logs d'un service -docker --context prod logs -f $(docker --context prod ps -q -f name=core_SERVICE) - -# Métriques système -docker --context prod stats -``` - -### Mises à jour - -Modifier les versions dans `docker-compose.yml` puis : - -```bash -./deploy.sh -``` - -Docker Swarm appliquera les changements de manière progressive. - ---- - -## Sécurité - -### Mesures en place - -✅ HTTPS automatique (Let's Encrypt) -✅ Secrets Docker (credentials chiffrés) -✅ Network isolation (3 réseaux séparés) -✅ VPN pour services internes (WireGuard) -✅ Resource limits sur CI/CD agent -✅ Backups automatisés quotidiens -✅ Non-root user pour Gitea (UID 1000) - -### Recommandations - -Voir [ANALYSE.md](./ANALYSE.md) pour la liste complète des améliorations de sécurité suggérées. - ---- - -## Historique - -### 2025-10-27 -- ✅ Upgrade vers Debian 13 (devcontainer) -- ✅ Update Woodpecker v3.11.0 -- ✅ Update Gitea v1.24.7 -- ✅ Ajout WireGuard VPN -- ✅ Ajout stack monitoring (Prometheus + Perses + cAdvisor) -- ✅ Ajout système de backup automatique - -### 2025-06-23 -- ✅ Retrait service my_cv (portfolio) -- ✅ Update images Woodpecker et Gitea - -### Antérieur -- Déploiement devcontainer Debian -- Upgrades réguliers des services -- Ajout Woodpecker CI -- Migration vers Docker Swarm - ---- - -## Statistiques - -- **Services actifs** : 8 -- **Réseaux overlay** : 3 -- **Volumes Docker** : 5 -- **Secrets Docker** : 4 -- **Configs Docker** : 2 -- **Ports exposés** : 4 (80, 443/tcp, 443/udp, 51820/udp) -- **Backup size** : ~50-500 MB (dépend des données Gitea) -- **Uptime target** : 99%+ - ---- - -## Licence et Auteur - -**Propriétaire** : qpismont -**Usage** : Personnel -**Repository** : https://gitea.qpismont.fr/qpismont/infra - ---- - -**Dernière mise à jour :** 27 octobre 2025 diff --git a/deploy.sh b/deploy.sh index c4ce3d2..ef284e5 100644 --- a/deploy.sh +++ b/deploy.sh @@ -1,4 +1,5 @@ #!/bin/bash DATETIME=$(date +%Y%m%d%H%M%S) docker --context prod stack deploy -c docker-compose.core.yml core --with-registry-auth +DATETIME=$(date +%Y%m%d%H%M%S) docker --context prod stack deploy -c docker-compose.git.yml git --with-registry-auth DATETIME=$(date +%Y%m%d%H%M%S) docker --context prod stack deploy -c docker-compose.observability.yml observability --with-registry-auth \ No newline at end of file diff --git a/docker-compose.core.yml b/docker-compose.core.yml index 3f882e5..8582ba8 100644 --- a/docker-compose.core.yml +++ b/docker-compose.core.yml @@ -19,81 +19,6 @@ services: - reverse_network - prometheus_network - woodpecker_server: - image: woodpeckerci/woodpecker-server:v3.19-alpine - volumes: - - woodpeckerdata:/var/lib/woodpecker/ - entrypoint: /bin/sh -c "export WOODPECKER_GITEA_CLIENT=$$(cat /run/secrets/woodpecker_gitea_client) && export WOODPECKER_GITEA_SECRET=$$(cat /run/secrets/woodpecker_gitea_secret) && export WOODPECKER_AGENT_SECRET=$$(cat /run/secrets/woodpecker_agent_secret) && /bin/woodpecker-server" - environment: - WOODPECKER_ADMIN: qpismont - WOODPECKER_HOST: https://woodpecker.qpismont.fr - WOODPECKER_GITEA: "true" - WOODPECKER_GITEA_URL: https://gitea.qpismont.fr - networks: - - reverse_network - secrets: - - woodpecker_agent_secret - - woodpecker_gitea_client - - woodpecker_gitea_secret - - woodpecker_agent: - image: woodpeckerci/woodpecker-agent:v3.19-alpine - volumes: - - /var/run/docker.sock:/var/run/docker.sock - entrypoint: /bin/sh -c "export WOODPECKER_AGENT_SECRET=$$(cat /run/secrets/woodpecker_agent_secret) && /bin/woodpecker-agent" - environment: - WOODPECKER_SERVER: woodpecker_server:9000 - WOODPECKER_MAX_WORKFLOWS: 1 - WOODPECKER_LIMIT_CPU_SET: 1 - networks: - - reverse_network - secrets: - - woodpecker_agent_secret - - gitea: - image: docker.gitea.com/gitea:28.2 - environment: - - USER_UID=1000 - - USER_GID=1000 - restart: always - volumes: - - giteadata:/data - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - networks: - - reverse_network - - herald: - image: tintounn/herald:1.2 - volumes: - - /var/run/docker.sock:/var/run/docker.sock - entrypoint: - - /bin/sh - - -c - - >- - export GITEA_TOKEN=$$(cat /run/secrets/herald_gitea_token) && - export OPEN_ROUTER_API_KEY=$$(cat /run/secrets/herald_openrouter_token) && - export WEBHOOK_SIG_HEADER_SECRET=$$(cat /run/secrets/herald_gitea_header_secret) && - export SENTRY_DSN=$$(cat /run/secrets/herald_sentry_dsn) && - /app/herald-server - networks: - - reverse_network - - prometheus_network - secrets: - - herald_gitea_token - - herald_openrouter_token - - herald_gitea_header_secret - - herald_sentry_dsn - environment: - HTTP_PORT: 3000 - BOT_MAX_CONCURRENT: 5 - GITEA_URL: http://gitea:3000 - GITEA_TIMEOUT: 60 - OPEN_ROUTER_MODEL: openai/gpt-5.6-luna-pro - OPEN_ROUTER_TIMEOUT: 600 - METRICS_BIND_ADDR: 0.0.0.0:9100 - SANDBOX_MAX_ITERATIONS: 32 - wireguard_server: image: linuxserver/wireguard cap_add: @@ -128,29 +53,6 @@ services: networks: - wireguard_network -secrets: - woodpecker_agent_secret: - name: woodpecker_agent_secret_${DATETIME} - file: ./secrets/woodpecker_agent_secret - woodpecker_gitea_secret: - name: woodpecker_gitea_secret_${DATETIME} - file: ./secrets/woodpecker_gitea_secret - woodpecker_gitea_client: - name: woodpecker_gitea_client_${DATETIME} - file: ./secrets/woodpecker_gitea_client - herald_gitea_token: - name: herald_gitea_token_${DATETIME} - file: ./secrets/herald/herald_gitea_token - herald_openrouter_token: - name: herald_openrouter_token_${DATETIME} - file: ./secrets/herald/herald_openrouter_token - herald_gitea_header_secret: - name: herald_gitea_header_secret_${DATETIME} - file: ./secrets/herald/herald_gitea_header_secret - herald_sentry_dsn: - name: herald_sentry_dsn_${DATETIME} - file: ./secrets/herald/herald_sentry_dsn - configs: caddy_config: name: caddy_config_${DATETIME} @@ -163,8 +65,6 @@ configs: file: ./portfolio/index.html volumes: - giteadata: - woodpeckerdata: reversecaddyconfig: reversecaddydata: diff --git a/docker-compose.git.yml b/docker-compose.git.yml new file mode 100644 index 0000000..30699e4 --- /dev/null +++ b/docker-compose.git.yml @@ -0,0 +1,110 @@ +version: "3" + +services: + gitea: + image: docker.gitea.com/gitea:28.2 + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always + volumes: + - giteadata:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + networks: + - reverse_network + + woodpecker_server: + image: woodpeckerci/woodpecker-server:v3.19-alpine + volumes: + - woodpeckerdata:/var/lib/woodpecker/ + entrypoint: /bin/sh -c "export WOODPECKER_GITEA_CLIENT=$$(cat /run/secrets/woodpecker_gitea_client) && export WOODPECKER_GITEA_SECRET=$$(cat /run/secrets/woodpecker_gitea_secret) && export WOODPECKER_AGENT_SECRET=$$(cat /run/secrets/woodpecker_agent_secret) && /bin/woodpecker-server" + environment: + WOODPECKER_ADMIN: qpismont + WOODPECKER_HOST: https://woodpecker.qpismont.fr + WOODPECKER_GITEA: "true" + WOODPECKER_GITEA_URL: https://gitea.qpismont.fr + networks: + - reverse_network + secrets: + - woodpecker_agent_secret + - woodpecker_gitea_client + - woodpecker_gitea_secret + + woodpecker_agent: + image: woodpeckerci/woodpecker-agent:v3.19-alpine + volumes: + - /var/run/docker.sock:/var/run/docker.sock + entrypoint: /bin/sh -c "export WOODPECKER_AGENT_SECRET=$$(cat /run/secrets/woodpecker_agent_secret) && /bin/woodpecker-agent" + environment: + WOODPECKER_SERVER: woodpecker_server:9000 + WOODPECKER_MAX_WORKFLOWS: 1 + WOODPECKER_LIMIT_CPU_SET: 1 + networks: + - reverse_network + secrets: + - woodpecker_agent_secret + + herald: + image: tintounn/herald:1.2 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + entrypoint: + - /bin/sh + - -c + - >- + export GITEA_TOKEN=$$(cat /run/secrets/herald_gitea_token) && + export OPEN_ROUTER_API_KEY=$$(cat /run/secrets/herald_openrouter_token) && + export WEBHOOK_SIG_HEADER_SECRET=$$(cat /run/secrets/herald_gitea_header_secret) && + export SENTRY_DSN=$$(cat /run/secrets/herald_sentry_dsn) && + /app/herald-server + networks: + - reverse_network + - prometheus_network + secrets: + - herald_gitea_token + - herald_openrouter_token + - herald_gitea_header_secret + - herald_sentry_dsn + environment: + HTTP_PORT: 3000 + BOT_MAX_CONCURRENT: 5 + GITEA_URL: http://gitea:3000 + GITEA_TIMEOUT: 60 + OPEN_ROUTER_MODEL: openai/gpt-5.6-luna-pro + OPEN_ROUTER_TIMEOUT: 600 + METRICS_BIND_ADDR: 0.0.0.0:9100 + SANDBOX_MAX_ITERATIONS: 32 + +secrets: + woodpecker_agent_secret: + name: woodpecker_agent_secret_${DATETIME} + file: ./secrets/woodpecker_agent_secret + woodpecker_gitea_secret: + name: woodpecker_gitea_secret_${DATETIME} + file: ./secrets/woodpecker_gitea_secret + woodpecker_gitea_client: + name: woodpecker_gitea_client_${DATETIME} + file: ./secrets/woodpecker_gitea_client + herald_gitea_token: + name: herald_gitea_token_${DATETIME} + file: ./secrets/herald/herald_gitea_token + herald_openrouter_token: + name: herald_openrouter_token_${DATETIME} + file: ./secrets/herald/herald_openrouter_token + herald_gitea_header_secret: + name: herald_gitea_header_secret_${DATETIME} + file: ./secrets/herald/herald_gitea_header_secret + herald_sentry_dsn: + name: herald_sentry_dsn_${DATETIME} + file: ./secrets/herald/herald_sentry_dsn + +volumes: + giteadata: + woodpeckerdata: + +networks: + reverse_network: + external: true + prometheus_network: + external: true diff --git a/docker-compose.observability.yml b/docker-compose.observability.yml index 416384b..eed623a 100644 --- a/docker-compose.observability.yml +++ b/docker-compose.observability.yml @@ -23,7 +23,7 @@ services: - wireguard_network blackbox_exporter: - image: prom/blackbox-exporter:v0.28.0 + image: prom/blackbox-exporter:v0.29.1 configs: - source: blackbox_config target: /etc/blackbox_exporter/config.yml @@ -52,8 +52,44 @@ services: - prometheus_network - reverse_network + docker-proxy-otel: + image: tecnativa/docker-socket-proxy:v0.5.0 + environment: + CONTAINERS: 1 + INFO: 1 + VERSION: 1 + PING: 1 + # docker_stats écoute /events pour suivre les conteneurs (sinon 403) + EVENTS: 1 + POST: 0 + EXEC: 0 + IMAGES: 0 + VOLUMES: 0 + NETWORKS: 0 + SECRETS: 0 + CONFIGS: 0 + SWARM: 0 + SERVICES: 0 + TASKS: 0 + NODES: 0 + SYSTEM: 0 + PLUGINS: 0 + SESSION: 0 + AUTH: 0 + BUILD: 0 + COMMIT: 0 + DISTRIBUTION: 0 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - prometheus_network + deploy: + resources: + limits: + memory: 64M + otel-collector: - image: otel/opentelemetry-collector-contrib:0.161.0 + image: otel/opentelemetry-collector-contrib:0.164.0 configs: - source: otel_collector_config target: /etc/otelcol-contrib/config.yaml @@ -66,12 +102,12 @@ services: deploy: resources: limits: - memory: 512M + memory: 768M networks: - prometheus_network prometheus: - image: prom/prometheus:v3.13.3 + image: prom/prometheus:v3.15.1 command: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/prometheus @@ -87,16 +123,6 @@ services: - prometheus_network - wireguard_network - cadvisor: - image: gcr.io/cadvisor/cadvisor:latest - volumes: - - /:/rootfs:ro - - /var/run:/var/run:rw - - /sys:/sys:ro - - /var/lib/docker/:/var/lib/docker:ro - networks: - - prometheus_network - configs: prometheus_config: name: prometheus_config_${DATETIME} diff --git a/otel-collector/config.yaml b/otel-collector/config.yaml index 14f6c7a..0d1b03b 100644 --- a/otel-collector/config.yaml +++ b/otel-collector/config.yaml @@ -14,6 +14,35 @@ receivers: network: load: processes: + docker_stats: + endpoint: tcp://docker-proxy-otel:2375 + collection_interval: 30s + timeout: 20s + api_version: "1.44" + container_labels_to_metric_labels: + com.docker.swarm.service.name: service_name + com.docker.swarm.task.name: task_name + metrics: + container.cpu.usage.total: + enabled: true + container.cpu.percent: + enabled: true + container.memory.usage.total: + enabled: true + container.memory.percent: + enabled: true + container.memory.usage.limit: + enabled: true + container.network.io.usage.rx_bytes: + enabled: true + container.network.io.usage.tx_bytes: + enabled: true + container.blockio.io_service_bytes_recursive: + enabled: true + container.pids.count: + enabled: true + container.uptime: + enabled: true prometheus: config: scrape_configs: @@ -21,10 +50,6 @@ receivers: scrape_interval: 10s static_configs: - targets: ['reverse_caddy:2019'] - - job_name: cadvisor - scrape_interval: 10s - static_configs: - - targets: ['cadvisor:8080'] - job_name: herald scrape_interval: 10s static_configs: @@ -64,6 +89,8 @@ processors: exporters: prometheusremotewrite: endpoint: http://prometheus:9090/api/v1/write + resource_to_telemetry_conversion: + enabled: true otlphttp/tempo: endpoint: http://tempo:4318 @@ -78,7 +105,7 @@ service: port: 8888 pipelines: metrics: - receivers: [otlp, prometheus, hostmetrics] + receivers: [otlp, prometheus, hostmetrics, docker_stats] processors: [memory_limiter, batch] exporters: [prometheusremotewrite] traces: diff --git a/portfolio/index.html b/portfolio/index.html index 47f7091..d942e0c 100644 --- a/portfolio/index.html +++ b/portfolio/index.html @@ -5,38 +5,63 @@