Docker + Traefik: besoin d'avis extérieurs pour un besoin un peu spécifique

kortex
2022-05-25T18:21:42+02:00
Linux.général, traefik, docker

Sommaire

Contexte

Solution qui fonctionne mais qui ne me convient pas

Solution que j'aurais souhaité avoir

Test violent n°1 : un prefix dans l'URL

Test violent n°2 : une URL par conteneur

Désolé

Au secours

Bonjour à tous,

J'ai un besoin assez spécifique pour lequel je m'arrache les cheveux depuis quelques jours.

Contexte

En gros, j'ai X conteneurs différents :

conteneur1

conteneur2

conteneur3

etc

Chaque conteneur :

écoute sur le port 5000 en interne

est mappé sur un port unique à l'extérieur / côté hôte. Exemple:

conteneur1: 6000 -> 5000

conteneur2: 6001 -> 5000

conteneur3: 6002 -> 5000

démarre un serveur web qui écoute le même endpoint: /app

une requête sur le endpoint /app va exécuter du code: ce code est différent selon les conteneurs

Jusqu'à maintenant les requêtes sont faites ainsi par une interface web:

conteneur1: http://127.0.0.1:6000/app

conteneur2: http://127.0.0.1:6001/app

conteneur3: http://127.0.0.1:6002/app

Ce n'est sûrement pas la façon de faire la plus élégante qui soit mais ça fonctionne et ça a le mérite d'être super simple :-)

J'ai besoin de démarrer un autre daemon dans chaque conteneur + ce daemon écoutera sur un autre port interne : je sais ce n'est pas du tout la philosophie mais pour l'instant nous ne pouvons pas faire autrement :-)

Ce daemon c'est Jupyter Notebook. Par défaut il écoute sur le port 8888 et réponds à "/".
Mais son url de base est configurable: elle est configurée pour répondre à /jupyter-notebook (nous verrons après pourquoi).

Alors j'arrive à démarrer mes deux daemons en utilisant supervisor: pas de soucis
Maintenant j'ai cette topologie interne:

conteneur1:

port 5000: utilisé par le daemon 1 qui réponds à /app

port 8888: utilisé par Jupyter Notebook qui réponds à /jupyter-notebook

conteneur2:

port 5000: utilisé par le daemon 1 qui réponds à /app

port 8888: utilisé par Jupyter Notebook qui réponds à /jupyter-notebook

conteneur3:

port 5000: utilisé par le daemon 1 qui réponds à /app

port 8888: utilisé par Jupyter Notebook qui réponds à /jupyter-notebook

Problème: mon interface web qui interroge ces URL's:

conteneur1: http://127.0.0.1:6000/app

conteneur2: http://127.0.0.1:6001/app

conteneur3: http://127.0.0.1:6002/app

Doit maintenant être capable d'interroger 2 ports par conteneur : c'est assez difficile à changer (ça implique trop de chose) donc on m'a demandé de trouver une alternative.

L'alternative sur laquelle je travaille c'est d'intercaler un Traefik.

Solution qui fonctionne mais qui ne me convient pas

J'ai réussi à faire quelque chose qui fonctionne mais je n'aime pas trop l'idée…

J'ai créé une instance Traefik par conteneur et c'est Traefik qui map le port 600X et qui ensuite va communiquer soit avec le port 5000 soit avec le port 8888.

En résumé ça donne ceci:

combinaison Traefik1 + conteneur1:

Traefik écoute sur le port 6000

127.0.0.1:6000/app --> Traefik 1 --> :5000

127.0.0.1:6000/jupyter-notebook --> Traefik 1 --> :8888

combinaison Traefik2 + conteneur2:

Traefik écoute sur le port 6001

127.0.0.1:6001/app --> Traefik 2 --> :5000

127.0.0.1:6001/jupyter-notebook --> Traefik 2 --> :8888

combinaison Traefik3 + conteneur3:

