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 APIconteneur n'est lié à aucun autre, mais le
Appconteneur est lié à APIet Nginxest lié à la fois à APIet App.
Il en résulte des modifications apportées aux envvariables vars et aux /etc/hostsfichiers qui résident dans les conteneurs APIet App. Les résultats ressemblent à ceci:
/ etc / hosts
L'exécution cat /etc/hostsdans votre Nginxconteneur 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 envdans votre Nginxconteneur 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/hostsentrées de fichier et de envvariables 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 nginxdans votre Nginxconteneur.
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/hostsfichier qui a dockercréé, ou vous pouvez utiliser les ENVvars et exécuter un remplacement de chaîne (j'ai utilisé sed) sur votre nginx.confet tout autre fichier de configuration qui peut être dans votre /etc/nginx/sites-enableddossier 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/hostsoption 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/hostsoption de fichier réside dans la façon dont vous écrivez votre Dockerfilepour utiliser un script shell comme CMDargument, qui à son tour gère le remplacement de chaîne pour copier les valeurs IP ENVdans 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.conffichier 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.confet api.myapp.conf.
La magie se produit Nginx-Startup.shlà où nous utilisons sedpour faire le remplacement de chaîne sur l' APP_IPespace réservé que nous avons écrit dans le upstreambloc de nos fichiers api.myapp.confet 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, sedgère les options différemment, le -idrapeau en particulier. Sur Ubuntu, le -idrapeau gérera le remplacement «en place»; il ouvrira le fichier, changera le texte, puis «sauvegardera» le même fichier. Sous OSX, l' -iindicateur 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' -iindicateur.
GOTCHA
Pour utiliser ENV vars dans l'expression régulière qui sedutilise 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.shexécution du script, qui a utilisé sedpour changer la valeur APP_IPde la ENVvariable correspondante que nous avons fournie dans la sedcommande. Nous avons maintenant des fichiers de configuration dans notre /etc/nginx/sites-enabledrépertoire qui ont les adresses IP des ENVvariables que le docker a définies lors du démarrage du conteneur. Dans votre api.myapp.conffichier, vous verrez que le upstreambloc 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.comobtiendra 172.0.0.2 la première fois, mais ensuite 172.0.0.4 la prochaine fois. Mais Nginxaura déjà défini la première adresse IP dans ses fichiers de configuration, ou dans son /etc/hostsfichier, il ne pourra donc pas déterminer la nouvelle adresse IP pour api.myapp.com. La solution à cela est susceptible d'utiliser CoreOSet de son etcdservice qui, dans ma compréhension limitée, agit comme un partage ENVpour toutes les machines enregistrées dans le même CoreOScluster. C'est le prochain jouet avec lequel je vais jouer.
OPTION B: utiliser les /etc/hostsentré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/hostsentrée dans vos fichiers api.myapp.confet 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/hostsfichier comme ceci: 172.0.0.2 APIje 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 Balancerapprovisionnement 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.