はじめに
本投稿はこちらの投稿の続編にあたります。
ソースや設定ファイルは差分の表記となりますので、ベースとなる成果物についての説明は本投稿においては割愛します。下記を参照願います。
目的
NGINXのロードバランサ機能の概要を理解、および、構築ができるようになる。
背景
参画したシステムではほぼ必ずと言っていいほどロードバランサの構成が取られていたが、インフラ側の構築経験がなかったため、自分で構築を体験してみたかった。NGINXを利用したWebサーバ構築を前回投稿していたため、そのソースコードを活用し知識を得ることができないかと思い、構築、投稿するに至った。
ロードバランサとは
負荷分散をする機能のことを言います。
負荷分散をすることにより以下を得ることができます。
- サーバリソース使用率の最適化
- スループットの最大化
- レイテンシーの低減
- 耐障害性の向上
NGINXのロードバランサ機能には以下の分散方式が用意されています。
- round-robin
リクエストをノード1つ1つに対し順番振り分けます。 - least-connected
リクエストをアクティブ、かつ、接続数が最も少ないノードに振り分けます。 - ip-hash
クライアントのIPアドレスと接続先ノードを紐付け、クライアントのリクエストを常に同じノードへ振り分けます。
振り分けに関しては、細かな設定も用意されています。詳細は公式ドキュメントを参照願います。
全体像
環境
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
で設定ファイルが入っているディレクトリをマウントするようにしていましたが、これをファイルコピーに変更しました。(どちらでもよかったですが、なんとなくこっちにしました)。
設定ファイルの説明は後述します。
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
に移行のため削除しました。
FROM tomcat:latest
- EXPOSE 8080
Tomcat-2
Tomcatの設定で指定しているデフォルトのポート8080から8081に修正しました。
編集済みファイルをコピーする選択肢もありましたが、sedで済ませました。
FROM tomcat:latest
RUN sed -i 's/Connector port="8080"/Connector port="8081"/' /usr/local/tomcat/conf/server.xml
Tomcat-3
Tomcat-2
と同様に8082ポートに修正しました。
FROM tomcat:latest
RUN sed -i 's/Connector port="8080"/Connector port="8082"/' /usr/local/tomcat/conf/server.xml
NGINX設定を修正
upstream apps
がロードバランサで振り分けられる先の指定となります。
IPアドレスは環境に合わせ修正してください。
振り分け先以外、特に指定がなければラウンドロビンが指定されます。今回はラウンドロビン設定で進めます。
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
で定義した分散先となるよう修正します。
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アプリのコンテンツの例です。()の中の番号がそれぞれ変わります。
<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が表示されます。
ちゃんと分散されてますね。
コンテナの起動を終了
% docker-compose down
最後に
業務で構築していたものはもっと高度なものだったかもしれないが、ロードバランサを構築するという目的は達成できた。
疑問に思ったのは、今回は振り分け先が3ノードだったため設定ファイルを書き換えることで対応したが、大量アクセスを想定し大量のノードを構築する場合、ポート等、ノードごとで固有の設定はどうやって効率よく設定ができるのだろうと思った。何かループ処理や変数などのロジックを組み込めるのか、最適なやり方があれば今後の課題としてクリアにしておきたい。