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:
1 parent
4852361ea6
commit
02473fafbf
6 files changed
+89
-8
No files matched your search
@@ -0,0 +1,8 @@
|
|||||||
|
.git
|
||||||
|
Scripts
|
||||||
|
tests
|
||||||
|
exemples
|
||||||
|
**/__pycache__
|
||||||
|
*.egg-info
|
||||||
|
build
|
||||||
|
dist
|
||||||
+24
@@ -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
|
||||||
@@ -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.
|
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).
|
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.
|
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.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
# Bloc à ajouter dans nginx.conf, à l'intérieur de « server { … } », quand le
|
# 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).
|
# 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à
|
# « ^~ » : 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.
|
# présente dans nginx.conf prendrait les fichiers de l'interface pour ceux du site.
|
||||||
location ^~ /admin/ {
|
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;
|
proxy_set_header Host $host;
|
||||||
# Traefik a déjà noté l'adresse du visiteur et le https : on les transmet tels quels.
|
# 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;
|
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ Sécurité (voir aussi securite.py) :
|
|||||||
"""
|
"""
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import ssl
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import signal
|
||||||
|
import ssl
|
||||||
import string
|
import string
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
import webbrowser
|
||||||
@@ -466,7 +467,8 @@ class Application:
|
|||||||
raccourcis = [("Dossier personnel", os.path.expanduser("~")), ("Site", self.racine)]
|
raccourcis = [("Dossier personnel", os.path.expanduser("~")), ("Site", self.racine)]
|
||||||
if r.q("v"):
|
if r.q("v"):
|
||||||
raccourcis.append(("Ce voyage", os.path.join(self.racine, 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"))
|
raccourcis += [(d, os.path.join("/Volumes", d)) for d in sorted(os.listdir("/Volumes"))
|
||||||
if not d.startswith(".")]
|
if not d.startswith(".")]
|
||||||
elif platform.system() == "Windows":
|
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)")
|
print(" (Ctrl+C pour arrêter)")
|
||||||
if ouvrir:
|
if ouvrir:
|
||||||
threading.Timer(0.5, lambda: webbrowser.open(url)).start()
|
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:
|
try:
|
||||||
serveur.serve_forever()
|
serveur.serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
Reference in new issue
Block a user