Nous sommes le 16 juillet 2015 et les choses ont encore changé. J'ai découvert ce conteneur automagique à partir de Jason Wilder :
https://github.com/jwilder/nginx-proxy
et le problème est résolu aussi longtemps qu'il faut jusqu'à _docker run
_ le conteneur. . C'est maintenant la solution que j'utilise pour résoudre ce problème.
Nous sommes en juillet 2015 et les choses ont radicalement changé en ce qui concerne la mise en réseau des conteneurs Docker. Il existe maintenant de nombreuses offres différentes qui résolvent ce problème (de différentes manières).
Vous devriez utiliser cet article pour acquérir une compréhension de base de l’approche
docker --link
de la découverte de service, qui est aussi élémentaire que possible, fonctionne très bien et nécessite en fait moins de danse de fantaisie que la plupart des autres solutions. Il est limité en ce sens qu'il est assez difficile de mettre en réseau des conteneurs sur des hôtes distincts dans un cluster donné. Les conteneurs ne peuvent pas être redémarrés une fois en réseau, mais offrent un moyen rapide et relativement simple de mettre en réseau des conteneurs sur le même hôte. C'est un bon moyen d'avoir une idée de ce que le logiciel que vous utiliserez probablement pour résoudre ce problème est en train de fonctionner sous le capot.En outre, vous voudrez probablement également jeter un œil à la nouvelle version de Docker
network
, celle d'Hashicorpconsul
, Weaveworksweave
, de Jeff Lindsayprogrium/consul
_ & _gliderlabs/registrator
, et celle de GoogleKubernetes
.Il existe également les offres CoreOS qui utilisent
etcd
,fleet
etflannel
.Et si vous voulez vraiment organiser une fête, vous pouvez créer un cluster à exécuter
Mesosphere
, ouDeis
, ouFlynn
.Si vous débutez dans le réseautage (comme moi), vous devriez alors sortir vos lunettes de lecture, pop "Peignez le ciel avec des étoiles - Le meilleur d’Enya" sur le Wi-Hi-Fi, et craquez une bière - il faudra un certain temps avant que vous compreniez vraiment ce que vous essayez de faire. Astuce: vous essayez d'implémenter un _
Service Discovery Layer
_ dans votre _Cluster Control Plane
_. C'est une très bonne façon de passer un samedi soir.C'est très amusant, mais j'aurais bien aimé prendre le temps de mieux comprendre le réseautage en général avant de plonger directement. J'ai finalement trouvé quelques messages des dieux bienveillants de Digital Ocean Tutorial:
Introduction to Networking Terminology
etUnderstanding ... Networking
. Je suggère de les lire quelques fois avant de plonger.S'amuser!
Je n'arrive pas à saisir le mappage de port pour les conteneurs Docker
. Spécifiquement, comment transmettre les requêtes de Nginx à un autre conteneur, en écoutant sur un autre port, sur le même serveur.
J'ai un fichier Docker pour un conteneur Nginx comme ceci:
_FROM ubuntu:14.04
MAINTAINER Me <[email protected]>
RUN apt-get update && apt-get install -y htop git nginx
ADD sites-enabled/api.myapp.com /etc/nginx/sites-enabled/api.myapp.com
ADD sites-enabled/app.myapp.com /etc/nginx/sites-enabled/app.myapp.com
ADD nginx.conf /etc/nginx/nginx.conf
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80 443
CMD ["service", "nginx", "start"]
_
Ensuite, le fichier de configuration _api.myapp.com
_ se présente comme suit:
_upstream api_upstream{
server 0.0.0.0:3333;
}
server {
listen 80;
server_name api.myapp.com;
return 301 https://api.myapp.com/$request_uri;
}
server {
listen 443;
server_name api.mypp.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $Host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_pass http://api_upstream;
}
}
_
Et puis un autre pour _app.myapp.com
_ également.
Et puis je cours:
_Sudo docker run -p 80:80 -p 443:443 -d --name Nginx myusername/nginx
_
Et tout se passe bien, mais les demandes ne sont pas transmises aux autres conteneurs/ports. Et quand je ssh dans le conteneur Nginx et inspecte les journaux, je ne vois aucune erreur.
De l'aide?
La réponse de @ T0xicCode est correcte, mais je pensais développer davantage les détails, car il m'a fallu environ 20 heures pour enfin mettre en œuvre une solution opérationnelle.
Si vous souhaitez exécuter Nginx dans son propre conteneur et l'utiliser comme proxy inverse pour équilibrer la charge de plusieurs applications sur la même instance de serveur, procédez comme suit:
Liez vos conteneurs
Lorsque vous _docker run
_ vos conteneurs, généralement en entrant un script Shell dans _User Data
_, vous pouvez déclarer des liens vers n’importe quel autre conteneur en cours d’exécution . Cela signifie que vous devez démarrer vos conteneurs dans l'ordre et seuls ces derniers conteneurs peuvent être liés aux anciens. Ainsi:
_#!/bin/bash
Sudo docker run -p 3000:3000 --name API mydockerhub/api
Sudo docker run -p 3001:3001 --link API:API --name App mydockerhub/app
Sudo docker run -p 80:80 -p 443:443 --link API:API --link App:App --name Nginx mydockerhub/nginx
_
Ainsi, dans cet exemple, le conteneur API
n'est lié à aucun autre, mais le conteneur App
est lié à API
et Nginx
est lié à la fois à API
et à App
.
Il en résulte des modifications apportées aux fichiers env
et aux fichiers _/etc/hosts
_ qui résident dans les conteneurs API
et App
. Les résultats ressemblent à ceci:
/ etc/hosts
Lancer _cat /etc/hosts
_ dans votre conteneur Nginx
produira les éléments suivants:
_172.17.0.5 0fd9a40ab5ec
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 App
172.17.0.2 API
_
ENV Vars
Exécuter env
dans votre conteneur Nginx
produira les éléments suivants:
_API_PORT=tcp://172.17.0.2:3000
API_PORT_3000_TCP_PROTO=tcp
API_PORT_3000_TCP_PORT=3000
API_PORT_3000_TCP_ADDR=172.17.0.2
APP_PORT=tcp://172.17.0.3:3001
APP_PORT_3001_TCP_PROTO=tcp
APP_PORT_3001_TCP_PORT=3001
APP_PORT_3001_TCP_ADDR=172.17.0.3
_
J'ai tronqué un grand nombre de vars réels, mais les valeurs ci-dessus sont la clé dont vous avez besoin pour proxy le trafic sur vos conteneurs.
Pour obtenir un shell pour exécuter les commandes ci-dessus dans un conteneur en cours d'exécution, utilisez les éléments suivants:
_Sudo docker exec -i -t Nginx bash
_
Vous pouvez constater que vous avez maintenant les deux entrées de fichier _/etc/hosts
_ et les variables env
qui contiennent l'adresse IP locale de tous les conteneurs liés. Pour autant que je sache, c'est tout ce qui se passe lorsque vous exécutez des conteneurs avec des options de lien déclarées. Mais vous pouvez maintenant utiliser ces informations pour configurer nginx
dans votre conteneur Nginx
.
Configuration de Nginx
C’est là que les choses se compliquent un peu et qu’il ya plusieurs options. Vous pouvez choisir de configurer vos sites pour qu'ils pointent vers une entrée du fichier _/etc/hosts
_ créée par docker
, ou vous pouvez utiliser les variables ENV
et exécuter une chaîne de remplacement (j'ai utilisé sed
) sur votre _nginx.conf
_. d’autres fichiers de configuration susceptibles d’être dans votre dossier _/etc/nginx/sites-enabled
_ pour insérer les valeurs IP.
OPTION A: Configurer Nginx avec ENV Vars
C'est l'option que j'ai choisie car je ne pouvais pas utiliser l'option de fichier _
/etc/hosts
_ pour fonctionner. Je vais essayer l'option B assez tôt et mettre à jour ce post avec tous les résultats.
La principale différence entre cette option et l'utilisation de l'option de fichier _/etc/hosts
_ réside dans la manière dont vous écrivez votre Dockerfile
pour utiliser un script Shell comme argument CMD
, qui à son tour gère le remplacement de la chaîne pour copier les valeurs IP de ENV
dans votre fichier de configuration. (s).
Voici l'ensemble des fichiers de configuration que j'ai obtenus:
Dockerfile
_FROM ubuntu:14.04
MAINTAINER Your Name <[email protected]>
RUN apt-get update && apt-get install -y nano htop git nginx
ADD nginx.conf /etc/nginx/nginx.conf
ADD api.myapp.conf /etc/nginx/sites-enabled/api.myapp.conf
ADD app.myapp.conf /etc/nginx/sites-enabled/app.myapp.conf
ADD Nginx-Startup.sh /etc/nginx/Nginx-Startup.sh
EXPOSE 80 443
CMD ["/bin/bash","/etc/nginx/Nginx-Startup.sh"]
_
nginx.conf
_daemon off;
user www-data;
pid /var/run/nginx.pid;
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 33;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/xml text/css application/x-javascript application/json;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# Virtual Host Configs
include /etc/nginx/sites-enabled/*;
# Error Page Config
#error_page 403 404 500 502 /srv/Splash;
}
_
REMARQUE: Il est important d'inclure _
daemon off;
_ dans votre fichier _nginx.conf
_ pour vous assurer que votre conteneur ne se ferme pas immédiatement après son lancement.
api.myapp.conf
_upstream api_upstream{
server APP_IP:3000;
}
server {
listen 80;
server_name api.myapp.com;
return 301 https://api.myapp.com/$request_uri;
}
server {
listen 443;
server_name api.myapp.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $Host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_pass http://api_upstream;
}
}
_
Nginx-Startup.sh
_#!/bin/bash
sed -i 's/APP_IP/'"$API_PORT_3000_TCP_ADDR"'/g' /etc/nginx/sites-enabled/api.myapp.com
sed -i 's/APP_IP/'"$APP_PORT_3001_TCP_ADDR"'/g' /etc/nginx/sites-enabled/app.myapp.com
service nginx start
_
Je vous laisse le soin de faire vos devoirs sur la plupart des contenus de _nginx.conf
_ et _api.myapp.conf
_.
La magie se passe dans _Nginx-Startup.sh
_ où nous utilisons sed
pour remplacer les chaînes dans l'espace réservé _APP_IP
_ que nous avons écrit dans le bloc upstream
de nos fichiers _api.myapp.conf
_ et _app.myapp.conf
_.
Cette question ask.ubuntu.com l'explique très bien: Rechercher et remplacer du texte dans un fichier à l'aide de commandes
GOTCHA Sous OSX,
sed
traite les options différemment, l'indicateur _-i
_ de manière spécifique. Sur Ubuntu, le drapeau _-i
_ gérera le remplacement "en place"; il ouvrira le fichier, changera le texte, puis "sauvegardera" le même fichier. Sur OSX, l'indicateur _-i
_ requiert l'extension de fichier que vous souhaitez que le fichier résultant ait. Si vous travaillez avec un fichier sans extension, vous devez entrer "" comme valeur pour l'indicateur _-i
_.GOTCHA Pour utiliser les variables ENV dans les expressions rationnelles utilisées par
sed
pour rechercher la chaîne que vous souhaitez remplacer, vous devez placer la variable var entre guillemets. Donc, la syntaxe correcte, quoique stupide, est la suivante.
Docker a donc lancé notre conteneur et déclenché l'exécution du script _Nginx-Startup.sh
_, qui a utilisé sed
pour remplacer la valeur _APP_IP
_ par la variable ENV
correspondante fournie dans la commande sed
. Nous avons maintenant des fichiers de configuration dans notre répertoire _/etc/nginx/sites-enabled
_ qui ont les adresses IP des vars ENV
que ce docker a définies lors du démarrage du conteneur. Dans votre fichier _api.myapp.conf
_, vous verrez que le bloc upstream
a été remplacé par le texte suivant:
_upstream api_upstream{
server 172.0.0.2:3000;
}
_
L'adresse IP que vous voyez peut être différente, mais j'ai remarqué qu'il s'agit généralement de _172.0.0.x
_.
Vous devriez maintenant avoir tout le routage approprié.
GOTCHA Vous ne pouvez pas relancer/réexécuter les conteneurs une fois que vous avez lancé le lancement initial de l'instance. Docker attribue une nouvelle adresse IP à chaque conteneur lors de son lancement et ne semble pas réutiliser celles déjà utilisées auparavant. Donc _
api.myapp.com
_ obtiendra 172.0.0.2 la première fois, puis 172.0.0.4 la prochaine fois. MaisNginx
aura déjà défini la première adresse IP dans ses fichiers de configuration, ou dans son fichier _/etc/hosts
_, de sorte qu'il ne sera pas en mesure de déterminer la nouvelle adresse IP pour _api.myapp.com
_. La solution à ce problème est susceptible d'utiliserCoreOS
et son serviceetcd
qui, selon ma compréhension limitée, agit comme unENV
partagé pour toutes les machines inscrites dans le même clusterCoreOS
. Ceci est le prochain jouet que je vais jouer avec la mise en place.
OPTION B: Utiliser _/etc/hosts
_ Entrées de fichier
Ceci devrait être le moyen le plus rapide et le plus simple de le faire, mais je ne pouvais pas le faire fonctionner. Apparemment, vous venez d'entrer la valeur de l'entrée _/etc/hosts
_ dans vos fichiers _api.myapp.conf
_ et _app.myapp.conf
_, mais cette méthode n'a pas fonctionné.
UPDATE: Voir réponse de @ Wes Tod pour obtenir des instructions sur la manière de faire fonctionner cette méthode.
Voici la tentative que j'ai faite dans _api.myapp.conf
_:
_upstream api_upstream{
server API:3000;
}
_
Considérant qu'il y a une entrée dans mon fichier _/etc/hosts
_ comme ceci: _172.0.0.2 API
_ J'ai pensé que cela attirerait simplement la valeur, mais cela ne semble pas être le cas.
J'ai également eu quelques problèmes auxiliaires liés à mon source _Elastic Load Balancer
_ auprès de tous les AZ, de sorte que le problème peut avoir été rencontré lorsque j'ai essayé cette voie. Au lieu de cela, j'ai dû apprendre à gérer le remplacement de chaînes dans Linux, donc c'était amusant. Je vais essayer cela dans un moment et voir comment ça se passe.
J'ai essayé d'utiliser le populaire proxy inverse de Jason Wilder, qui fonctionne comme par magie pour tout le monde, et j'ai appris que cela ne fonctionnait pas pour tout le monde (c'est-à-dire: moi). Et je suis tout nouveau chez NGINX, et je n’ai pas aimé que je ne comprenne pas les technologies que j’essayais d’utiliser.
Je voulais ajouter mes 2 centimes, car la discussion ci-dessus concernant linking
conteneurs est maintenant dépassée car il s'agit d'une fonctionnalité obsolète. Alors, voici une explication sur la façon de le faire en utilisant networks
. Cette réponse est un exemple complet de configuration de nginx en tant que proxy inverse sur un site Web paginé de manière statique à l'aide de Docker Compose
et de la configuration de nginx.
Ajoutez les services qui doivent communiquer entre eux sur un réseau prédéfini. Pour une discussion étape par étape sur les réseaux Docker, j’ai appris certaines choses ici: https://technologyconversations.com/2016/04/25/docker-networking-and-dns-the-good-the- mauvais-et-le-laid /
Tout d’abord, nous avons besoin d’un réseau sur lequel tous vos services backend peuvent parler. J'ai appelé le mien web
mais cela peut être ce que vous voulez.
docker network create web
Nous allons simplement faire une application de site Web simple. Le site Web est une simple page index.html servie par un conteneur nginx. Le contenu est un volume monté sur l'hôte sous un dossier content
DockerFile:
FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf
default.conf
server {
listen 80;
server_name localhost;
location / {
root /var/www/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
docker-compose.yml
version: "2"
networks:
mynetwork:
external:
name: web
services:
nginx:
container_name: sample-site
build: .
expose:
- "80"
volumes:
- "./content/:/var/www/html/"
networks:
default: {}
mynetwork:
aliases:
- sample-site
Notez que nous n’avons plus besoin de mappage de port ici. Nous exposons simplement le port 80. Ceci est pratique pour éviter les collisions de ports.
Lancez ce site avec
docker-compose up -d
Quelques vérifications amusantes concernant les mappages DNS pour votre conteneur:
docker exec -it sample-site bash
ping sample-site
Ce ping devrait fonctionner dans votre conteneur.
Proxy inverse Nginx:
Dockerfile
FROM nginx
RUN rm /etc/nginx/conf.d/*
Nous réinitialisons toute la configuration de l'hôte virtuel, car nous allons la personnaliser.
docker-compose.yml
version: "2"
networks:
mynetwork:
external:
name: web
services:
nginx:
container_name: nginx-proxy
build: .
ports:
- "80:80"
- "443:443"
volumes:
- ./conf.d/:/etc/nginx/conf.d/:ro
- ./sites/:/var/www/
networks:
default: {}
mynetwork:
aliases:
- nginx-proxy
Lancez le proxy en utilisant notre fidèle
docker-compose up -d
En supposant qu'il n'y ait pas de problème, deux conteneurs en cours d'exécution peuvent se parler en utilisant leurs noms. Testons-le.
docker exec -it nginx-proxy bash
ping sample-site
ping nginx-proxy
Le dernier détail est de configurer le fichier d'hébergement virtuel afin que le proxy puisse diriger le trafic en fonction de la façon dont vous souhaitez configurer votre correspondance:
sample-site.conf pour notre configuration d'hébergement virtuel:
server {
listen 80;
listen [::]:80;
server_name my.domain.com;
location / {
proxy_pass http://sample-site;
}
}
Selon la configuration du proxy, vous aurez besoin de ce fichier stocké dans votre dossier local conf.d
que nous avons monté via la déclaration volumes
dans le fichier docker-compose
.
Dernier point mais non le moindre, dites à nginx de recharger sa configuration.
docker exec nginx-proxy service nginx reload
Cette séquence d'étapes est l'aboutissement de nombreuses heures de douleur à la tête alors que je luttais contre l'erreur toujours douloureuse 502 Bad Gateway et que j'apprenais nginx pour la première fois, car la majeure partie de mon expérience était avec Apache.
Cette réponse montre comment supprimer l'erreur 502 Bad Gateway résultant de l'impossibilité pour les conteneurs de communiquer entre eux.
J'espère que cette réponse permettra à quelqu'un d'économiser des heures de douleur, car il était très difficile de comprendre les contenants les uns avec les autres pour une raison quelconque, même si c'était ce que je pensais être un cas d'utilisation évident. Mais là encore, je suis idiot. Et s'il vous plaît laissez-moi savoir comment je peux améliorer cette approche.
En utilisant docker links , vous pouvez lier le conteneur en amont au conteneur nginx. Une fonctionnalité supplémentaire est que docker gère le fichier Host, ce qui signifie que vous pourrez faire référence au conteneur lié en utilisant un nom plutôt que l'adresse IP potentiellement aléatoire.
"Option B" d'AJB peut fonctionner en utilisant l'image de base Ubuntu et en configurant vous-même nginx. (Cela n'a pas fonctionné lorsque j'ai utilisé l'image Nginx de Docker Hub.)
Voici le fichier Docker que j'ai utilisé:
FROM ubuntu
RUN apt-get update && apt-get install -y nginx
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
RUN rm -rf /etc/nginx/sites-enabled/default
EXPOSE 80 443
COPY conf/mysite.com /etc/nginx/sites-enabled/mysite.com
CMD ["nginx", "-g", "daemon off;"]
Mon config nginx (alias: conf/mysite.com):
server {
listen 80 default;
server_name mysite.com;
location / {
proxy_pass http://website;
}
}
upstream website {
server website:3000;
}
Et enfin, comment je commence mes conteneurs:
$ docker run -dP --name website website
$ docker run -dP --name nginx --link website:website nginx
Cela m’a permis de me lancer et de fonctionner de sorte que mon nginx pointe l’amont vers le deuxième conteneur docker qui expose le port 3000.
La réponse de @ gdbj est une excellente explication et la réponse la plus récente. Voici cependant une approche plus simple.
Donc, si vous souhaitez rediriger tout le trafic de nginx écoutant _80
_ vers un autre conteneur exposant _8080
_, la configuration minimale peut être aussi petite que:
nginx.conf:
_server {
listen 80;
location / {
proxy_pass http://client:8080; # this one here
proxy_redirect off;
}
}
_
docker-compose.yml
_version: "2"
services:
entrypoint:
image: some-image-with-nginx
ports:
- "80:80"
links:
- client # will use this one here
client:
image: some-image-with-api
ports:
- "8080:8080"
_
Je viens de trouver un article de Anand Mani Sankar qui montre un moyen simple d’utiliser le proxy en amont de nginx avec docker composer.
Fondamentalement, il faut configurer la liaison d’instance et les ports dans le fichier docker-compose et mettre à jour le fichier en amont dans nginx.conf en conséquence.