85 votes

Assignation de vhosts aux ports Docker

J'ai mis en place un DNS générique de façon à ce que toutes les requêtes web vers un domaine personnalisé (*.foo) soient redirigées vers l'adresse IP de l'hôte Docker. Si j'ai plusieurs conteneurs exécutant des instances Apache (ou Nginx), chaque conteneur mappe le port Apache (80) vers un port externe entrant.

Ce que j'aimerais faire, c'est effectuer une requête vers container-1.foo, qui est déjà mapée vers la bonne adresse IP (de l'hôte Docker) via mon serveur DNS personnalisé, mais rediriger la requête par défaut sur le port 80 vers le bon port externe Docker de sorte que l'instance Apache correcte du conteneur spécifié puisse répondre en fonction du domaine personnalisé. De même, container-2.foo redirigerait vers un deuxième conteneur apache, et ainsi de suite.

Existe-t-il une solution préconçue pour cela, est-il préférable de faire tourner un proxy Nginx sur l'hôte Docker, ou devrais-je écrire un proxy node.js avec la possibilité de gérer les conteneurs Docker (démarrer/arrêter/reconstruire via le web), ou...? Quelles options ai-je qui feraient de l'utilisation des conteneurs Docker quelque chose de plus naturel et non de jonglage avec des ports et des conteneurs superflus?

0 votes

J'ai aussi cette question - autant que je sache, exécuter chaque application dans un conteneur Docker puis faire le routage sur l'hôte en utilisant un serveur nginx (peut-être dans son propre conteneur) est la bonne manière de le faire. Je me demande si je devrais exécuter le serveur d'application de manière autonome (c'est-à-dire exposer un serveur php-fpm, puma, etc.) ou inclure une instance (inutile ?) de nginx également.

0 votes

Jetez un coup d'œil sur github.com/dotcloud/hipache, qui est un reverse-proxy configurable via redis.

82voto

Thomas Points 609

Cette réponse peut être un peu tardive, mais ce dont vous avez besoin est un proxy inverse automatique. J'ai utilisé deux solutions à cet effet :

  • jwilder/nginx-proxy
  • Traefik

Avec le temps, ma préférence va vers Traefik. Principalement parce qu'il est bien documenté et maintenu, et propose plus de fonctionnalités (équilibrage de charge avec différentes stratégies et priorités, vérifications de la santé, disjoncteurs automatiques, certificats SSL automatiques avec ACME/Let's Encrypt, ...).


Utilisation de jwilder/nginx-proxy

Lorsque vous exécutez un conteneur Docker image Docker nginx-proxy de Jason Wilder, vous obtenez un serveur nginx configuré en tant que proxy inverse pour vos autres conteneurs sans aucune configuration à maintenir.

Il vous suffit de lancer vos autres conteneurs avec la variable d'environnement VIRTUAL_HOST et nginx-proxy découvrira leur ip:port et mettra à jour la configuration nginx pour vous.

Disons que votre DNS est configuré de sorte que *.test.local est associé à l'adresse IP de votre hôte Docker, alors lancez simplement les conteneurs suivants pour obtenir une démonstration rapide en cours d'exécution :

# démarrer le proxy inverse
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

# démarrer un premier conteneur pour http://tutum.test.local
docker run -d -e "VIRTUAL_HOST=tutum.test.local" tutum/hello-world

# démarrer un deuxième conteneur pour http://deis.test.local
docker run -d -e "VIRTUAL_HOST=deis.test.local" deis/helloworld

Utilisation de Traefik

Lorsque vous exécutez un conteneur Traefik, vous obtenez un serveur proxy inverse configuré qui reconfigurera ses règles de transfert en fonction des étiquettes docker trouvées sur vos conteneurs.

Disons que votre DNS est configuré de sorte que *.test.local est associé à l'adresse IP de votre hôte Docker, alors lancez simplement les conteneurs suivants pour obtenir une démonstration rapide en cours d'exécution :

# démarrer le proxy inverse
docker run --rm -it -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:1.7 --docker

# démarrer un premier conteneur pour http://tutum.test.local
docker run -d -l "traefik.frontend.rule=Host:tutum.test.local" tutum/hello-world

# démarrer un deuxième conteneur pour http://deis.test.local
docker run -d -l "traefik.frontend.rule=Host:deis.test.local" deis/helloworld

0 votes

-v /var/run/docker.sock:/tmp/docker.sock Est-ce une solution dangereuse? Le conteneur proxy nginx a-t-il accès au démon hôte docker? Est-ce que cela pourrait représenter une faille de sécurité?

0 votes

Peut-être. Notez également que ne pas partager /var/run/docker.sock n'est pas non plus une garantie que l'hôte docker ne peut pas être exploité à partir d'un conteneur. La sécurité de Docker est un sujet à part entière.

0 votes

Y a-t-il des problèmes de sécurité connus ? Quand pouvez-vous atteindre l'hôte docker depuis le conteneur.

42voto

David Baird Points 520

Voici deux réponses possibles : (1) configurer les ports directement avec Docker et utiliser Nginx/Apache pour proxy les hôtes virtuels, ou (2) utiliser Dokku pour gérer les ports et les hôtes virtuels pour vous (c'est ainsi que j'ai appris à faire la Méthode 1).

