redireccionar puerto inverso funciona configurar como carga cache balanceo balanceador nginx docker

inverso - ¿Cómo configurar la asignación de puertos Docker para usar Nginx como proxy ascendente?



proxy inverso apache (6)

Actualización II

Ahora es el 16 de julio de 2015 y las cosas han cambiado nuevamente. He descubierto este contenedor automático de Jason Wilder : https://github.com/jwilder/nginx-proxy y resuelve este problema aproximadamente en el tiempo que le lleva a docker run el contenedor. Esta es ahora la solución que estoy usando para resolver este problema.

Actualizar

Ahora es julio de 2015 y las cosas han cambiado drásticamente con respecto a los contenedores Docker en red. Ahora hay muchas ofertas diferentes que resuelven este problema (en una variedad de formas).

Debería usar esta publicación para obtener una comprensión básica del enfoque de docker --link para el descubrimiento de servicios, que es tan básico como parece, funciona muy bien y en realidad requiere menos baile elegante que la mayoría de las otras soluciones. Está limitado porque es bastante difícil conectar en red contenedores en hosts separados en cualquier clúster dado, y los contenedores no pueden reiniciarse una vez que están en red, pero ofrecen una forma rápida y relativamente fácil de conectar en red contenedores en el mismo host. Es una buena manera de tener una idea de lo que el software que probablemente usará para resolver este problema realmente está haciendo bajo el capó.

Además, es probable que también desee ver la network naciente de Docker, el consul de Hashicorp, el weave Weaveworks, el progrium/consul y gliderlabs/registrator Jeff Lindsay y los Kubernetes de Google.

También están las ofertas de CoreOS que utilizan etcd , fleet y flannel .

Y si realmente quieres tener una fiesta, puedes girar un clúster para ejecutar Mesosphere , o Deis o Flynn .

Si eres nuevo en la creación de redes (como yo), entonces deberías sacar tus lentes de lectura, hacer estallar "Paint The Sky With Stars - The Best of Enya" en el Wi-Hi-Fi y tomar una cerveza: será un tiempo antes de que realmente entiendas exactamente qué es lo que estás tratando de hacer. Sugerencia: está intentando implementar una Service Discovery Layer en su Cluster Control Plane . Es una muy buena manera de pasar un sábado por la noche.

Es muy divertido, pero desearía haberme tomado el tiempo de educarme mejor sobre las redes en general antes de sumergirme. Finalmente encontré un par de publicaciones de los benevolentes dioses del Tutorial Digital Ocean: Introduction to Networking Terminology y Understanding ... Networking Introduction to Networking Terminology Understanding ... Networking . Sugiero leerlas varias veces antes de sumergirse.

¡Que te diviertas!



Publicación original

Parece que no puedo entender la asignación de puertos para los contenedores Docker . Específicamente cómo pasar solicitudes de Nginx a otro contenedor, escuchando en otro puerto, en el mismo servidor.

Tengo un Dockerfile para un contenedor Nginx así:

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"]



Y luego el archivo de configuración api.myapp.com ve así:

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; } }

Y luego otro para app.myapp.com también.

Y luego corro:

sudo docker run -p 80:80 -p 443:443 -d --name Nginx myusername/nginx


Y todo funciona bien, pero las solicitudes no se transfieren a los otros contenedores / puertos. Y cuando me meto en el contenedor Nginx e inspecciono los registros, no veo errores.

¿Alguna ayuda?


Acabo de encontrar un article de Anand Mani Sankar que muestra una manera simple de usar el proxy ascendente nginx con Docker Composer.

Básicamente, uno debe configurar el enlace de instancia y los puertos en el archivo docker-compose y actualizar en sentido ascendente en nginx.conf en consecuencia.


Con los enlaces de Docker , puede vincular el contenedor ascendente al contenedor nginx. Una característica adicional es que Docker administra el archivo host, lo que significa que podrá hacer referencia al contenedor vinculado mediante un nombre en lugar de la IP potencialmente aleatoria.


Intenté usar el popular proxy inverso Jason Wilder que funciona mágicamente por código para todos, y aprendí que no funciona para todos (es decir, para mí). Y soy nuevo en NGINX, y no me gustó que no entendía las tecnologías que estaba tratando de usar.

Quería agregar mis 2 centavos, porque la discusión anterior sobre la linking contenedores ahora está fechada ya que es una característica obsoleta. Así que aquí hay una explicación sobre cómo hacerlo usando networks . Esta respuesta es un ejemplo completo de cómo configurar nginx como proxy inverso para un sitio web estáticamente paginado usando Docker Compose y la configuración nginx.

TL; DR;

Agregue los servicios que necesitan comunicarse entre sí en una red predefinida. Para una discusión paso a paso en las redes de Docker, aprendí algunas cosas aquí: https://technologyconversations.com/2016/04/25/docker-networking-and-dns-the-good-the-bad-and-the-ugly/

