Docker - dimensionando nginx e php-fpm separadamente

Docker - dimensionando nginx e php-fpm separadamente

Tenho brincado com docker e docker-compose e tenho uma dúvida.

Atualmente meu docker-compose.yml está assim:

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

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

O aplicativo contém php-fpm na porta 9000 e o código do meu aplicativo. Web é nginx com alguns bits de configuração.

Isso funciona como eu esperaria, no entanto, para conectar o nginx ao php-fpm, tenho esta linha:

fastcgi_pass    app:9000;

Como posso dimensionar isso de forma eficaz? Se eu quisesse, por exemplo, ter um contêiner nginx em execução, mas três contêineres de aplicativos em execução, certamente terei três instâncias de php-fpm, todas tentando escutar na porta 9000.

Como posso ter cada instância do php-fpm em uma porta diferente, mas ainda saber onde elas estão na minha configuração do nginx a qualquer momento?

Estou adotando a abordagem errada?

Obrigado!

Responder1

Uma solução é adicionar instâncias adicionais de php-fpm ao seu arquivo docker-compose e, em seguida, usar um upstream nginx conforme mencionado nas outras respostas para balancear a carga entre eles. Isso é feito neste exemplo de repositório 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;
}

Isso não é realmente ideal porque exigirá a alteração da configuração do nginx e docker-compose.yml quando você quiser aumentar ou diminuir a escala.

Observe que a porta 9000 é interna ao contêiner e não ao seu host real, portanto, não importa se você tem vários contêineres php-fpm na porta 9000.

Docker adquiriu Tutum neste outono. Eles têm uma solução que combina um contêiner HAProxy com sua API para ajustar automaticamente a configuração do balanceador de carga aos contêineres em execução que estão fazendo o balanceamento de carga. Essa é uma boa solução. Então o nginx aponta para o nome do host atribuído ao balanceador de carga. Talvez a Docker integre ainda mais esse tipo de solução em suas ferramentas após a aquisição da Tutum. Há um artigo sobre isso aqui:https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service

Tutum é atualmente um serviço pago. Rancher é um projeto de código aberto que oferece um recurso de balanceamento de carga semelhante. Eles também têm um "rancher-compose.yml" que pode definir o balanceamento de carga e o dimensionamento da configuração dos serviços no docker-compose.yml. http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/ http://docs.rancher.com/rancher/concepts/#load-balancer

ATUALIZAÇÃO 06/03/2017: usei um projeto chamadointerligarque funciona com o Docker para atualizar automaticamente a configuração do nginx e reiniciá-lo. Veja também o de @iwaseatenbyagrueresponderque tem abordagens adicionais.

Responder2

Embora esta postagem seja de 2015 e eu sinta que estou necroando (desculpe, comunidade), acho que é valioso acrescentar neste momento:

Hoje em dia (e desde que o Kubernetes foi mencionado) quando você está trabalhando com Docker você pode usar Kubernetes ou Docker Swarm com muita facilidade para resolver este problema. Ambos os orquestradores receberão seus nós docker (um nó = um servidor com Docker nele) e você poderá implantar serviços neles e eles gerenciarão os desafios de porta para você usando redes de sobreposição.

Como sou mais versado em Docker Swarm, é assim que você faria para abordar esse problema (supondo que você tenha um único nó Docker):

Inicialize o enxame:

docker swarm init

cd na raiz do seu projeto

cd some/project/root

crie uma pilha swarm a partir do docker-compose.yml (em vez de usar docker-compose):

docker stack deploy -c docker-compose.yml myApp

Isso criará uma pilha de serviço docker swarm chamada "myApp" e gerenciará as portas para você. Isso significa: você só precisa adicionar uma definição de "porta: 9000:9000" ao seu serviço php-fpm em seu arquivo docker-compose e então você pode escalar o serviço php-fpm, digamos, para 3 instâncias, enquanto o enxame irá equilibre automaticamente a carga das solicitações entre as três instâncias sem a necessidade de nenhum trabalho adicional.

Responder3

Você pode usar um upstream para definir vários back-ends, conforme descrito aqui:

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

Você também gostaria que a configuração fosse atualizada sempre que novos back-end morrem/entram em serviço com algo como:

https://github.com/kelseyhightower/confd

Responder4

Outra abordagem pode ser olhar para algo comomodelo de cônsul.

E claro, em algum momento,Kubernetespode precisar ser mencionado.

No entanto, você pode considerar uma abordagem um pouco mais de 'pedaços de barbante e fita adesiva', observando o que o consumo de eventos do docker pode fazer por você (execute docker events --since 0uma amostra rápida).

Seria razoavelmente trivial ter um script analisando esses eventos (tendo em mente que existem vários pacotes de clientes disponíveis, inclusive para python, go, etc), alterando um arquivo de configuração e recarregando o nginx (ou seja, usando a abordagem consul-template, mas sem necessidade de cônsul).

Porém, voltando à sua premissa original: contanto que seus contêineres php-fpm sejam iniciados com sua própria rede (ou seja, não compartilhem a de outro contêiner, como o nginx), você poderá ter tantos contêineres escutando na porta 9000 como você deseja - como eles têm IPs por contêiner, não há problema com 'conflito' de portas.

A maneira como você dimensiona isso provavelmente dependerá de qual é seu objetivo/caso de uso final, mas uma coisa que você pode considerar é colocar o HAproxy entre o nginx e seus nós php-fpm. Uma coisa que isso pode permitir que você faça é simplesmente nomear um intervalo (e possivelmente criar um docker network) para seus servidores php-fpm (ou seja, 172.18.0.0/24) e ter o HAproxy configurado para tentar usar qualquer IP dentro desse intervalo como back-end . Como o HAproxy possui verificações de integridade, ele pode identificar rapidamente quais endereços estão ativos e utilizá-los.

Verhttps://stackoverflow.com/questions/1358198/nginx-removing-upstream-servers-from-poolpara uma discussão sobre como o nginx vs haproxy lida com upstreams.

A menos que você esteja usando uma rede docker dedicada para isso, vocêpoderprecisa fazer algum gerenciamento manual de IP para seus nós php-fpm.

informação relacionada