Docker - Skalierung von Nginx und PHP-Fpm getrennt

11

Ich habe mit Docker und Docker-Compose herumgespielt und habe eine Frage.

Derzeit sieht meine docker-compose.yml folgendermaßen aus:

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

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

App enthält PHP-Fpm auf Port 9000 und meinen Anwendungscode. Web ist Nginx mit ein paar Bits Konfiguration.

Dies funktioniert so, wie ich es erwarten würde, aber um nginx mit php-fpm zu verbinden, habe ich diese Zeile:

fastcgi_pass    app:9000;

Wie kann ich das effektiv skalieren? Wenn ich zum Beispiel wollte, dass ein Nginx-Container läuft, aber drei App-Container, dann werde ich sicher drei PHP-Fpm-Instanzen haben, die alle versuchen, Port 9000 abzuhören.

Wie kann ich jede PHP-Fpm-Instanz an einem anderen Port haben und trotzdem wissen, wo sie sich zu einem bestimmten Zeitpunkt in meiner Nginx-Konfiguration befinden?

Gehe ich falsch vor?

Vielen Dank!

JimBlizz
quelle

Antworten:

5

Eine Lösung besteht darin, Ihrer Docker-Compose-Datei zusätzliche PHP-Fpm-Instanzen hinzuzufügen und dann einen Nginx-Upstream zu verwenden, wie in den anderen Antworten erwähnt, um den Lastausgleich zwischen ihnen zu gewährleisten. Dies geschieht in diesem Beispiel für das Docker-Compose-Repo: 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;
}

Dies ist nicht wirklich ideal, da die nginx-Konfiguration und die Datei docker-compose.yml geändert werden müssen, wenn Sie die Größe erhöhen oder verringern möchten.

Beachten Sie, dass sich der 9000-Port im Container befindet und nicht in Ihrem eigentlichen Host. Es spielt also keine Rolle, dass Sie mehrere PHP-Fpm-Container auf Port 9000 haben.

Docker hat Tutum diesen Herbst erworben. Sie haben eine Lösung, die einen HAProxy-Container mit ihrer API kombiniert, um die Load-Balancer-Konfiguration automatisch an die laufenden Container anzupassen, für die der Load-Balancing durchgeführt wird. Das ist eine schöne Lösung. Dann zeigt nginx auf den Hostnamen, der dem Load Balancer zugewiesen ist. Vielleicht wird Docker diese Art von Lösung nach der Übernahme von Tutum weiter in seine Tools integrieren. Hier gibt es einen Artikel darüber: https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service

Tutum ist derzeit ein kostenpflichtiger Dienst. Rancher ist ein Open-Source-Projekt, das eine ähnliche Lastausgleichsfunktion bietet. Sie haben auch eine "rancher-compose.yml", die den Lastausgleich und die Skalierung des Service-Setups in der docker-compose.yml definieren kann. http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/ http://docs.rancher.com/rancher/concepts/#load-balancer

UPDATE 06.03.2017: Ich habe ein Projekt namens Interlock verwendet , das mit Docker zusammenarbeitet, um die Nginx-Konfiguration automatisch zu aktualisieren und neu zu starten. Siehe auch die Antwort von @ iwaseatenbyagrue, die zusätzliche Ansätze enthält.

rmarscher
quelle
0

Wenn sich Ihre Nginx- und PHP-Fpm-Container auf demselben Host befinden, können Sie eine kleine dnsmasq- Instanz auf dem Host konfigurieren , die vom Nginx-Container verwendet werden soll, und ein Skript ausführen, um den DNS- Eintrag automatisch zu aktualisieren, wenn die IP-Adresse des Containers vorhanden ist geändert.

Ich habe dazu ein kleines Skript geschrieben (unten eingefügt), das den DNS-Eintrag, der denselben Namen wie der Name des Containers hat, automatisch aktualisiert und auf die IP-Adressen der Container verweist:

#!/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

Dann starten Sie Ihren nginx Container mit --dns host-ip-address, wo host-ip-addressdie IP - Adresse des Rechners , auf der Schnittstelle docker0.

Ihre Nginx-Konfiguration sollte Namen dynamisch auflösen:

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

Verweise:

Wenn sich Ihr Nginx und Ihr PHP-Fpm auf verschiedenen Hosts befinden, können Sie die Antwort von @ smaj ausprobieren.

