1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NGINXで構築したWebサーバにロードバランサ機能を設定する。

Posted at

はじめに

本投稿はこちらの投稿の続編にあたります。
ソースや設定ファイルは差分の表記となりますので、ベースとなる成果物についての説明は本投稿においては割愛します。下記を参照願います。

目的

NGINXのロードバランサ機能の概要を理解、および、構築ができるようになる。

背景

参画したシステムではほぼ必ずと言っていいほどロードバランサの構成が取られていたが、インフラ側の構築経験がなかったため、自分で構築を体験してみたかった。NGINXを利用したWebサーバ構築を前回投稿していたため、そのソースコードを活用し知識を得ることができないかと思い、構築、投稿するに至った。

ロードバランサとは

負荷分散をする機能のことを言います。
負荷分散をすることにより以下を得ることができます。

  • サーバリソース使用率の最適化
  • スループットの最大化
  • レイテンシーの低減
  • 耐障害性の向上

NGINXのロードバランサ機能には以下の分散方式が用意されています。

  • round-robin
    リクエストをノード1つ1つに対し順番振り分けます。
  • least-connected
    リクエストをアクティブ、かつ、接続数が最も少ないノードに振り分けます。
  • ip-hash
    クライアントのIPアドレスと接続先ノードを紐付け、クライアントのリクエストを常に同じノードへ振り分けます。

振り分けに関しては、細かな設定も用意されています。詳細は公式ドキュメントを参照願います。

全体像

今回はこんな構成です。
image.png

環境

os: macOS Monterey 12.5
machine: MacBook Air(Retina, 13-inch, 2018)
cpu: 1.6GHz デュアルコアIntel Core i5

Dockerデスクトップをインストール済みです。

% brew list --version | grep docker
docker 4.11.1,84025

今回のファイル

内容

以降は、リポジトリのv1タグをベースに修正点の説明をしていきます。

自身で動作させたい場合、リポジトリクローン後、本投稿の修正内容が反映されているv2タグをチェックアウトし、NGINX設定を修正セクションで説明しているnginx-server/nginx.confの振り分け先IPアドレスを環境に合わせるだけで後は手順通りに動かせます。

Dockerfileの作成、修正

NGINX

ポートの指定はdocker-compose.xmlに移行のため削除しました。
docker-compose.xmlで設定ファイルが入っているディレクトリをマウントするようにしていましたが、これをファイルコピーに変更しました。(どちらでもよかったですが、なんとなくこっちにしました)。
設定ファイルの説明は後述します。

nginx-server/Dockerfile
FROM nginx:latest

