Докер - окремо масштабування nginx та php-fpm


11

Я пограв з докером і докер-композитом і маю питання.

Наразі мій docker-compose.yml виглядає так:

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

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

Додаток містить php-fpm на порт 9000 та мій код програми. Web - це nginx з кількома бітами конфігурації.

Це функціонує так, як я би очікував цього, але для того, щоб підключити nginx до php-fpm, у мене є ця лінія:

fastcgi_pass    app:9000;

Як я можу ефективно масштабувати це? Якщо б я хотів, наприклад, мати один контейнер nginx, але три контейнери додатків, то у мене обов'язково три екземпляри php-fpm, які намагаються слухати на порту 9000.

Як я можу мати кожен екземпляр php-fpm на іншому порту, але все ще знаю, де вони знаходяться в моєму конфігурації nginx в будь-який момент часу?

Я невірний підхід?

Спасибі!

Відповіді:


5

Одне рішення - додати додаткові екземпляри php-fpm до файлу, який складається з докер-файлів, а потім використовувати nginx вгору за потоком, як зазначено в інших відповідях, щоб збалансувати навантаження між ними. Це робиться в цьому прикладі репо-докер-композиції: 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;
}

Це насправді не ідеально, тому що потрібно змінити конфігурацію nginx і docker-compose.yml, коли потрібно масштабувати вгору або вниз.

Зауважте, що порт 9000 є внутрішнім для контейнера, а не вашим фактичним хостом, тому не має значення, що у вас є кілька контейнерів php-fpm на порт 9000.

Восени цього року Докер придбав Тутум. У них є рішення, яке поєднує контейнер HAProxy з їх api, щоб автоматично налаштувати конфігурацію балансира навантаження до запущених контейнерів, які це балансування навантаження. Це приємне рішення. Потім nginx вказує на ім'я хоста, призначене балансиру навантаження. Можливо, Докер ще більше інтегрує цей тип рішення у свої інструменти після придбання Tutum. Про це є стаття тут: https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service

Наразі Tutum - це платна послуга. Rancher - це проект з відкритим кодом, який забезпечує подібну функцію балансування навантаження. Вони також мають "rancher-compose.yml", який може визначати балансування навантаження та масштабування налаштування служб у docker-compose.yml. http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/ http://docs.rancher.com/rancher/concepts/#load-balancer

ОНОВЛЕННЯ 2017/03/06: Я використовував проект під назвою interlock, який працює з Docker, щоб автоматично оновити конфігурацію nginx та перезапустити її. Також дивіться @ iwaseatenbyagrue в відповідь , який має додаткові підходи.


1

Ви можете скористатися висхідним потоком для визначення декількох перешкод, як описано тут:

/programming/5467921/how-to-use-fastcgi-next-upstream-in-nginx

Ви також хочете, щоб конфігурація оновлювалася кожного разу, коли нові пакунки вмирають / вступають у службу з чимось на зразок:

https://github.com/kelseyhightower/confd


0

У випадку, коли ваші контейнери Nginx та php-fpm знаходяться на одному хості, ви можете налаштувати невеликий екземпляр dnsmasq на хості, який буде використовуватися контейнером Nginx, та запустити сценарій для автоматичного оновлення запису DNS, коли IP-адреса контейнера має змінився.

Для цього я написав невеликий сценарій (вставлений нижче), який автоматично оновлює запис DNS, який має те саме ім'я, як ім'я контейнерів, і вказує їх на IP-адреси контейнерів:

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

Потім запустіть контейнер nginx --dns host-ip-address, де host-ip-addressзнаходиться IP-адреса хоста в інтерфейсі docker0.

Ваша конфігурація Nginx повинна динамічно розв’язувати імена:

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

Список літератури:

Якщо ваш nginx і php-fpm знаходяться на різних хостах, ви можете спробувати відповідь @ smaj.


0

Іншим підходом може бути пошук щось на зразок консульського шаблону .

І, звичайно, в який - то момент, Kubernetes може знадобитися згадувалося.

Однак ви можете розглянути трохи більше "біт струнних і канальних стрічок", поглянувши на те, що споживаючі докерські події можуть зробити для вас (запустіть docker events --since 0для швидкого зразка).

Було б досить тривіально мати сценарій, що дивиться на ці події (маючи на увазі, є декілька клієнтських пакетів, у тому числі для python, go і т. Д.), Внесення змін до конфігураційного файлу та перезавантаження nginx (тобто з використанням підходу-шаблону, але без потреби консула).

Однак, щоб повернутися до початкового приміщення: поки ваші контейнери php-fpm запускаються з власною мережею (тобто не поділяються з іншим контейнером, наприклад nginx), ви можете мати стільки контейнерів, які слухають на порту 9000, як ви хочете - оскільки у них є IP-адреси для контейнерів, з "зіткненням" портів немає жодної проблеми.

Як ви масштабуєте це, швидше за все, буде залежати від вашої кінцевої мети / випадку використання, але одне, що ви можете розглянути, - це розміщення HAproxy між nginx та вашими php-fpm вузлами. Одне, що може вам дозволити зробити, це просто призначити діапазон (і, можливо, створити a docker network) для ваших серверів php-fpm (тобто 172.18.0.0/24), і налаштувати HAproxy для того, щоб спробувати використовувати будь-який IP в межах цього діапазону як бекенд . Оскільки HAproxy має перевірку стану здоров’я, він може швидко визначити, які адреси є в прямому ефірі, і використовувати їх.

Дивіться /programming/1358198/nginx-removing-upstream-servers-from-pool для обговорення того, як nginx проти haproxy має справу з висхідними потоками.

Якщо ви не використовували для цього спеціалізовану мережу докера , можливо , вам доведеться виконати ручне управління IP-адресами для ваших вузлів php-fpm.


0

Хоча ця публікація є з 2015 року, і я відчуваю, що я нівелюю (шкода спільноти), мені здається, що це важливо додати в цей час:

У наш час (і оскільки згадувалося про Kubernetes), коли ви працюєте з Docker, ви можете дуже легко використовувати Kubernetes або Docker Swarm для вирішення цієї проблеми. Обидва оркестранти візьмуть ваші докерські вузли (один вузол = один сервер з Докером на ньому), і ви зможете розгорнути їм сервіси, і вони керуватимуть викликами портів для вас, використовуючи накладені мережі.

Оскільки я більше розбираюся в Docker Swarm, саме так ви зробили б це рішення для вирішення цієї проблеми (якщо припустити, що у вас є один докерський вузол):

Ініціалізуйте рій:

docker swarm init

CD в ​​корінь вашого проекту

cd some/project/root

створити стек рій із вашого docker-compose.yml (замість того, щоб використовувати docker-compose):

docker stack deploy -c docker-compose.yml myApp

Це створить стек служби рій докера під назвою "myApp" і керуватиме портами для вас. Це означає: Вам потрібно додати лише одне визначення "port: 9000: 9000" до вашої служби php-fpm у вашому файлі docker-compose, і тоді ви можете збільшити масштаб служби php-fpm, скажімо, до 3 примірників, тоді як рій буде автоматично магічно завантажуйте - врівноважуйте запити між трьома екземплярами без необхідності подальшої роботи

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.