xuhdev
quelle
0

Ein anderer Ansatz könnte darin bestehen, sich mit so etwas wie einer Konsul-Vorlage zu befassen .

Und natürlich muss Kubernetes irgendwann erwähnt werden.

Sie könnten jedoch einen etwas mehr Ansatz in Betracht ziehen, indem Sie sich ansehen, was konsumierende Docker-Ereignisse für Sie tun könnten ( docker events --since 0für ein kurzes Beispiel).

Es wäre ziemlich trivial, ein Skript zu haben, das diese Ereignisse untersucht (wenn man bedenkt, dass mehrere Client-Pakete verfügbar sind, einschließlich für Python, go usw.), eine Konfigurationsdatei ändert und nginx neu lädt (dh unter Verwendung des Consul-Template-Ansatzes). aber ohne Konsul).

Um jedoch zu Ihrer ursprünglichen Prämisse zurückzukehren: Solange Ihre PHP-Fpm-Container mit einem eigenen Netzwerk gestartet sind (dh nicht das eines anderen Containers wie dem Nginx-Container gemeinsam nutzen), können so viele Container den Port abhören 9000 wie Sie möchten - da sie IPs pro Container haben, gibt es kein Problem damit, dass Ports zusammenstoßen.

Wie Sie dies skalieren, hängt wahrscheinlich von Ihrem endgültigen Ziel / Anwendungsfall ab. Eine Sache, die Sie in Betracht ziehen könnten, ist jedoch, HAproxy zwischen nginx und Ihren PHP-Fpm-Knoten zu platzieren. Auf diese Weise können Sie einfach einen Bereich docker networkfür Ihre PHP-Fpm-Server (z. B. 172.18.0.0/24) festlegen (und möglicherweise einen erstellen) und HAproxy so konfigurieren, dass versucht wird, eine beliebige IP innerhalb dieses Bereichs als Backend zu verwenden . Da HAproxy über Integritätsprüfungen verfügt, kann es schnell erkennen, welche Adressen aktiv sind, und diese verwenden.

Unter /programming/1358198/nginx-removing-upstream-servers-from-pool finden Sie eine Diskussion darüber, wie nginx vs haproxy mit Upstreams umgeht.

Sofern Sie hierfür kein dediziertes Docker-Netzwerk verwendet haben, müssen Sie möglicherweise eine manuelle IP-Verwaltung für Ihre PHP-Fpm-Knoten durchführen.

Ich wurde von der Wahrheit gegessen
quelle
0

Obwohl dieser Beitrag aus dem Jahr 2015 stammt und ich das Gefühl habe, dass ich nekrotisch bin (sorry Community), halte ich es zu diesem Zeitpunkt für wertvoll, Folgendes hinzuzufügen:

Heutzutage (und da Kubernetes erwähnt wurde) können Sie bei der Arbeit mit Docker Kubernetes oder Docker Swarm sehr einfach verwenden, um dieses Problem zu lösen. Beide Orchestratoren nehmen Ihre Docker-Knoten auf (ein Knoten = ein Server mit Docker), und Sie können Dienste für sie bereitstellen, und sie verwalten Port-Herausforderungen für Sie mithilfe von Overlay-Netzwerken.

Da ich mit Docker Swarm besser vertraut bin, gehen Sie folgendermaßen vor, um dieses Problem anzugehen (vorausgesetzt, Sie haben einen einzelnen Docker-Knoten):

Initialisieren Sie den Schwarm:

docker swarm init

CD in Ihr Projektstammverzeichnis

cd some/project/root

Erstellen Sie einen Schwarmstapel aus Ihrer docker-compose.yml (anstatt docker-compose zu verwenden):

docker stack deploy -c docker-compose.yml myApp

Dadurch wird ein Docker-Schwarm-Service-Stack namens "myApp" erstellt und die Ports für Sie verwaltet. Dies bedeutet: Sie müssen Ihrem PHP-Fpm-Dienst in Ihrer Docker-Compose-Datei nur eine "Port: 9000: 9000" -Definition hinzufügen, und dann können Sie den PHP-Fpm-Dienst beispielsweise auf 3 Instanzen skalieren, während der Schwarm dies tut Automatischer Lastausgleich der Anforderungen zwischen den drei Instanzen, ohne dass weitere Arbeiten erforderlich sind.

Worp
quelle