- EXPOSE 80
- 
- RUN rm -rf /etc/nginx/conf.d
+ RUN rm -f /etc/nginx/conf.d/*
+ COPY conf.d/nginx.conf /etc/nginx/conf.d
+ COPY nginx.conf /etc/nginx

Tomcat-1

ポートの指定はdocker-compose.xmlに移行のため削除しました。

tomcat-server1/Dockerfile
FROM tomcat:latest

- EXPOSE 8080

Tomcat-2

Tomcatの設定で指定しているデフォルトのポート8080から8081に修正しました。
編集済みファイルをコピーする選択肢もありましたが、sedで済ませました。

tomcat-server2/Dockerfile(新規作成)
FROM tomcat:latest

RUN sed -i 's/Connector port="8080"/Connector port="8081"/' /usr/local/tomcat/conf/server.xml

Tomcat-3

Tomcat-2と同様に8082ポートに修正しました。

tomcat-server3/Dockerfile(新規作成)
FROM tomcat:latest

RUN sed -i 's/Connector port="8080"/Connector port="8082"/' /usr/local/tomcat/conf/server.xml

NGINX設定を修正

upstream appsがロードバランサで振り分けられる先の指定となります。
IPアドレスは環境に合わせ修正してください。
振り分け先以外、特に指定がなければラウンドロビンが指定されます。今回はラウンドロビン設定で進めます。

nginx-server/nginx.conf(新規作成)
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    upstream apps {
        server 192.168.x.x:8080;
        server 192.168.x.x:8081;
        server 192.168.x.x:8082;
    }

    include /etc/nginx/conf.d/*.conf;
}

リクエスト分散するため、URLの直接指定からnginx-server/nginx.confで定義した分散先となるよう修正します。

nginx-server/conf.d/nginx.conf
server {
    listen 80;
    server_name localhost;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    location / {
-       proxy_pass http://192.168.x.x:8080;
+       proxy_pass http://apps;
        # proxy_pass http://host.docker.internal:8080;
    }
}

コンテンツをアプリごとに用意

tomcat-server-1,2,3それぞれにコンテンツを用意します。
リクエストした際にどのノードにアクセスしたかわかるよう、番号を変えるようにします。
以下はtomcat-server-1アプリのコンテンツの例です。()の中の番号がそれぞれ変わります。

tomcat-server1/webapps/sample/sample.html
<h1>hello sample.html (1)</h1>

docker-compose.ymlの修正

サービスごとに説明します。

  • nginx-server
    NGINXのDockerfileにて設定ファイルをコピーするように修正したため、ボリュームに指定していた設定ファイルが配置されているディレクトリconf.dを外してます。
    ポートの指定は本ファイルの定義に集約するようにしたため80ポートの指定を追加しています。
  • tomcat-server-1,2,3
    基本的には同じ構成となります。特に説明を入れるところはないので、ソース差分のみ掲載とします。
version: "3"
services:
    nginx-server:
        build:
            context: ./nginx-server
        volumes:
-           - ./nginx-server/conf.d:/etc/nginx/conf.d
            - ./nginx-server/log:/var/log/nginx
+       expose:
+           - 80
        ports:
            - 80:80

-   tomcat-server:
+   tomcat-server-1:
        build:
-           context: ./tomcat-server
+           context: ./tomcat-server1
        volumes:
-           - ./tomcat-server/webapps:/usr/local/tomcat/webapps
-           - ./tomcat-server/log:/usr/local/tomcat/logs
+           - ./tomcat-server1/webapps:/usr/local/tomcat/webapps
+           - ./tomcat-server1/log:/usr/local/tomcat/logs
+       expose:
+           - 8080
        ports:
            - 8080:8080
+   tomcat-server-2:
+       build:
+           context: ./tomcat-server2
+       volumes:
+           - ./tomcat-server2/webapps:/usr/local/tomcat/webapps
+           - ./tomcat-server2/log:/usr/local/tomcat/logs
+       expose:
+           - 8081
+       ports:
+           - 8081:8081
+
+   tomcat-server-3:
+       build:
+           context: ./tomcat-server3
+       volumes:
+           - ./tomcat-server3/webapps:/usr/local/tomcat/webapps
+           - ./tomcat-server3/log:/usr/local/tomcat/logs
+       expose:
+           - 8082
+       ports:
+           - 8082:8082

コンテナをビルド

% docker-compose build

コンテナを起動

% docker-compose up -d

実行結果

http://localhost/sample/sample.htmlへアクセスを行い、3つのノードが順番にアクセスされるかを検証してみます。
リロードをするたびにリクエスト先のHTMLが表示されます。
image.png
image.png
image.png
ちゃんと分散されてますね。

コンテナの起動を終了

% docker-compose down

最後に

業務で構築していたものはもっと高度なものだったかもしれないが、ロードバランサを構築するという目的は達成できた。

疑問に思ったのは、今回は振り分け先が3ノードだったため設定ファイルを書き換えることで対応したが、大量アクセスを想定し大量のノードを構築する場合、ポート等、ノードごとで固有の設定はどうやって効率よく設定ができるのだろうと思った。何かループ処理や変数などのロジックを組み込めるのか、最適なやり方があれば今後の課題としてクリアにしておきたい。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?