Traefik écoute sur le port 6002

127.0.0.1:6002/app --> Traefik 3 --> :5000

127.0.0.1:6002/jupyter-notebook --> Traefik 3 --> :8888

Alors certes ça fonctionne mais :

ça demande de jouer avec une "contrainte" dans Traefik pour éviter que les configurations dynamiques ne remontent dans la mauvaise instance

ça fait démarrer plusieurs instances de Traefik pour pas grand chose

Solution que j'aurais souhaité avoir

J'aurais préféré avoir un Traefik commun à tous mes conteneurs.

Test violent n°1 : un prefix dans l'URL

J'ai pensé à ceci :
* Traefik en écoute sur le port 6000
* une "location" dans l'URL qui est le conteneur à joindre:
* 127.0.0.1:6000/conteneur1/app --> conteneur1:5000/app
* 127.0.0.1:6000/conteneur1/jupyter-notebook --> conteneur1:8888/jupyter-notebook
* 127.0.0.1:6000/conteneur2/app --> conteneur2:5000/app
* 127.0.0.1:6000/conteneur2/jupyter-notebook --> conteneur2:8888/jupyter-notebook
* 127.0.0.1:6000/conteneur3/app --> conteneur3:5000/app
* 127.0.0.1:6000/conteneur3/jupyter-notebook --> conteneur3:8888/jupyter-notebook
* utiliser un "stripprefix" pour supprimer le "/conteneur1" (sinon le backend final ne comprends pas la requête)

Ça fonctionne bien pour /app mais pas pour /jupyter-notebook qui a une facheuse tendance à faire une redirection sur "/jupyter-notebook"…

Test violent n°2 : une URL par conteneur

J'ai pensé à créer des labels de configuration comme ceci:

labels pour conteneur1:

si hôte est conteneur1.mydomain.com et si PathPrefix est /app alors conteneur1 port 5000

si hôte est conteneur1.mydomain.com et si PathPrefix est /jupyter-notebook alors conteneur1 port 8888

labels pour conteneur2:

si hôte est conteneur2.mydomain.com et si PathPrefix est /app alors conteneur2 port 5000

si hôte est conteneur2.mydomain.com et si PathPrefix est /jupyter-notebook alors conteneur2 port 8888

labels pour conteneur3:

si hôte est conteneur3.mydomain.com et si PathPrefix est /app alors conteneur2 port 5000

si hôte est conteneur3.mydomain.com et si PathPrefix est /jupyter-notebook alors conteneur2 port 8888

Problème : les conteneurs peuvent être créés / détruit X fois par jour donc il faudrait trouver une solution qui fait que l'URL fonctionne à tous les coups
J'avais pensé avoir une espèce de FQDN *.mydomain.com qui réponds toujours 127.0.0.1 pour arriver à ceci:

conteneur1.mydomain.com -> 127.0.0.1

conteneur2.mydomain.com -> 127.0.0.1

conteneur3.mydomain.com -> 127.0.0.1

Problème :

/etc/hosts ne permets pas l'utilisation de wildcard

j'ai testé dnsmasq mais ça pétillait pas mal avec SystemD Resolved :

si je désactive SystemD ResolveD la résolution côté hôte fonctionne

mais dans les conteneurs Docker non…

quand bien même je trouve à régler le problème de résolution dans Docker, j'ai des serveurs sur lesquels le réseau est bizarrement configuré : les serveurs DNS sont poussés par le DHCP sur lequel je n'ai pas la main donc ça devient vite un sac de nœuds…

Désolé

Désolé pour le pavé mais il n'était pas évident à expliquer en plus court :-)

Au secours

J'ai sûrement mal fait quelque chose à un moment car je suis fatigué donc désolé si j'ai loupé une évidence :)

Est-ce que quelqu'un aurait une autre idée svp ?
Ou un approfondissement d'un de mes tests à suggérer svp ?

Je vous remercie d'avance :)