feat: Add Docker image update system (TrueNAS Scale inspired)
- Implement UpdateService for image version checking and atomic updates - Add DockerComposeManager for centralized docker-compose management - Create 12 docker-compose references in /home/innotex/Docker - Add 13 new API endpoints (6 for images, 7 for compose management) - Add comprehensive documentation and examples
This commit is contained in:
474
DOCKER_UPDATE_SYSTEM.md
Normal file
474
DOCKER_UPDATE_SYSTEM.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# Docker Image Update System - InnotexBoard
|
||||
|
||||
## 📌 Vue d'ensemble
|
||||
|
||||
Le système de mise à jour Docker d'InnotexBoard est **inspiré de TrueNAS Scale** et fournit:
|
||||
- ✅ Vérification automatique des mises à jour d'images
|
||||
- ✅ Téléchargement (pull) des nouvelles images
|
||||
- ✅ Mise à jour in-place des conteneurs
|
||||
- ✅ Nettoyage automatique des images orphelines
|
||||
- ✅ Gestion centralisée des docker-compose
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
InnotexBoard
|
||||
├── Backend API (FastAPI)
|
||||
│ ├── update_service.py # Service de mise à jour des images
|
||||
│ ├── compose_manager.py # Manager des docker-compose
|
||||
│ ├── endpoints/docker.py # API endpoints pour Docker
|
||||
│ └── endpoints/compose.py # API endpoints pour Docker Compose
|
||||
│
|
||||
├── Frontend (Vue.js)
|
||||
│ └── Components
|
||||
│ ├── ImageUpdates.vue # Gestion des mises à jour
|
||||
│ └── ComposeManager.vue # Gestion des docker-compose
|
||||
│
|
||||
└── Docker References
|
||||
└── /home/innotex/Docker/
|
||||
├── docker-compose.*.yml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 🔄 Workflow de Mise à Jour (Inspiré de TrueNAS Scale)
|
||||
|
||||
### 1. Détection des Mises à Jour
|
||||
```
|
||||
Client → GET /api/v1/docker/images/check-all-updates
|
||||
→ Check Docker Registry V2 API
|
||||
→ Compare versions (sémantique)
|
||||
→ Return list of available updates
|
||||
```
|
||||
|
||||
### 2. Téléchargement des Images
|
||||
```
|
||||
Client → POST /api/v1/docker/images/pull
|
||||
→ docker pull {image}:{tag}
|
||||
→ Store locally
|
||||
```
|
||||
|
||||
### 3. Mise à Jour Atomique du Conteneur
|
||||
```
|
||||
Client → POST /api/v1/docker/containers/{id}/update-image
|
||||
↓
|
||||
1. Stop container
|
||||
2. Pull new image
|
||||
3. Remove old container
|
||||
4. Create new container with new image
|
||||
5. Start new container
|
||||
↓
|
||||
Rollback-safe (old image retained until prune)
|
||||
```
|
||||
|
||||
### 4. Nettoyage
|
||||
```
|
||||
Client → POST /api/v1/docker/images/prune
|
||||
→ Remove dangling images
|
||||
→ Free up disk space
|
||||
```
|
||||
|
||||
## 📡 API Endpoints
|
||||
|
||||
### Images Management
|
||||
|
||||
#### Lister toutes les images locales
|
||||
```http
|
||||
GET /api/v1/docker/images
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"image": "portainer/portainer-ce",
|
||||
"tag": "latest",
|
||||
"image_id": "abc123",
|
||||
"created": "2024-01-16T10:30:00Z",
|
||||
"size": "123.45 MB",
|
||||
"containers_using": ["portainer"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Vérifier les mises à jour d'une image
|
||||
```http
|
||||
GET /api/v1/docker/images/check-update/{image_name}
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"image": "portainer/portainer-ce:latest",
|
||||
"current_tag": "latest",
|
||||
"latest_tag": "2.19.3",
|
||||
"has_update": true,
|
||||
"registry": "docker.io"
|
||||
}
|
||||
```
|
||||
|
||||
#### Vérifier toutes les mises à jour
|
||||
```http
|
||||
GET /api/v1/docker/images/check-all-updates
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"total_containers": 5,
|
||||
"containers_with_updates": 2,
|
||||
"updates": [
|
||||
{
|
||||
"container": "portainer",
|
||||
"update": {
|
||||
"image": "portainer/portainer-ce:latest",
|
||||
"current_tag": "latest",
|
||||
"latest_tag": "2.19.3",
|
||||
"has_update": true,
|
||||
"registry": "docker.io"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Télécharger une image (Pull)
|
||||
```http
|
||||
POST /api/v1/docker/images/pull
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
Body:
|
||||
{
|
||||
"image": "portainer/portainer-ce",
|
||||
"tag": "latest"
|
||||
}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Image portainer/portainer-ce:latest téléchargée avec succès"
|
||||
}
|
||||
```
|
||||
|
||||
#### Mettre à jour l'image d'un conteneur
|
||||
```http
|
||||
POST /api/v1/docker/containers/{container_id}/update-image
|
||||
Authorization: Bearer {token}
|
||||
Content-Type: application/json
|
||||
|
||||
Body:
|
||||
{
|
||||
"new_image": "portainer/portainer-ce",
|
||||
"new_tag": "latest"
|
||||
}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"success": true,
|
||||
"message": "Conteneur portainer mis à jour avec succès",
|
||||
"old_image": "portainer/portainer-ce:2.19.0",
|
||||
"new_image": "portainer/portainer-ce:latest"
|
||||
}
|
||||
```
|
||||
|
||||
#### Nettoyer les images inutilisées
|
||||
```http
|
||||
POST /api/v1/docker/images/prune
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Query Parameters:
|
||||
- dangling_only: boolean (default: true)
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"success": true,
|
||||
"deleted_images": 5,
|
||||
"space_freed_mb": "234.56",
|
||||
"details": [...]
|
||||
}
|
||||
```
|
||||
|
||||
### Docker Compose Management
|
||||
|
||||
#### Lister tous les docker-compose disponibles
|
||||
```http
|
||||
GET /api/v1/docker/compose/list
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
[
|
||||
{
|
||||
"name": "portainer",
|
||||
"file": "docker-compose.portainer.yml",
|
||||
"path": "/home/innotex/Docker/docker-compose.portainer.yml",
|
||||
"exists": true
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
#### Vérifier l'état d'un docker-compose
|
||||
```http
|
||||
GET /api/v1/docker/compose/{compose_name}/status
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"file": "docker-compose.portainer.yml",
|
||||
"containers": [
|
||||
{
|
||||
"ID": "abc123",
|
||||
"Name": "portainer",
|
||||
"State": "running",
|
||||
"Status": "Up 2 hours"
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### Démarrer un docker-compose
|
||||
```http
|
||||
POST /api/v1/docker/compose/{compose_name}/start
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Services démarrés pour docker-compose.portainer.yml"
|
||||
}
|
||||
```
|
||||
|
||||
#### Arrêter un docker-compose
|
||||
```http
|
||||
POST /api/v1/docker/compose/{compose_name}/stop
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Services arrêtés pour docker-compose.portainer.yml"
|
||||
}
|
||||
```
|
||||
|
||||
#### Arrêter et supprimer (down)
|
||||
```http
|
||||
POST /api/v1/docker/compose/{compose_name}/down
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Services arrêtés et supprimés pour docker-compose.portainer.yml"
|
||||
}
|
||||
```
|
||||
|
||||
#### Redémarrer un docker-compose
|
||||
```http
|
||||
POST /api/v1/docker/compose/{compose_name}/restart
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Services redémarrés pour docker-compose.portainer.yml"
|
||||
}
|
||||
```
|
||||
|
||||
#### Télécharger les images (Pull) d'un docker-compose
|
||||
```http
|
||||
POST /api/v1/docker/compose/{compose_name}/pull
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Images téléchargées pour docker-compose.portainer.yml"
|
||||
}
|
||||
```
|
||||
|
||||
#### Récupérer les logs
|
||||
```http
|
||||
GET /api/v1/docker/compose/{compose_name}/logs
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Query Parameters:
|
||||
- tail: integer (default: 100)
|
||||
|
||||
Response 200:
|
||||
{
|
||||
"status": "success",
|
||||
"file": "docker-compose.portainer.yml",
|
||||
"logs": "..."
|
||||
}
|
||||
```
|
||||
|
||||
## 📂 Structure des Fichiers
|
||||
|
||||
### Backend
|
||||
```
|
||||
backend/app/services/
|
||||
├── update_service.py # Service de mise à jour des images
|
||||
├── compose_manager.py # Manager des docker-compose
|
||||
└── docker_service.py # Service Docker existant
|
||||
|
||||
backend/app/api/endpoints/
|
||||
├── docker.py # Endpoints Docker (mis à jour)
|
||||
└── compose.py # Endpoints Docker Compose (nouveau)
|
||||
```
|
||||
|
||||
### Frontend (À implémenter)
|
||||
```
|
||||
frontend/src/
|
||||
├── views/
|
||||
│ ├── ImagesView.vue # Gestion des images
|
||||
│ └── UpdatesView.vue # Gestion des mises à jour
|
||||
│
|
||||
└── components/
|
||||
├── ImageList.vue
|
||||
├── UpdateChecker.vue
|
||||
├── ComposeManager.vue
|
||||
└── ComposeLogs.vue
|
||||
```
|
||||
|
||||
## 🐳 Docker Compose References
|
||||
|
||||
### Localisation
|
||||
`/home/innotex/Docker/`
|
||||
|
||||
### Applications Disponibles
|
||||
- **portainer** - Gestion Docker UI
|
||||
- **sonarr** - Gestionnaire de séries TV
|
||||
- **radarr** - Gestionnaire de films
|
||||
- **qbittorrent** - Client torrent
|
||||
- **jellyfin** - Serveur média open-source
|
||||
- **plex** - Serveur média premium
|
||||
- **nextcloud** - Cloud self-hosted
|
||||
- **nginx** - Serveur web / proxy
|
||||
- **pihole** - DNS ad-blocker
|
||||
- **homeassistant** - Domotique
|
||||
- **watchtower** - Mise à jour automatique
|
||||
- **monitoring** - Prometheus + Grafana
|
||||
|
||||
## 🔑 Labels personnalisés (TrueNAS Scale Style)
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
# Identifiant unique
|
||||
com.innotexboard.app: "app-name"
|
||||
|
||||
# Catégorie fonctionnelle
|
||||
com.innotexboard.category: "Media|Network|Cloud|Management|..."
|
||||
|
||||
# Description lisible
|
||||
com.innotexboard.description: "Description"
|
||||
|
||||
# Version actuelle
|
||||
com.innotexboard.version: "version"
|
||||
|
||||
# Activer/désactiver les mises à jour auto
|
||||
com.innotexboard.update-enabled: "true"
|
||||
|
||||
# URL d'accès
|
||||
com.innotexboard.url: "http://localhost:port"
|
||||
```
|
||||
|
||||
## 🚀 Utilisation Rapide
|
||||
|
||||
### Via cURL
|
||||
|
||||
```bash
|
||||
# Vérifier les mises à jour disponibles
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8000/api/v1/docker/images/check-all-updates
|
||||
|
||||
# Lancer un service
|
||||
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8000/api/v1/docker/compose/portainer/start
|
||||
|
||||
# Vérifier le statut
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8000/api/v1/docker/compose/portainer/status
|
||||
|
||||
# Récupérer les logs
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8000/api/v1/docker/compose/portainer/logs?tail=50
|
||||
|
||||
# Mettre à jour une image
|
||||
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"new_image":"portainer/portainer-ce","new_tag":"latest"}' \
|
||||
http://localhost:8000/api/v1/docker/containers/{container_id}/update-image
|
||||
|
||||
# Nettoyer les images orphelines
|
||||
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8000/api/v1/docker/images/prune
|
||||
```
|
||||
|
||||
## 📋 Checklist de Déploiement
|
||||
|
||||
- [ ] Backend: Services `update_service.py` et `compose_manager.py` créés
|
||||
- [ ] Backend: Endpoints Docker mis à jour
|
||||
- [ ] Backend: Endpoints Compose créés
|
||||
- [ ] Backend: Routes mises à jour
|
||||
- [ ] Docker: `/home/innotex/Docker` créé avec 11 docker-compose de référence
|
||||
- [ ] Docker: Labels de versioning ajoutés
|
||||
- [ ] Frontend: UI pour images (À implémenter)
|
||||
- [ ] Frontend: UI pour mises à jour (À implémenter)
|
||||
- [ ] Frontend: UI pour docker-compose (À implémenter)
|
||||
- [ ] Documentation: README créé
|
||||
- [ ] Tests: API testée
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### "Docker n'est pas accessible"
|
||||
```bash
|
||||
# Vérifier que Docker est accessible
|
||||
docker ps
|
||||
|
||||
# Vérifier les permissions du socket
|
||||
ls -la /var/run/docker.sock
|
||||
|
||||
# Ajouter l'utilisateur au groupe docker
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
### "Timeout lors de la mise à jour"
|
||||
```bash
|
||||
# Les timeouts peuvent survenir sur les connexions lentes
|
||||
# Augmenter le timeout dans update_service.py
|
||||
# ou tirer directement l'image:
|
||||
docker pull portainer/portainer-ce:latest
|
||||
```
|
||||
|
||||
### "Erreur: Impossible de supprimer le conteneur"
|
||||
```bash
|
||||
# Le conteneur est peut-être verrouillé
|
||||
# Forcer avec:
|
||||
docker rm -f container_name
|
||||
```
|
||||
|
||||
## 📚 Ressources
|
||||
|
||||
- [Docker Registry V2 API](https://docs.docker.com/registry/spec/api/)
|
||||
- [Docker Compose CLI](https://docs.docker.com/compose/reference/)
|
||||
- [TrueNAS Scale Documentation](https://www.truenas.com/docs/scale/)
|
||||
- [Portainer Docs](https://docs.portainer.io/)
|
||||
|
||||
## 📝 Notes d'Implémentation
|
||||
|
||||
### Points Forts
|
||||
✅ Architecture similaire à TrueNAS Scale
|
||||
✅ Support du versionning sémantique
|
||||
✅ API centralisée pour Docker et docker-compose
|
||||
✅ Gestion des labels pour identification
|
||||
✅ Nettoyage automatique des images
|
||||
|
||||
### Améliorations Futures
|
||||
🔜 Interface web complète (frontend)
|
||||
🔜 Support des webhooks Docker
|
||||
🔜 Notifications de mise à jour
|
||||
🔜 Historique des mises à jour
|
||||
🔜 Rollback automatique en cas d'erreur
|
||||
🔜 Mise à jour programmée (cron)
|
||||
🔜 Support des registries privés
|
||||
Reference in New Issue
Block a user