Méthode 1a (attribuer directement les ports avec docker)

Étape 1 : Configurer nginx.conf ou Apache sur l'hôte, avec les affectations de numéros de port souhaitées. Ce serveur web, s'exécutant sur l'hôte, fera le proxying de l'hôte virtuel. Rien de spécial à ce sujet en ce qui concerne Docker - c'est un hébergement vhost normal. La partie spéciale vient ensuite, à l'Étape 2, pour faire en sorte que Docker utilise le bon numéro de port de l'hôte.

Étape 2 : Forcer les affectations de numéros de port dans Docker avec "-p" pour définir les mappings de ports de Docker, et "-e" pour définir des variables d'environnement personnalisées dans Docker, comme suit :

port=12345 # <-- le réglage de port vhost utilisé dans nginx/apache
IMAGE=myapps/container-1
id=$(docker run -d -p :$port -e PORT=$port $IMAGE)
# -p :$port va établir un mappage de 12345->12345 de l'extérieur de Docker à
# l'intérieur de Docker.
# Ensuite, l'application doit observer la variable d'environnement PORT
# pour se lancer sur ce port ; Cela est défini par -e PORT=$port.

# Extras supplémentaires :
echo $id # <-- l'ID en cours de votre conteneur
echo $id > /app/files/CONTAINER # <-- rappeler l'ID de Docker pour cette instance
docker ps # <-- vérifier que l'application s'exécute
docker logs $id # <-- regarder la sortie de l'instance en cours d'exécution
docker kill $id # <-- pour arrêter l'application

Méthode 1b Port d'application codé en dur

...si votre application utilise un port codé en dur, par exemple le port 5000 (c'est-à-dire ne peut pas être configuré via une variable d'environnement PORT, comme dans la Méthode 1a), alors il peut être codé en dur via Docker de cette manière :

publicPort=12345
id=$(docker run -d -p $publicPort:5000 $IMAGE)
# -p $publicPort:5000 va mapper le port 12345 à l'extérieur de Docker au port 5000 à l'intérieur
# de Docker. Par conséquent, nginx/apache doit être configuré pour le proxy vhost vers 12345,
# et l'application à l'intérieur de Docker doit écouter sur 5000.

Méthode 2 (laissez Dokku déterminer les ports)

Pour l'instant, une option assez bonne pour gérer les hôtes virtuels Docker est Dokku. Une option à venir pourrait être d'utiliser Flynn, mais à l'heure actuelle, Flynn en est à ses débuts et n'est pas tout à fait prêt. Par conséquent, nous optons pour Dokku pour le moment : après avoir suivi les instructions d'installation de Dokku, pour un seul domaine, activez les hôtes virtuels en créant le fichier "VHOST" :

echo votredomaine.com > /home/git/VHOST
# dans votre cas : echo foo > /home/git/VHOST

Maintenant, lorsque une application est poussée via SSH vers Dokku (consultez la documentation de Dokku pour savoir comment faire cela), Dokku examinera le fichier VHOST et pour l'application particulière poussée (disons que vous avez poussé "container-1"), il générera le fichier suivant :

/home/git/container-1/nginx.conf

Et il aura le contenu suivant :

upstream container-1 { server 127.0.0.1:49162; }
server {
  listen      80;
  server_name container-1.votredomaine.com;
  location    / {
    proxy_pass  http://container-1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

Lorsque le serveur est redémarré, Dokku veillera à ce que Docker démarre l'application avec le port mappé sur son port initialement déployé (49162 ici), plutôt que d'obtenir aléatoirement un autre port. Pour réaliser cette affectation déterministe, Dokku enregistre le port initialement attribué dans /home/git/container-1/PORT et au prochain démarrage, il définit l'environnement PORT sur cette valeur, et mappe également les affectations de ports de Docker pour être ce port à la fois du côté hôte et du côté application. Contrairement au premier lancement, où Dokku définira PORT=5000 et puis trouvera le port aléatoire que Dokku mappe côté VPS à 5000 côté application. C'est un peu compliqué (et pourrait même changer à l'avenir), mais ça fonctionne !

La manière dont VHOST fonctionne, en coulisses, est : en poussant une app via SSH, Dokku exécutera des hooks qui se trouvent dans /var/lib/dokku/plugins/nginx-vhosts. Ces hooks sont également situés dans le code source de Dokku ici et sont responsables d'écrire les fichiers nginx.conf avec les réglages vhost corrects. Si vous n'avez pas ce répertoire sous /var/lib/dokku, essayez d'exécuter dokku plugins-install.

3voto

ben schwartz Points 1027

Avec Docker, vous voulez que les adresses IP internes restent normales (par exemple 80) et comment connecter les ports aléatoires.

Une façon de les gérer, c'est avec un reverse proxy comme hipache. Pointez votre dns vers lui, et ensuite vous pouvez reconfigurer le proxy au fur et à mesure que vos conteneurs se lancent et s'arrêtent. Jetez un œil à http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/ pour voir comment cela pourrait fonctionner.

Si vous recherchez quelque chose de plus robuste, vous voudrez peut-être jeter un coup d'œil à la "découverte de services." (un aperçu de la découverte de services avec Docker : http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X