Definir la red

En primer lugar, necesitamos una red en la que todos sus servicios de back-end puedan hablar. Llamé a mi web pero puede ser lo que quieras.

docker network create web

Construye la aplicación

Simplemente haremos una aplicación de sitio web simple. El sitio web es una simple página index.html que es servida por un contenedor nginx. El contenido es un volumen montado para el host bajo el content una carpeta

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

Tenga en cuenta que ya no necesitamos mapeo de puertos aquí. Simplemente exponemos el puerto 80. Esto es útil para evitar colisiones de puertos.

Ejecute la aplicación

Enciende este sitio web con

docker-compose up -d

Algunas comprobaciones divertidas sobre las asignaciones de dns para su contenedor:

docker exec -it sample-site bash ping sample-site

Este ping debería funcionar, dentro de su contenedor.

Construye el proxy

Proxy inverso de Nginx:

Dockerfile

FROM nginx RUN rm /etc/nginx/conf.d/*

Restablecemos toda la configuración del host virtual, ya que la vamos a personalizar.

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

Ejecute el proxy

Encienda el proxy usando nuestro confiable

docker-compose up -d

Suponiendo que no haya problemas, tiene dos contenedores en ejecución que pueden comunicarse entre sí utilizando sus nombres. Probémoslo.

docker exec -it nginx-proxy bash ping sample-site ping nginx-proxy

Configurar host virtual

El último detalle es configurar el archivo de alojamiento virtual para que el proxy pueda dirigir el tráfico en función de cómo quiera configurar su coincidencia:

sample-site.conf para nuestra configuración de alojamiento virtual:

server { listen 80; listen [::]:80; server_name my.domain.com; location / { proxy_pass http://sample-site; } }

Según cómo se configuró el proxy, necesitará este archivo almacenado en su carpeta conf.d local que montamos a través de la declaración de volumes en el archivo docker-compose .

Por último, pero no menos importante, dígale a nginx que vuelva a cargar su configuración.

docker exec nginx-proxy service nginx reload

Esta secuencia de pasos es la culminación de horas de fuertes dolores de cabeza mientras luchaba con el siempre doloroso error 502 Bad Gateway, y aprendía nginx por primera vez, ya que la mayor parte de mi experiencia fue con Apache.

Esta respuesta es para demostrar cómo eliminar el error 502 Bad Gateway que resulta de que los contenedores no puedan comunicarse entre sí.

Espero que esta respuesta le ahorre a alguien horas de dolor, ya que conseguir contenedores para hablar entre ellos fue realmente difícil de entender por alguna razón, a pesar de ser lo que esperaba que fuera un caso de uso obvio. Pero, de nuevo, yo tonto. Y háganme saber cómo puedo mejorar este enfoque.


La respuesta de @ gdbj es una gran explicación y la respuesta más actualizada. Sin embargo, aquí hay un enfoque más simple.

Entonces, si desea redirigir todo el tráfico desde nginx escuchando 80 a otro contenedor que expone 8080 , la configuración mínima puede ser tan pequeña como:

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"

Docker docs


La respuesta de @ T0xicCode es correcta, pero pensé en ampliar los detalles, ya que en realidad me tomó alrededor de 20 horas finalmente implementar una solución de trabajo.

Si está buscando ejecutar Nginx en su propio contenedor y usarlo como proxy inverso para equilibrar la carga de múltiples aplicaciones en la misma instancia del servidor, los pasos que debe seguir son los siguientes:

Vincula tus contenedores

Cuando la docker run sus contenedores, generalmente al ingresar un script de shell en los 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 con los anteriores. 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 contenedor de la API no está vinculado a ningún otro, pero el contenedor de la App está vinculado a la API y Nginx está vinculado tanto a la API como a la App .

El resultado de esto son los cambios en los archivos env y los archivos /etc/hosts que residen dentro de los contenedores API y de App . Los resultados se ven así:

/ etc / hosts

Ejecutar cat /etc/hosts dentro de su contenedor Nginx 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 env dentro de su contenedor Nginx 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 muchos de los vars reales, pero los anteriores son los valores clave que necesita para proxy del tráfico 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 entradas de archivos /etc/hosts y entornos que contienen la dirección IP local para cualquiera de los contenedores que estaban vinculados. Hasta donde puedo decir, esto es todo lo que sucede cuando ejecutas contenedores con opciones de enlace declaradas. Pero ahora puede usar esta información para configurar nginx dentro de su contenedor Nginx .



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/hosts que creó docker , o puede utilizar los vars de ENV y ejecutar un reemplazo de cadena (utilicé sed ) en su nginx.conf y cualquier otro archivo conf que puede estar en su carpeta /etc/nginx/sites-enabled para insertar los valores de IP.



OPCIÓN A: Configurar Nginx usando ENV Vars

Esta es la opción que utilicé porque no pude hacer que la opción de archivo /etc/hosts funcione. Probaré la Opción B pronto y actualizaré esta publicación con cualquier hallazgo.

La diferencia clave entre esta opción y el uso de la opción de archivo /etc/hosts es cómo escribir su Dockerfile para usar un script de shell como argumento CMD , que a su vez maneja el reemplazo de cadena para copiar los valores de IP de ENV a su archivo conf ( s)

Aquí está el conjunto de archivos de configuración con los que terminé:

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; }

NOTA: Es importante incluir el daemon off; en su archivo nginx.conf 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

Le dejaré a usted hacer su tarea sobre la mayoría de los contenidos de nginx.conf y api.myapp.conf .

La magia ocurre en Nginx-Startup.sh donde usamos sed para reemplazar las cadenas en el marcador de posición APP_IP que hemos escrito en el bloque upstream de nuestros archivos api.myapp.conf y app.myapp.conf .

Esta pregunta de ask.ubuntu.com lo explica muy bien: buscar y reemplazar texto dentro de un archivo usando comandos

GOTCHA En OSX, sed maneja las opciones de manera diferente, específicamente la bandera -i . En Ubuntu, la bandera -i manejará el reemplazo ''en su lugar''; abrirá el archivo, cambiará el texto y luego ''guardará'' el mismo archivo. En OSX, el indicador -i requiere la extensión de archivo que desea que tenga el archivo resultante. Si está trabajando con un archivo que no tiene extensión, debe ingresar '''' como valor para el indicador -i .

GOTCHA Para usar ENV vars dentro de la expresión regular que sed usa para encontrar la cadena que desea reemplazar, necesita envolver la var entre comillas dobles. Entonces, la sintaxis correcta, aunque de aspecto extraño, es la anterior.

Entonces, Docker lanzó nuestro contenedor y activó la Nginx-Startup.sh comandos Nginx-Startup.sh , que utilizó sed para cambiar el valor APP_IP a la variable ENV correspondiente que proporcionamos en el comando sed . Ahora tenemos archivos conf dentro de nuestro directorio /etc/nginx/sites-enabled que tienen las direcciones IP de los archivos ENV que la ventana acoplable establece al iniciar el contenedor. Dentro de su archivo api.myapp.conf verá que el bloque upstream 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 generalmente es 172.0.0.x

Ahora debería tener todo enrutado adecuadamente.

GOTCHA No puede reiniciar / volver a ejecutar ningún contenedor una vez que haya ejecutado el inicio de la instancia inicial. Docker proporciona a cada contenedor una nueva IP al momento del lanzamiento y no parece reutilizar ninguno de los que usaba antes. Entonces api.myapp.com obtendrá 172.0.0.2 la primera vez, pero luego obtendrá 172.0.0.4 la próxima vez. Pero Nginx ya habrá configurado la primera IP en sus archivos conf, o en su /etc/hosts , por lo que no podrá determinar la nueva IP para api.myapp.com . Es probable que la solución a esto use CoreOS y su servicio etcd que, en mi comprensión limitada, actúa como un ENV compartido para todas las máquinas registradas en el mismo clúster CoreOS . Este es el próximo juguete con el que voy a jugar.



OPCIÓN B: Use /etc/hosts File Entries

Esta debería ser la forma más rápida y fácil de hacerlo, pero no pude hacerlo funcionar. Aparentemente, simplemente ingresó el valor de la entrada /etc/hosts en sus archivos api.myapp.conf y app.myapp.conf , pero no pude hacer que este método funcionara.

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/hosts así: 172.0.0.2 API , pensé que solo obtendría el valor, pero no parece ser.

También tuve un par de problemas auxiliares con mi fuente de Elastic Load Balancer de todas las AZ, por lo que puede haber sido el problema cuando intenté esta ruta. En cambio, tuve que aprender a manejar el reemplazo de cadenas en Linux, así que fue divertido. Lo intentaré en un momento y veré cómo va.


share se puede hacer funcionar usando la imagen base de Ubuntu y configurando nginx por su cuenta. (No funcionó cuando usé la imagen Nginx de Docker Hub).

Aquí está el archivo Docker que utilicé:

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;"]

Mi configuración nginx (también conocido como: conf / mysite.com):

server { listen 80 default; server_name mysite.com; location / { proxy_pass http://website; } } upstream website { server website:3000; }

Y finalmente, cómo comienzo mis contenedores:

$ docker run -dP --name website website $ docker run -dP --name nginx --link website:website nginx

Esto me puso en funcionamiento, por lo que mi nginx apuntó hacia el segundo contenedor acoplable que expuso el puerto 3000.