web-dev-qa-db-ja.com

Docker-nginxとphp-fpmを別々にスケーリングする

私は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

アプリには、ポート9000のphp-fpmと私のアプリケーションコードが含まれています。 Webはnginxで、いくつかの構成が含まれています。

これは、私が期待するように機能しますが、nginxをphp-fpmに接続するには、次の行を使用します。

fastcgi_pass    app:9000;

これを効果的にスケーリングするにはどうすればよいですか?たとえば、1つのnginxコンテナーを実行し、3つのアプリコンテナーを実行したい場合は、3つのphp-fpmインスタンスがすべてポート9000でリッスンしようとしていることを確認します。

どのようにして各php-fpmインスタンスを別のポートに置くことはできますが、それらがいつでも私のnginx構成のどこにあるかを知ることができますか?

私は間違ったアプローチを取っていますか?

ありがとう!

11
JimBlizz

1つの解決策は、追加の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 configとdocker-compose.ymlを変更する必要があるため、これは実際には理想的ではありません。

9000ポートはコンテナーの内部であり、実際のホストではないため、ポート9000に複数のphp-fpmコンテナーがあることは問題ではありません。

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

Tutumは現在有料サービスです。 Rancherは、同様の負荷分散機能を提供するオープンソースプロジェクトです。また、Docker-compose.ymlでサービスセットアップの負荷分散とスケーリングを定義できる「rancher-compose.yml」もあります。 http://rancher.com/the-magical-moment-when-container-load-balancing-meets-service-discovery/http://docs.rancher.com/rancher/concepts /#load-balancer

UPDATE 2017/03/06:私は interlock と呼ばれるプロジェクトを使用しました。これはDockerと連携してnginx設定を自動的に更新し、再起動します。 @iwaseatenbyagrueの answer も参照してください。これには追加のアプローチがあります。

5
rmarscher

ここで説明するように、アップストリームを使用して複数のバックエンドを定義できます。

https://stackoverflow.com/questions/5467921/how-to-use-fastcgi-next-upstream-in-nginx

また、次のような新しいバックエンドが停止またはサービスに入るたびに、構成を更新する必要があります。

https://github.com/kelseyhightower/confd

1
smaj

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は、インターフェースdocker0上のホストのIPアドレスです。

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
xuhdev

別のアプローチは、 consul-template のようなものを調べることです。

そしてもちろん、ある時点で Kubernetes について言及する必要があるかもしれません。

ただし、Dockerイベントを使用して何ができるかを調べることで、少し文字列とダクトテープのアプローチを検討できます(簡単なサンプルの場合はdocker events --since 0を実行してください)。

これらのイベントを確認するスクリプト(python、goなどを含むいくつかのクライアントパッケージが利用可能であることを念頭に置いてください)、構成ファイルを修正し、nginxを再読み込みする(つまり、consul-templateアプローチを使用する)ことは、かなり簡単です。領事は必要ありません)。

ただし、元の前提に戻るには、php-fpmコンテナーが独自のネットワークで開始されている限り(つまり、nginxのような別のコンテナーのネットワークを共有していない場合)、ポートでリッスンするコンテナーをいくつでも持つことができます。必要に応じて9000-コンテナごとのIPがあるため、ポートの「衝突」の問題はありません。

これをどのようにスケーリングするかは、最終的な目標やユースケースによって異なりますが、検討する必要があるのは、nginxとphp-fpmノードの間にHAproxyを配置することです。これにより、php-fpmサーバー(つまり172.18.0.0/24)の範囲を指定し(場合によってはdocker networkを作成し)、HAproxyを設定して、バックエンドとしてのその範囲。 HAproxyはヘルスチェックを備えているため、どのアドレスがライブであるかをすばやく特定し、それらを利用できます。

Nginxとhaproxyがアップストリームをどのように処理するかについての議論は https://stackoverflow.com/questions/1358198/nginx-removing-upstream-servers-from-pool を参照してください。

これに専用のDockerネットワークを使用していない限り、php-fpmノードの手動IP管理をmightする必要があります。

0

この投稿は2015年のものであり、私はネクロイングしているように感じます(ごめんなさいコミュニティ)、この時点で追加することは貴重だと感じています。

今日(そしてKubernetesが言及されて以来)、Dockerを使用しているときは、KubernetesまたはDocker Swarmを非常に簡単に使用してこの問題を解決できます。両方のオーケストレーターがDockerノード(1つのノード= Dockerを搭載した1つのサーバー)を取り込み、それらにオーケストレーターをデプロイして、オーバーレイネットワークを使用してポートの課題を管理します。

私はDocker Swarmに精通しているので、次の方法でこの問題に対処します(単一のDockerノードがあると想定しています)。

スウォームを初期化します。

docker swarm init

プロジェクトルートにcdします。

cd some/project/root

(docker-composeを使用する代わりに)docker-compose.ymlからスウォームスタックを作成します。

docker stack deploy -c docker-compose.yml myApp

これにより、「myApp」と呼ばれるdocker swarmサービススタックが作成され、ポートが管理されます。つまり、docker-composeファイルのphp-fpmサービスに "port:9000:9000"定義を1つ追加するだけで、php-fpmサービスを3つのインスタンスに拡張できます。 3つのインスタンス間でリクエストを自動的に負荷分散し、追加の作業は必要ありません。

0
Worp