Docker: escalar nginx y php-fpm por separado

Docker: escalar nginx y php-fpm por separado

He estado jugando con Docker y Docker-Compose y tengo una pregunta.

Actualmente mi docker-compose.yml se ve así:

app:
    image: myname/php-app
    volumes:
        - /var/www
    environment:
        <SYMFONY_ENVIRONMENT>: dev

web:
    image: myname/nginx
    ports:
        - 80
    links:
        - app
    volumes_from:
        - app

La aplicación contiene php-fpm en el puerto 9000 y el código de mi aplicación. Web es nginx con algunos bits de configuración.

Esto funciona como lo esperaría, sin embargo, para conectar nginx a php-fpm tengo esta línea:

fastcgi_pass    app:9000;

¿Cómo puedo escalar esto de manera efectiva? Si quisiera, por ejemplo, tener un contenedor nginx ejecutándose pero tres contenedores de aplicaciones ejecutándose, seguramente tendré tres instancias de php-fpm, todas intentando escuchar en el puerto 9000.

¿Cómo puedo tener cada instancia de php-fpm en un puerto diferente pero aún así saber dónde están en mi configuración de nginx en un momento dado?

¿Estoy adoptando el enfoque equivocado?

¡Gracias!

Respuesta1

Una solución es agregar instancias php-fpm adicionales a su archivo docker-compose y luego usar un nginx upstream como se menciona en las otras respuestas para equilibrar la carga entre ellas. Esto se hace en este repositorio de ejemplo de Docker-Compose:https://github.com/iamyojimbo/docker-nginx-php-fpm/blob/master/nginx/nginx.conf#L137

upstream php {
    #If there's no directive here, then use round_robin.
    #least_conn;
    server dockernginxphpfpm_php1_1:9000;
    server dockernginxphpfpm_php2_1:9000;
    server dockernginxphpfpm_php3_1:9000;
}

Esto no es realmente ideal porque requerirá cambiar la configuración de nginx y docker-compose.yml cuando desee ampliar o reducir.

Tenga en cuenta que el puerto 9000 es interno al contenedor y no a su host real, por lo que no importa que tenga varios contenedores php-fpm en el puerto 9000.

Docker adquirió Tutum este otoño. Tienen una solución que combina un contenedor HAProxy con su API para ajustar automáticamente la configuración del equilibrador de carga a los contenedores en ejecución que está equilibrando la carga. Esa es una buena solución. Luego nginx apunta al nombre de host asignado al equilibrador de carga. Quizás Docker integre aún más este tipo de solución en sus herramientas luego de la adquisición de Tutum. Hay un artículo al respecto aquí:https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service

Tutum es actualmente un servicio pago. Rancher es un proyecto de código abierto que proporciona una función de equilibrio de carga similar. También tienen un "rancher-compose.yml" que puede definir el equilibrio de carga y el escalado de la configuración de los servicios en docker-compose.yml. http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/ http://docs.rancher.com/rancher/concepts/#load-balancer

ACTUALIZACIÓN 06/03/2017: He usado un proyecto llamadoentrelazarque funciona con Docker para actualizar automáticamente la configuración de nginx y reiniciarla. Vea también el de @iwaseatenbyagruerespuestaque tiene enfoques adicionales.

Respuesta2

Aunque esta publicación es de 2015 y siento que me estoy necrogando (lo siento comunidad), siento que es valioso agregar en este momento:

Hoy en día (y desde que se mencionó Kubernetes) cuando trabajas con Docker puedes usar Kubernetes o Docker Swarm muy fácilmente para resolver este problema. Ambos orquestadores aceptarán sus nodos de Docker (un nodo = un servidor con Docker) y usted podrá implementar servicios en ellos y ellos administrarán los desafíos de puerto por usted utilizando redes superpuestas.

Como estoy más versado en Docker Swarm, así es como lo haría para abordar este problema (suponiendo que tenga un solo nodo Docker):

Inicializa el enjambre:

docker swarm init

cd en la raíz de tu proyecto

cd some/project/root

cree una pila de enjambre desde su docker-compose.yml (en lugar de usar docker-compose):

docker stack deploy -c docker-compose.yml myApp

Esto creará una pila de servicios Docker Swarm llamada "myApp" y administrará los puertos por usted. Esto significa: solo tiene que agregar una definición de "puerto: 9000:9000" a su servicio php-fpm en su archivo docker-compose y luego puede escalar el servicio php-fpm, digamos a 3 instancias, mientras el enjambre lo hará. Equilibra automáticamente la carga de las solicitudes entre las tres instancias sin necesidad de realizar más trabajo.

Respuesta3

Puede utilizar un upstream para definir múltiples backends, como se describe aquí:

https://stackoverflow.com/questions/5467921/how-to-use-fastcgi-next-upstream-in-nginx

También querrás actualizar la configuración cada vez que nuevos backends mueran o entren en servicio con algo como:

https://github.com/kelseyhightower/confd

Respuesta4

Otro enfoque podría ser investigar algo comoplantilla-cónsul.

Y por supuesto, en algún momento,Kubernetestal vez sea necesario mencionarlo.

Sin embargo, podría considerar un enfoque un poco más de 'trozos de cuerda y cinta adhesiva' al observar lo que el consumo de eventos acoplables podría hacer por usted (ejecute docker events --since 0para obtener una muestra rápida).

Sería razonablemente trivial tener un script que analice estos eventos (teniendo en cuenta que hay varios paquetes de cliente disponibles, incluidos Python, go, etc.), modificando un archivo de configuración y recargando nginx (es decir, usando el enfoque de plantilla de cónsul, pero sin necesidad de cónsul).

Sin embargo, volviendo a su premisa original: siempre que sus contenedores php-fpm se inicien con su propia red (es decir, sin compartir la de otro contenedor, como el de nginx), entonces podrá tener tantos contenedores escuchando en el puerto como sea posible. 9000 como desee: como tienen IP por contenedor, no hay problema con el "choque" de puertos.

La forma en que escale esto probablemente dependerá de cuál sea su objetivo/caso de uso final, pero una cosa que podría considerar es colocar HAproxy entre nginx y sus nodos php-fpm. Una cosa que esto podría permitirle hacer es simplemente nominar un rango (y posiblemente crear un docker network) para sus servidores php-fpm (es decir, 172.18.0.0/24) y configurar HAproxy para intentar usar cualquier IP dentro de ese rango como backend. . Dado que HAproxy tiene controles de estado, podría identificar rápidamente qué direcciones están activas y utilizarlas.

Verhttps://stackoverflow.com/questions/1358198/nginx-removing-upstream-servers-from-poolpara una discusión sobre cómo nginx vs haproxy maneja las aguas arriba.

A menos que esté utilizando una red Docker dedicada para esto,podríaNecesitas realizar alguna gestión manual de IP para tus nodos php-fpm.

información relacionada