Administration dans un conteneur Docker (Dockerfile, exemples compose et nginx) ; arrêt propre sur SIGTERM

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mf2kATMtqVABHSYdxJMnim
This commit is contained in:
FabriceandClaude Opus 5.5 committed 2026-10-09 16:59:27 +00:00
1 parent 4852361ea6
commit 02473fafbf
6 files changed
+89 -8

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
.git
Scripts
tests
exemples
**/__pycache__
*.egg-info
build
dist
+24
View File
@@ -0,0 +1,24 @@
# Interface RTG en conteneur, derrière le nginx du site
# (README, « L'administration dans Docker »).
FROM python:3.12-slim
# ffmpeg (libx265, libx264), exiftool, fuseaux horaires
RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg libimage-exiftool-perl tzdata \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY pyproject.toml README.md ./
COPY rtg ./rtg
RUN pip install --no-cache-dir . && rtg verifier
# Mot de passe (acces.toml) : /config/rtg, à monter depuis le Mac.
# Le conteneur voit les disques du Mac sous /Volumes, aux mêmes chemins que
# le Mac : les sources notées dans les voyage.toml restent valables.
ENV XDG_CONFIG_HOME=/config TZ=Europe/Paris PYTHONUNBUFFERED=1 \
RTG_RACINE=/Volumes/CLEROADTRIPS/Road-Trips RTG_PREFIXE=/admin
EXPOSE 8765
# Aucun port publié : seul le nginx du site (même réseau Docker) le joint.
CMD exec rtg --racine "$RTG_RACINE" interface --proxy --prefixe "$RTG_PREFIXE" \
--ecoute 0.0.0.0 --sans-navigateur
+11
View File
@@ -181,6 +181,17 @@ Pour administrer le site depuis son adresse publique (bouton « Connexion » en
```
4. Dans l'interface, Réglages → « Administration depuis le site » : adresse `/admin/`. Après « Refaire l'accueil », le bouton « Connexion » apparaît sur la page d'accueil.
### L'administration dans Docker
Plutôt que de laisser `rtg interface` ouvert dans un Terminal, on peut le faire tourner dans un conteneur, à côté du nginx du site : il démarre avec Docker et redémarre tout seul. Le `Dockerfile` est à la racine de RoadTripsGenerator (Python, ffmpeg, exiftool).
1. Définir le mot de passe sur le Mac, une fois : `rtg mot-de-passe`. Le conteneur lit le même fichier.
2. Ajouter le service `rtg` au `docker-compose.yml` du site : voir `exemples/docker-compose.yml`. Le conteneur voit `/Volumes` aux mêmes chemins que le Mac : la clé, le disque des rushs… Les sources notées dans les `voyage.toml` restent donc valables.
3. Dans `nginx.conf`, faire pointer `/admin/` vers ce conteneur : voir `exemples/nginx-admin.conf`. Le site reste en ligne même si le conteneur RTG est arrêté.
4. `docker compose up -d --build`.
Après une mise à jour de RTG : `docker compose up -d --build rtg`. Un disque branché après le démarrage du conteneur peut demander `docker compose restart rtg`. L'encodage utilise les processeurs attribués à Docker (réglages de Docker Desktop, « Resources ») ; l'encodeur matériel VideoToolbox du Mac n'est pas disponible dans le conteneur.
Le bouton n'est qu'un lien : la protection est celle de l'interface (mot de passe, blocage après plusieurs essais faux, cookie de session limité à `/admin/`, envoyé seulement en HTTPS).
Tout ce que fait l'interface s'écrit dans `site.toml` et les `voyage.toml`. On peut toujours utiliser les commandes ci-dessous ou modifier ces fichiers à la main. Une réécriture par l'interface conserve les valeurs mais pas les commentaires.
+29
View File
@@ -0,0 +1,29 @@
# docker-compose.yml du site, avec l'administration RTG dans son propre conteneur.
# Après une mise à jour de RTG : docker compose up -d --build rtg
services:
roadtrip:
image: nginx:alpine
restart: unless-stopped
networks:
- ouaibe_network
volumes:
- /Volumes/CLEROADTRIPS/Road-Trips:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
labels:
- traefik.enable=true
- traefik.docker.network=ouaibe_network
- traefik.http.routers.ouaibe_roadtrip.rule=Host(`roadtrip.ouaibe.fr`) || Host(`roadtrips.ouaibe.fr`)
- traefik.http.routers.ouaibe_roadtrip.entrypoints=websecure
rtg:
build: /Volumes/CLEROADTRIPS/RoadTripsGenerator
restart: unless-stopped
networks:
- ouaibe_network
volumes:
- /Volumes:/Volumes # la clé, le LaCie… aux mêmes chemins que sur le Mac
- ${HOME}/.config/rtg:/config/rtg # le mot de passe défini avec « rtg mot-de-passe »
networks:
ouaibe_network:
external: true
+8 -6
View File
@@ -1,15 +1,17 @@
# Bloc à ajouter dans nginx.conf, à l'intérieur de « server { … } », quand le
# site est servi par un conteneur nginx derrière Traefik (Traefik → nginx → RTG).
# RTG tourne sur le Mac : rtg interface --proxy --prefixe /admin
#
# Dans docker-compose.yml, sous le service nginx, ajouter aussi :
# extra_hosts:
# - "host.docker.internal:host-gateway"
# « ^~ » : sinon une règle du type « location ~* \.(js|css|png)$ » déjà
# présente dans nginx.conf prendrait les fichiers de l'interface pour ceux du site.
location ^~ /admin/ {
proxy_pass http://host.docker.internal:8765;
# RTG dans le conteneur « rtg » (exemples/docker-compose.yml). Passer par
# une variable laisse nginx démarrer même si ce conteneur est arrêté.
resolver 127.0.0.11 valid=30s;
set $rtg http://rtg:8765;
proxy_pass $rtg;
# RTG lancé à la main sur le Mac à la place : remplacer les trois lignes
# ci-dessus par « proxy_pass http://host.docker.internal:8765; ».
proxy_set_header Host $host;
# Traefik a déjà noté l'adresse du visiteur et le https : on les transmet tels quels.
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
+9 -2
View File
@@ -17,12 +17,13 @@ Sécurité (voir aussi securite.py) :
"""
import io
import json
import ssl
import mimetypes
import os
import platform
import re
import shutil
import signal
import ssl
import string
import threading
import webbrowser
@@ -466,7 +467,8 @@ class Application:
raccourcis = [("Dossier personnel", os.path.expanduser("~")), ("Site", self.racine)]
if r.q("v"):
raccourcis.append(("Ce voyage", os.path.join(self.racine, r.q("v"))))
if platform.system() == "Darwin" and os.path.isdir("/Volumes"):
# /Volumes : disques du Mac, y compris vus depuis le conteneur Docker.
if os.path.isdir("/Volumes"):
raccourcis += [(d, os.path.join("/Volumes", d)) for d in sorted(os.listdir("/Volumes"))
if not d.startswith(".")]
elif platform.system() == "Windows":
@@ -908,6 +910,11 @@ def lancer(racine, port=8765, ouvrir=True, distant=False, certificat=None, cle=N
print(" (Ctrl+C pour arrêter)")
if ouvrir:
threading.Timer(0.5, lambda: webbrowser.open(url)).start()
# « docker stop » envoie SIGTERM : on s'arrête aussitôt, comme sur Ctrl+C.
def sur_sigterm(*_):
raise KeyboardInterrupt
signal.signal(signal.SIGTERM, sur_sigterm)
try:
serveur.serve_forever()
except KeyboardInterrupt: