Docker: ridimensionamento separato di nginx e php-fpm


11

Ho giocato con docker e docker-compose e ho una domanda.

Attualmente il mio docker-compose.yml è simile al seguente:

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

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

L'app contiene php-fpm sulla porta 9000 e il mio codice dell'applicazione. Il Web è nginx con alcuni bit di configurazione.

Questo funziona come mi aspetterei, tuttavia per collegare nginx a php-fpm ho questa linea:

fastcgi_pass    app:9000;

Come posso ridimensionarlo efficacemente? Se volessi, ad esempio, avere un contenitore nginx in esecuzione ma tre contenitori di app in esecuzione, avrò sicuramente tre istanze php-fpm che provano tutte ad ascoltare sulla porta 9000.

Come posso avere ciascuna istanza di php-fpm su una porta diversa ma sapere ancora dove si trovano nella mia configurazione di nginx in un dato momento?

Sto prendendo un approccio sbagliato?

Grazie!

Risposte:


5

Una soluzione è aggiungere ulteriori istanze php-fpm al file comporre docker e quindi utilizzare un nginx a monte come menzionato nelle altre risposte per bilanciare il carico tra di loro. Questo viene fatto in questo repo di esempio 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;
}

Questo non è davvero l'ideale perché richiederà la modifica di nginx config e docker-compose.yml quando si desidera ridimensionare o ridurre.

Nota che la porta 9000 è interna al contenitore e non al tuo host reale, quindi non importa che tu abbia più contenitori php-fpm sulla porta 9000.

Docker ha acquisito Tutum questo autunno. Hanno una soluzione che combina un contenitore HAProxy con le loro API per adattare automaticamente la configurazione del bilanciamento del carico ai contenitori in esecuzione che sta bilanciando il carico. Questa è una bella soluzione. Quindi nginx punta al nome host assegnato al bilanciamento del carico. Forse Docker integrerà ulteriormente questo tipo di soluzione nei propri strumenti dopo l'acquisizione di Tutum. C'è un articolo a riguardo qui: https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service

Tutum è attualmente un servizio a pagamento. Rancher è un progetto open source che fornisce una funzionalità di bilanciamento del carico simile. Hanno anche un "rancher-compose.yml" che può definire il bilanciamento del carico e il ridimensionamento della configurazione dei servizi in docker-compose.yml. http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/ http://docs.rancher.com/rancher/concepts/#load-balancer

AGGIORNAMENTO 2017/03/06: Ho usato un progetto chiamato interlock che funziona con Docker per aggiornare automaticamente la configurazione di nginx e riavviarlo. Vedi anche la risposta di @ iwaseatenbyagrue che ha approcci aggiuntivi.



0

Nel caso in cui i contenitori Nginx e php-fpm si trovino sullo stesso host, è possibile configurare una piccola istanza dnsmasq sull'host che verrà utilizzata dal contenitore Nginx ed eseguire uno script per aggiornare automaticamente il record DNS quando l'indirizzo IP del contenitore ha cambiato.

Ho scritto un piccolo script per farlo (incollato di seguito), che aggiorna automaticamente il record DNS che ha lo stesso nome del nome dei contenitori e li indirizza agli indirizzi IP dei contenitori:

#!/bin/bash

# 10 seconds interval time by default
INTERVAL=${INTERVAL:-10}

# dnsmasq config directory
DNSMASQ_CONFIG=${DNSMASQ_CONFIG:-.}

# commands used in this script
DOCKER=${DOCKER:-docker}
SLEEP=${SLEEP:-sleep}
TAIL=${TAIL:-tail}

declare -A service_map

while true
do
    changed=false
    while read line
    do
        name=${line##* }
        ip=$(${DOCKER} inspect --format '{{.NetworkSettings.IPAddress}}' $name)
        if [ -z ${service_map[$name]} ] || [ ${service_map[$name]} != $ip ] # IP addr changed
        then
            service_map[$name]=$ip
            # write to file
            echo $name has a new IP Address $ip >&2
            echo "host-record=$name,$ip"  > "${DNSMASQ_CONFIG}/docker-$name"
            changed=true
        fi
    done < <(${DOCKER} ps | ${TAIL} -n +2)

    # a change of IP address occured, restart dnsmasq
    if [ $changed = true ]
    then
        systemctl restart dnsmasq
    fi

    ${SLEEP} $INTERVAL
done

Quindi, avvia il tuo contenitore nginx con --dns host-ip-address, dove si host-ip-addresstrova l'indirizzo IP dell'host sull'interfaccia docker0.

La tua configurazione Nginx dovrebbe risolvere i nomi in modo dinamico:

server {
  resolver host-ip-address;
  listen 80;
  server_name @server_name@;
  root /var/www/@root@;
  index index.html index.htm index.php;

  location ~ ^(.+?\.php)(/.*)?$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$1;
    set $backend "@fastcgi_server@";
    fastcgi_pass $backend;
  }
}

Riferimenti:

Se nginx e php-fpm si trovano su host diversi, puoi provare la risposta di @ smaj.


0

Un altro approccio potrebbe essere quello di esaminare qualcosa come console-template .

E ovviamente, ad un certo punto, potrebbe essere necessario menzionare Kubernetes .

Tuttavia, è possibile prendere in considerazione un approccio un po 'più di "bit of string and duct tape" osservando cosa consumano gli eventi docker per te (esegui docker events --since 0per un rapido esempio).

Sarebbe ragionevolmente banale avere uno script che guardasse questi eventi (tenendo presente che ci sono diversi pacchetti client disponibili, tra cui python, go, ecc.), Che modifica un file di configurazione e ricarica nginx (cioè usando l'approccio console-template, ma senza la necessità di console).

Per tornare alla tua premessa originale, però: fintanto che i tuoi contenitori php-fpm vengono avviati con la propria rete (cioè non condividendo quella di un altro contenitore, come quello nginx), puoi avere tanti container in ascolto sulla porta 9000 come vuoi - dato che hanno IP per container, non c'è nessun problema con il "clashing" delle porte.

Il modo in cui lo ridimensionerai probabilmente dipenderà dal tuo obiettivo / caso d'uso finale, ma una cosa che potresti considerare è posizionare HAproxy tra nginx e i tuoi nodi php-fpm. Una cosa che potrebbe permetterti di fare è semplicemente nominare un intervallo (e possibilmente creare un docker network) per i tuoi server php-fpm (cioè 172.18.0.0/24) e avere HAproxy configurato per provare a utilizzare qualsiasi IP all'interno di quell'intervallo come back-end . Poiché HAproxy ha controlli di integrità, potrebbe identificare rapidamente quali indirizzi sono attivi e utilizzarli.

Vedi /programming/1358198/nginx-removing-upstream-servers-from-pool per una discussione su come nginx vs haproxy gestisce i flussi up.

A meno che tu non stia utilizzando una rete docker dedicata per questo, potresti dover eseguire una gestione manuale dell'IP per i tuoi nodi php-fpm.


0

Anche se questo post è del 2015 e mi sento necroing (mi dispiace comunità), mi sento che sia utile aggiungere a questo punto nel tempo:

Al giorno d'oggi (e da quando è stato menzionato Kubernetes) quando si lavora con Docker, è possibile utilizzare Kubernetes o Docker Swarm molto facilmente per risolvere questo problema. Entrambi gli orchestrator accetteranno i tuoi nodi docker (un nodo = un server con Docker su di esso) e potrai distribuire servizi su di essi e gestiranno le sfide delle porte usando reti di overlay.

Dato che sono più esperto di Docker Swarm, ecco come lo faresti per affrontare questo problema (supponendo che tu abbia un singolo nodo Docker):

Inizializza lo sciame:

docker swarm init

cd nella radice del progetto

cd some/project/root

crea uno stack di sciami dal tuo docker-compose.yml (invece di usare docker-compose):

docker stack deploy -c docker-compose.yml myApp

Questo creerà uno stack di servizi per lo sciame di docker chiamato "myApp" e gestirà le porte per te. Questo significa: Devi solo aggiungere una definizione "port: 9000: 9000" al tuo servizio php-fpm nel tuo file comporre docker e quindi puoi aumentare il servizio php-fpm, diciamo a 3 istanze, mentre lo sciame bilanciamento automatico del carico delle richieste tra le tre istanze senza ulteriore lavoro necessario.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.