La respuesta de @ T0xicCode es correcta, pero pensé que ampliaría los detalles, ya que en realidad me tomó alrededor de 20 horas implementar finalmente una solución funcional.
Si está buscando ejecutar Nginx en su propio contenedor y usarlo como un proxy inverso para equilibrar la carga de varias aplicaciones en la misma instancia de servidor, los pasos que debe seguir son los siguientes:
Vincula tus contenedores
Cuando utiliza docker runsus contenedores, generalmente ingresando un script de shell User Data, puede declarar enlaces a cualquier otro contenedor en ejecución . Esto significa que debe iniciar sus contenedores en orden y solo los últimos contenedores pueden vincularse a los primeros. Al igual que:
#!/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
Entonces, en este ejemplo, el APIcontenedor no está vinculado a ningún otro, pero el
Appcontenedor está vinculado APIy Nginxestá vinculado a ambos APIy App.
El resultado de esto son cambios en las envvars y los /etc/hostsarchivos que residen dentro de los contenedores APIy App. Los resultados se ven así:
/ etc / hosts
Ejecutar cat /etc/hostsdentro de su Nginxcontenedor producirá lo siguiente:
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
Ejecutar envdentro de su Nginxcontenedor producirá lo siguiente:
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
He truncado muchas de las variables reales, pero los anteriores son los valores clave que necesita para el tráfico proxy a sus contenedores.
Para obtener un shell para ejecutar los comandos anteriores dentro de un contenedor en ejecución, use lo siguiente:
sudo docker exec -i -t Nginx bash
Puede ver que ahora tiene /etc/hostsentradas de archivo y envvariables que contienen la dirección IP local para cualquiera de los contenedores que estaban vinculados. Por lo que puedo decir, esto es todo lo que sucede cuando ejecuta contenedores con opciones de enlace declaradas. Pero ahora puede usar esta información para configurar nginxdentro de su Nginxcontenedor.
Configurando Nginx
Aquí es donde se pone un poco complicado y hay un par de opciones. Puede elegir configurar sus sitios para que apunten a una entrada en el /etc/hostsarchivo que dockercreó, o puede utilizar las ENVvars y ejecutar un reemplazo de cadena (yo usé sed) en su nginx.confy cualquier otro archivo conf que pueda estar en su /etc/nginx/sites-enabledcarpeta para insertar la IP valores.
OPCIÓN A: Configurar Nginx usando ENV Vars
Esta es la opción que elegí porque no pude hacer que la
/etc/hostsopción de archivo funcionara. Pronto intentaré la Opción B y actualizaré esta publicación con cualquier hallazgo.
La diferencia clave entre esta opción y el uso de la /etc/hostsopción de archivo es cómo escribe su Dockerfilepara usar un script de shell como CMDargumento, que a su vez maneja el reemplazo de la cadena para copiar los valores de IP ENVa sus archivos conf.
Aquí está el conjunto de archivos de configuración con los que terminé:
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;
}
NOTA: Es importante incluirlo daemon off;en su nginx.confarchivo para asegurarse de que su contenedor no salga inmediatamente después del lanzamiento.
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
Dejaré que usted haga su tarea sobre la mayoría de los contenidos de nginx.confy api.myapp.conf.
La magia ocurre Nginx-Startup.shcuando usamos sedpara hacer el reemplazo de cadenas en el APP_IPmarcador de posición que hemos escrito en el upstreambloque de nuestros archivos api.myapp.confy app.myapp.conf.
Esta pregunta de ask.ubuntu.com lo explica muy bien: busque
y reemplace texto dentro de un archivo usando comandos
GOTCHA
En OSX, sedmaneja las opciones de manera diferente, -iespecíficamente la bandera. En Ubuntu, la -ibandera manejará el reemplazo 'en su lugar'; abrirá el archivo, cambiará el texto y luego 'guardará' el mismo archivo. En OSX, la -ibandera requiere la extensión de archivo que le gustaría que tuviera el archivo resultante. Si está trabajando con un archivo que no tiene extensión, debe ingresar "" como el valor de la -ibandera.
GOTCHA
Para usar ENV vars dentro de la expresión regular que sedusa para encontrar la cadena que desea reemplazar, debe envolver la var entre comillas dobles. Entonces, la sintaxis correcta, aunque de aspecto extraño, es la anterior.
Entonces, Docker ha lanzado nuestro contenedor y ha activado la Nginx-Startup.shsecuencia de comandos para que se ejecute, que ha utilizado sedpara cambiar el valor APP_IPa la ENVvariable correspondiente que proporcionamos en el sedcomando. Ahora tenemos archivos conf dentro de nuestro /etc/nginx/sites-enableddirectorio que tienen las direcciones IP de las ENVvars que Docker configuró al iniciar el contenedor. Dentro de su api.myapp.confarchivo, verá que el upstreambloque ha cambiado a esto:
upstream api_upstream{
server 172.0.0.2:3000;
}
La dirección IP que ve puede ser diferente, pero he notado que normalmente lo es 172.0.0.x.
Ahora debería tener todo enrutado correctamente.
GOTCHA
No puede reiniciar / volver a ejecutar ningún contenedor una vez que haya ejecutado el lanzamiento inicial de la instancia. Docker proporciona a cada contenedor una nueva IP al iniciarse y no parece reutilizar ninguna de las que se usó antes. Entonces api.myapp.comobtendrá 172.0.0.2 la primera vez, pero luego obtendrá 172.0.0.4 la próxima vez. Pero Nginxya habrá configurado la primera IP en sus archivos conf, o en su /etc/hostsarchivo, por lo que no podrá determinar la nueva IP para api.myapp.com. Es probable que se utilice la solución a esto CoreOSy su etcdservicio que, según mi entendimiento limitado, actúa como compartido ENVpara todas las máquinas registradas en el mismo CoreOSclúster. Este es el próximo juguete con el que voy a jugar.
OPCIÓN B: Usar /etc/hostsentradas de archivo
Esta debería ser la forma más rápida y fácil de hacer esto, pero no pude hacer que funcione. Aparentemente, solo /etc/hostsingresó el valor de la entrada en sus archivos api.myapp.confy app.myapp.conf, pero no pude hacer que este método funcione.
ACTUALIZACIÓN:
consulte la respuesta de @Wes Tod para obtener instrucciones sobre cómo hacer que este método funcione.
Aquí está el intento que hice en api.myapp.conf:
upstream api_upstream{
server API:3000;
}
Teniendo en cuenta que hay una entrada en mi /etc/hostsarchivo como esa: 172.0.0.2 APIpensé que solo obtendría el valor, pero no parece serlo.
También tuve un par de problemas auxiliares con mi Elastic Load Balancerabastecimiento de todas las AZ, por lo que ese pudo haber sido el problema cuando probé esta ruta. En su lugar, tuve que aprender a manejar la sustitución de cadenas en Linux, así que fue divertido. Lo intentaré en un momento y veré cómo funciona.