Docker - osobne skalowanie nginx i php-fpm

11

Bawiłem się dokerem i kompozycją doktora i mam pytanie.

Obecnie mój docker-compose.yml wygląda następująco:

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

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

Aplikacja zawiera php-fpm na porcie 9000 i mój kod aplikacji. Sieć jest nginx z kilkoma bitami konfiguracji.

Działa to tak, jakbym tego oczekiwał, jednak aby połączyć nginx z php-fpm, mam następującą linię:

fastcgi_pass    app:9000;

Jak mogę to skutecznie skalować? Jeśli chciałbym na przykład mieć jeden kontener nginx, ale trzy kontenery aplikacji, to na pewno będę miał trzy instancje php-fpm, wszystkie próbujące nasłuchiwać na porcie 9000.

Jak mogę mieć każdą instancję php-fpm na innym porcie, ale nadal wiedzieć, gdzie są one w mojej konfiguracji nginx w danym momencie?

Czy przyjmuję niewłaściwe podejście?

Dzięki!

JimBlizz
źródło

Odpowiedzi:

5

Jednym z rozwiązań jest dodanie dodatkowych instancji php-fpm do pliku tworzącego okno dokowane, a następnie użycie nginx w górę, jak wspomniano w innych odpowiedziach, w celu zrównoważenia obciążenia między nimi. Odbywa się to w tym przykładzie repozytorium docker-komponuj: 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;
}

To nie jest naprawdę idealne, ponieważ będzie wymagało zmiany konfiguracji nginx i docker-compose.yml, gdy chcesz skalować w górę lub w dół.

Zauważ, że port 9000 jest wewnętrznym kontenerem, a nie twoim rzeczywistym hostem, więc nie ma znaczenia, że ​​masz wiele kontenerów php-fpm na porcie 9000.

Docker nabył Tutum tej jesieni. Mają rozwiązanie, które łączy kontener HAProxy z interfejsem API w celu automatycznego dostosowania konfiguracji modułu równoważenia obciążenia do działających kontenerów, które równoważą obciążenie. To miłe rozwiązanie. Następnie nginx wskazuje nazwę hosta przypisaną do modułu równoważenia obciążenia. Być może Docker w dalszym ciągu zintegruje tego typu rozwiązanie ze swoimi narzędziami po przejęciu Tutum. Artykuł na ten temat znajduje się tutaj: https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service

Tutum jest obecnie usługą płatną. Rancher to projekt typu open source, który zapewnia podobną funkcję równoważenia obciążenia. Mają także „rancher-compose.yml”, który może definiować równoważenie obciążenia i skalowanie konfiguracji usług w docker-compose.yml. http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/ http://docs.rancher.com/rancher/concepts/#load-balancer

AKTUALIZACJA 2017/03/06: Użyłem projektu o nazwie interlock, który współpracuje z Dockerem, aby automatycznie zaktualizować konfigurację nginx i zrestartować ją. Patrz także @ iwaseatenbyagrue za odpowiedź , która ma dodatkowych podejść.

rmarscher
źródło
0

W przypadku, gdy twoje kontenery Nginx i php-fpm znajdują się na tym samym hoście, możesz skonfigurować małą instancję dnsmasq na hoście, która będzie używana przez kontener Nginx, i uruchomić skrypt, aby automatycznie aktualizować rekord DNS, gdy adres IP kontenera ma zmienione.

Napisałem do tego mały skrypt (wklejony poniżej), który automatycznie aktualizuje rekord DNS, który ma taką samą nazwę jak nazwa kontenerów i wskazuje je na adresy IP kontenerów:

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

Następnie uruchom kontener nginx --dns host-ip-address, gdzie host-ip-addressjest adres IP hosta w interfejsie docker0.

Twoja konfiguracja Nginx powinna dynamicznie rozpoznawać nazwy:

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

Bibliografia:

Jeśli twoje nginx i php-fpm są na różnych hostach, możesz wypróbować odpowiedź @ smaj.

xuhdev
źródło
0

Innym podejściem może być przyjrzenie się szablonowi konsul .

I oczywiście, w pewnym momencie, może trzeba wspomnieć o Kubernetesie .

Można jednak rozważyć nieco więcej „fragmentów sznurka i taśmy izolacyjnej”, patrząc na to, co mogą zrobić dla Ciebie pochłaniające zdarzenia dokera (uruchom docker events --since 0szybką próbkę).

Racjonalnie trywialne byłoby posiadanie skryptu analizującego te zdarzenia (pamiętając, że dostępnych jest kilka pakietów klienckich, w tym dla Pythona, go itp.), Zmieniania pliku konfiguracyjnego i przeładowywania nginx (tj. Przy użyciu podejścia konsul-szablon, ale bez potrzeby konsula).

Wracając jednak do pierwotnej przesłanki: tak długo, jak kontenery php-fpm są uruchamiane z ich własną siecią (tzn. Nie współużytkują innego kontenera, takiego jak nginx), możesz mieć tyle kontenerów nasłuchujących na porcie 9000, jak chcesz - ponieważ mają adresy IP na kontener, nie ma problemu z „kolizją” portów.

Sposób skalowania będzie prawdopodobnie zależeć od ostatecznego celu / przypadku użycia, ale jedną rzeczą, którą możesz rozważyć, jest umieszczenie HAproxy między nginx a węzłami php-fpm. Jedną z rzeczy, na które możesz to pozwolić, jest po prostu wyznaczenie zakresu (i ewentualnie utworzenie a docker network) dla serwerów php-fpm (tj. 172.18.0.0/24) i skonfigurowanie HAproxy do używania dowolnego adresu IP w tym zakresie jako backendu . Ponieważ HAproxy ma kontrole stanu, może szybko zidentyfikować, które adresy są aktywne i z nich skorzystać.

Zobacz /programming/1358198/nginx-removing-upstream-servers-from-pool, aby uzyskać dyskusję na temat tego, jak Nginx vs. Haproxy radzi sobie z upstreams.

O ile nie używasz do tego dedykowanej sieci dokerów, być może będziesz musiał zrobić ręczne zarządzanie IP dla swoich węzłów php-fpm.

iwaseatenbyagrue
źródło
0

Chociaż ten post pochodzi z 2015 r. I wydaje mi się, że nekroję (przepraszam społeczność), wydaje mi się, że warto w tym momencie dodać:

W dzisiejszych czasach (i od kiedy wspomniano o Kubernetesie) podczas pracy z Dockerem możesz bardzo łatwo użyć Kubernetes lub Docker Swarm, aby rozwiązać ten problem. Obaj orkiestratorzy wezmą twoje węzły dokerów (jeden węzeł = jeden serwer z Dockerem na nim) i możesz wdrożyć na nich usługi, a oni będą zarządzać wyzwaniami dla portów za pomocą sieci nakładek.

Ponieważ jestem bardziej zaznajomiony z Docker Swarm, oto jak zrobiłbyś to, aby podejść do tego problemu (zakładając, że masz pojedynczy węzeł Docker):

Zainicjuj rój:

docker swarm init

cd do katalogu głównego projektu

cd some/project/root

utwórz stos roju z docker-compose.yml (zamiast używać docker-compose):

docker stack deploy -c docker-compose.yml myApp

Spowoduje to utworzenie stosu usługi dokowania roju o nazwie „myApp” i zarządzanie portami za Ciebie. Oznacza to: Musisz dodać tylko jedną definicję „port: 9000: 9000” do usługi php-fpm w pliku skompilowania dokera, a następnie możesz skalować usługę php-fpm, powiedzmy do 3 instancji, podczas gdy rój będzie automatycznie magicznie równoważy obciążenia żądań między trzema instancjami bez dalszej pracy.

Worp
źródło