Я играл с docker и docker-compose и у меня есть вопрос.
В настоящее время мой 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 в любой момент времени?
Я ошибаюсь?
Спасибо!
Одно из решений - добавить дополнительные экземпляры php-fpm в ваш файл docker-compose, а затем использовать восходящий поток nginx, как упоминалось в других ответах, для балансировки нагрузки между ними. Это сделано в этом примере репозитория 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;
}
Это не совсем идеально, потому что потребуется изменить конфигурацию nginx и docker-compose.yml, когда вы захотите увеличить или уменьшить масштаб.
Обратите внимание, что порт 9000 является внутренним по отношению к контейнеру, а не к вашему фактическому хосту, поэтому не имеет значения, что у вас есть несколько контейнеров php-fpm на порту 9000.
Осенью этого года Docker приобрел Tutum. У них есть решение, которое объединяет контейнер HAProxy с их API, чтобы автоматически настраивать конфигурацию балансировщика нагрузки для работающих контейнеров, которые он балансирует. Это хорошее решение. Затем nginx указывает на имя хоста, назначенное балансировщику нагрузки. Возможно, Docker будет и дальше интегрировать этот тип решения в свои инструменты после приобретения Tutum. Об этом есть статья: https://web.archive.org/web/20160628133445/https://support.tutum.co/support/solutions/articles/5000050235-load-balancing-a-web-service
Тутум в настоящее время является платной услугой. 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: я использовал проект под названием блокировка который работает с Docker, чтобы автоматически обновлять конфигурацию nginx и перезапускать его. Также см. @ Iwaseatenbyagrue's ответ который имеет дополнительные подходы.
Вы можете использовать восходящий поток для определения нескольких бэкэндов, как описано здесь:
https://stackoverflow.com/questions/5467921/how-to-use-fastcgi-next-upstream-in-nginx
Вы также хотели бы, чтобы конфигурация обновлялась всякий раз, когда новые серверные модули умирают / вводятся в эксплуатацию, с чем-то вроде:
Другой подход может заключаться в том, чтобы изучить что-то вроде консул-шаблон.
И, конечно же, в какой-то момент Kubernetes возможно, стоит упомянуть.
Тем не менее, вы могли бы рассмотреть вариант с чуть большим количеством «кусочков струны и клейкой ленты», посмотрев на то, что потребляющие события докера могут сделать для вас (запустите docker events --since 0
для быстрого образца).
Было бы достаточно тривиально иметь сценарий, просматривающий эти события (имея в виду, что существует несколько доступных клиентских пакетов, в том числе для python, go и т. Д.), Изменяя файл конфигурации и перезагружая nginx (то есть с использованием подхода consul-template, но без консула).
Однако, чтобы вернуться к исходной предпосылке: пока ваши контейнеры php-fpm запускаются с их собственной сетью (то есть не разделяют сеть другого контейнера, такого как nginx), вы можете иметь столько контейнеров, которые прослушивают порт 9000, как вы хотите - поскольку у них есть IP-адреса для каждого контейнера, проблем с конфликтом портов нет.
Как вы это масштабируете, вероятно, будет зависеть от вашей конечной цели / варианта использования, но вы можете подумать о том, чтобы разместить HAproxy между nginx и вашими узлами php-fpm. Это может позволить вам просто назначить диапазон (и, возможно, создать docker network
) для ваших серверов php-fpm (например, 172.18.0.0/24) и настроить HAproxy на попытку использовать любой IP-адрес в этом диапазоне в качестве бэкэнда. Поскольку у HAproxy есть проверки работоспособности, он может быстро определить, какие адреса активны, и использовать их.
Видеть https://stackoverflow.com/questions/1358198/nginx-removing-upstream-servers-from-pool для обсуждения того, как nginx и haproxy работают с апстримами.
Если вы не использовали для этого выделенную сеть докеров, вы мощь необходимо вручную управлять IP-адресами для ваших узлов php-fpm.
В случае, когда ваши контейнеры 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.
Хотя этот пост написан в 2015 году, и я чувствую, что некроу (извините, сообщество), я чувствую, что сейчас полезно добавить:
В настоящее время (и с тех пор, как упоминался Kubernetes), когда вы работаете с Docker, вы можете очень легко использовать Kubernetes или Docker Swarm для решения этой проблемы. Оба оркестратора будут принимать ваши узлы докеров (один узел = один сервер с Docker на нем), и вы можете развертывать для них службы, и они будут управлять проблемами портов для вас, используя наложения сетей.
Поскольку я больше разбираюсь в Docker Swarm, вот как вы можете подойти к этой проблеме (при условии, что у вас есть один узел Docker):
Инициализируем рой:
docker swarm init
cd в корень вашего проекта
cd some/project/root
создайте стек роя из вашего docker-compose.yml (вместо использования docker-compose):
docker stack deploy -c docker-compose.yml myApp
Это создаст стек службы docker swarm под названием «myApp» и будет управлять портами за вас. Это означает: вам нужно только добавить одно определение «порт: 9000: 9000» в свою службу php-fpm в файле docker-compose, а затем вы можете масштабировать службу php-fpm, скажем, до трех экземпляров, в то время как рой будет автоматически распределяет нагрузку между запросами между тремя экземплярами без каких-либо дополнительных действий.