La réponse de @ T0xicCode est correcte, mais j'ai pensé développer les détails car il m'a fallu environ 20 heures pour enfin mettre en place une solution fonctionnelle.
Si vous cherchez à 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, les étapes à suivre sont les suivantes:
Liez vos conteneurs
Lorsque vous utilisezdocker run
vos conteneurs, généralement en entrant un script shell dans User Data
, vous pouvez déclarer des liens vers tout autre conteneur en cours d' exécution . Cela signifie que vous devez démarrer vos conteneurs dans l'ordre et que seuls les derniers conteneurs peuvent être liés aux premiers. 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 API
conteneur n'est lié à aucun autre, mais le
App
conteneur est lié à API
et Nginx
est lié à la fois à API
et App
.
Il en résulte des modifications apportées aux env
variables vars et aux /etc/hosts
fichiers qui résident dans les conteneurs API
et App
. Les résultats ressemblent à ceci:
/ etc / hosts
L'exécution cat /etc/hosts
dans votre Nginx
conteneur 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
L'exécution env
dans votre Nginx
conteneur 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é la plupart des variables réelles, mais les valeurs ci-dessus sont les valeurs clés dont vous avez besoin pour transférer le trafic vers vos conteneurs.
Pour obtenir un shell pour exécuter les commandes ci-dessus dans un conteneur en cours d'exécution, utilisez ce qui suit:
sudo docker exec -i -t Nginx bash
Vous pouvez voir que vous disposez désormais à la fois d' /etc/hosts
entrées de fichier et de env
variables contenant l'adresse IP locale de l'un des conteneurs liés. 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 Nginx
conteneur.
Configurer Nginx
C'est là que ça devient un peu compliqué, et il y a quelques options. Vous pouvez choisir de configurer vos sites pour pointer vers une entrée dans le /etc/hosts
fichier qui a docker
créé, ou vous pouvez utiliser les ENV
vars et exécuter un remplacement de chaîne (j'ai utilisé sed
) sur votre nginx.conf
et tout autre fichier de configuration qui peut être dans votre /etc/nginx/sites-enabled
dossier pour insérer l'adresse IP valeurs.
OPTION A: Configurer Nginx à l'aide d'ENV Vars
C'est l'option que j'ai choisie car je ne pouvais pas faire fonctionner l'
/etc/hosts
option de fichier. Je vais essayer l'option B assez tôt et mettre à jour cet article avec les résultats.
La principale différence entre cette option et l'utilisation de l' /etc/hosts
option de fichier réside dans la façon dont vous écrivez votre Dockerfile
pour utiliser un script shell comme CMD
argument, qui à son tour gère le remplacement de chaîne pour copier les valeurs IP ENV
dans vos fichiers de configuration.
Voici l'ensemble des fichiers de configuration avec lesquels j'ai fini:
Dockerfile
FROM ubuntu:14.04
MAINTAINER Your Name <you@myapp.com>
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 de l'inclure daemon off;
dans votre nginx.conf
fichier 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 produit Nginx-Startup.sh
là où nous utilisons sed
pour faire le remplacement de chaîne sur l' APP_IP
espace réservé que nous avons écrit dans le upstream
bloc de nos fichiers api.myapp.conf
et app.myapp.conf
.
Cette question de ask.ubuntu.com l'explique très bien:
rechercher et remplacer du texte dans un fichier à l'aide de commandes
GOTCHA
Sous OSX, sed
gère les options différemment, le -i
drapeau en particulier. Sur Ubuntu, le -i
drapeau gérera le remplacement «en place»; il ouvrira le fichier, changera le texte, puis «sauvegardera» le même fichier. Sous OSX, l' -i
indicateur nécessite l'extension de fichier que vous souhaitez que le fichier résultant ait. Si vous travaillez avec un fichier sans extension, vous devez saisir «» comme valeur pour l' -i
indicateur.
GOTCHA
Pour utiliser ENV vars dans l'expression régulière qui sed
utilise pour trouver la chaîne que vous voulez remplacer, vous devez mettre la var entre guillemets. Ainsi, la syntaxe correcte, quoique d'aspect bancal, est celle ci-dessus.
Ainsi, docker a lancé notre conteneur et déclenché l' Nginx-Startup.sh
exécution du script, qui a utilisé sed
pour changer la valeur APP_IP
de la ENV
variable correspondante que nous avons fournie dans la sed
commande. Nous avons maintenant des fichiers de configuration dans notre /etc/nginx/sites-enabled
répertoire qui ont les adresses IP des ENV
variables que le docker a définies lors du démarrage du conteneur. Dans votre api.myapp.conf
fichier, vous verrez que le upstream
bloc a changé comme suit:
upstream api_upstream{
server 172.0.0.2:3000;
}
L'adresse IP que vous voyez peut être différente, mais j'ai remarqué que c'est généralement le cas 172.0.0.x
.
Vous devriez maintenant avoir tout routé correctement.
GOTCHA
Vous ne pouvez redémarrer / réexécuter aucun conteneur une fois que vous avez exécuté le lancement initial de l'instance. Docker fournit à chaque conteneur une nouvelle adresse IP lors du lancement et ne semble pas réutiliser celle qui était utilisée auparavant. Donc api.myapp.com
obtiendra 172.0.0.2 la première fois, mais ensuite 172.0.0.4 la prochaine fois. Mais Nginx
aura déjà défini la première adresse IP dans ses fichiers de configuration, ou dans son /etc/hosts
fichier, il ne pourra donc pas déterminer la nouvelle adresse IP pour api.myapp.com
. La solution à cela est susceptible d'utiliser CoreOS
et de son etcd
service qui, dans ma compréhension limitée, agit comme un partage ENV
pour toutes les machines enregistrées dans le même CoreOS
cluster. C'est le prochain jouet avec lequel je vais jouer.
OPTION B: utiliser les /etc/hosts
entrées de fichier
Cela devrait être le moyen le plus rapide et le plus simple de le faire, mais je n'ai pas pu le faire fonctionner. Apparemment, vous entrez simplement la valeur de l' /etc/hosts
entrée dans vos fichiers api.myapp.conf
et app.myapp.conf
, mais je n'ai pas pu faire fonctionner cette méthode.
MISE À JOUR:
Voir la réponse de @Wes Tod pour savoir comment faire fonctionner cette méthode.
Voici la tentative que j'ai faite api.myapp.conf
:
upstream api_upstream{
server API:3000;
}
Compte tenu du fait qu'il y a une entrée dans mon /etc/hosts
fichier comme ceci: 172.0.0.2 API
je pensais que cela extrairait simplement la valeur, mais cela ne semble pas l'être.
J'ai également eu quelques problèmes accessoires avec mon Elastic Load Balancer
approvisionnement de tous les AZ, c'est peut-être le problème lorsque j'ai essayé cette route. Au lieu de cela, j'ai dû apprendre à gérer le remplacement des chaînes sous Linux, donc c'était amusant. Je vais essayer dans un moment et voir comment ça se passe.