前提と構成図
- ConoHa VPSを3台使用し、ロードバランサー1台、Webサーバ2台で構成します(下記の構成図を参照)。
- ロードバランサーとWebサーバの接続には、ConoHaのローカルネットワーク機能を使用します
- ロードバランサーにはHAProxyを使用し、いわゆるL7ロードバランサーとします
- HAProxyはHTTPリバースプロクシとして機能します。
- バックエンドのWebサーバはApacheで構築します。
1. 事前準備
1-1. ノートPCをWiFiに接続します
WiFiを搭載したノートPCをお持ちの方は、以下の情報でインターネットに接続してください。
SSID: (配布されている資料をご確認ください)
Password:(配布されている資料をご確認ください)
WiFiが使えない方で有線LANが使える方は、ケーブルをお貸ししますので、スタッフにお声がけください。(数に限りがあります)
2. 共通のサーバー設定
今回はVPSを3つ使うため、以降はそれぞれのVPSを LB, WEB1, WEB2 と呼びます。まずは、3台のサーバにローカルネットワークの設定を行っていきます。
2-1. VPS(サーバ)にログインします
SSHで3台のサーバにログインします。ターミナルを複数立ち上げるようにしてください。
もちろんタブ表示できるなら、それでもかまいません。
GNU screenやtmuxをお使いの方は、自慢のカスタマイズを披露してください:)
VPS詳細情報は以下のように確認できます。接続先IPアドレスの確認と、SSH秘密鍵のダウンロードを行ってください。ユーザ名は「root」です。
なお、ここでダウンロードできる秘密鍵は、ConoHaでVPSを作成したときに共通で使うものです。一度ダウンロードすれば、LB, WEB1, WEB2共通で使えます。
SSHの接続方法は、お使いのターミナルエミュレータによって違います。ConoHaではTeraTermとPoderosaについてガイドを用意しています。必要に応じて参照してください。
Mac OSXやLinuxなど、コマンドラインからsshコマンドを使用する場合は以下のようになります。(秘密鍵ファイルの名前をconoha.keyと仮定しています)
ssh -i conoha.key root@[接続先IPアドレス]
2-2. プロンプトを変更する
今回は3つのVPSを代わる代わる操作しますが、間違ったVPSを操作してしまうと大変です。最初にプロンプトを変更してみましょう。各サーバで以下のコマンドを実行してください。
LB
export PS1="[e[1;32m][u@LB]$[e[1;00m] "
WEB1
export PS1="[e[1;36m][u@WEB1]$[e[1;00m] "
WEB2
export PS1="[e[1;35m][u@WEB2]$[e[1;00m] "
こうすることでわかりやすくなりました。
2-3. ネットワークインターフェイスが追加されていることを確認します。
今回、ロードバランサーとWebサーバの間は、ローカルネットワークで接続します。念のため、サーバにネットワークインターフェイスが追加されていることを確認しましょう。
すべてのサーバで以下のコマンドを実行してください。
ip link
eth1が表示されればOKです。
3: eth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:3c:3b:71 brd ff:ff:ff:ff:ff:ff
valid_lft forever preferred_lft forever
2-4. eth1にネットワークの設定を行う
次に、ネットワークインターフェイスにIPアドレスを割り当てます。少し手順が長いので注意してください。
CentOSなので設定ファイルは/etc/sysconfig/network-scripts/の配下にあります。ifcfg-eth0をifcfg-eth1にコピーして、内容を編集します。以下の手順を実行してください。なお、ここではエディタとしてvimを使いますが、もちろん他のエディタでも問題ありません。
この作業もすべてのサーバで行います。
cd /etc/sysconfig/network-scripts
cp ifcfg-eth0 ifcfg-eth1
vim ifcfg-eth1
ファイル内容を下記に変更します。[IPアドレス]の部分には、サーバの役割毎に別々のIPアドレスを指定します。
DEVICE="eth1"
BOOTPROTO="none"
ONBOOT="yes"
TYPE="Ethernet"
IPADDR="[IPアドレス]"
NETMASK="255.255.255.0"
ローカルネットワーク用IPアドレス一覧
- LB 192.168.0.11
- Web1 192.168.0.12
- Web2 192.168.0.13
もしよくわからない方は、以下に編集後のファイルを用意したので参考にしてください。
設定ファイルを記述したらネットワークをリスタートします。
service network restart
これでIPアドレスが割り当てられています、確認してみましょう。ipコマンドに引数addrをつけると、インターフェイス毎にIPアドレスなどが表示されます。
ip addr
以下のようにinetのところにIPアドレスが表示されていればOKです。
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:3b:f6:31 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.12/24 brd 192.168.0.255 scope global eth1
inet6 fe80::f816:3eff:fe3b:f631/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
2-5. ローカルネットワークの疎通確認をする
ネットワークの設定はできました。ちゃんと通信できるでしょうか? おなじみのpingで確認してみましょう。
ping 192.168.0.11
ping 192.168.0.12
ping 192.168.0.13
LB, WEB1, WEB2、それぞれからpingを実行して、他のサーバに到達できることを確認してください。
3. Webサーバの設定をする
ここからはWEB1とWEB2のサーバ上で作業します。
3-1. Webサーバのインストール(Apache)
WEB1とWEB2にはApacheをインストールしてWebサーバとして機能させます。yumでインストールしますが、CentOSではApacheはhttpdと言う名前でインストールできます。以下のコマンドを実行してください。途中で Is this ok? と聞かれるのでy(Enter)と入力します。
yum install httpd
インストールが完了したら、httpdを起動します。
service httpd start
3-2. iptablesの設定
Webサーバとして使うため、もう一つ設定が必要です。iptablesの設定です。
CentOS 6.5はiptablesでパケットフィルタリングを行っています。デフォルトではHTTPで使うTCP 80番ポート宛ての通信は、すべてフィルタリングされます。
ポートを開放するにはiptablesの設定を変更します。設定ファイルは/etc/sysconfig/iptablesにあるので、エディタで編集します。
vim /etc/sysconfig/iptables
デフォルトでファイルの内容は以下のようになっています。
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT # <<<==== この行を追加 =====
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
「<<<==== この行を追加 =====」と書かれている行を追加して、ファイルを保存します。
そして、iptablesをリスタートして設定を反映させます。
service iptables restart
[補足]
今回の構成では、Webサーバにはローカルネットワークからのみ接続が来るため、iptablesでポートを開放する際には接続元をローカルネットワーク(192.168.0.0/24)に制限するべきです。今回は学習用であり、インターネット側からWeb表示を確認したいため、この制限は行いません。参考までに、接続元を制限する場合は、iptablesに-sオプションを付けて以下のようにします。
-A INPUT -m state --state NEW -m tcp -p tcp -s 192.168.0.0/24 --dport 80 -j ACCEPT
3-3. Web表示を確認する
さぁこれでWebサーバの設定が完了しました。ブラウザなどからhttp://[WEBサーバのIPアドレス]/にアクセスしてみましょう。Apacheの初期ページが表示されればOKです。
このままでも良いのですが、後ほどロードバランサーを組んだときのために、WEB1,WEB2のどちらにアクセスしているのかわかるようにしておきます。環境変数などを表示するPHPスクリプトを用意したので、ドキュメントルートに配置してください。
# ドキュメントルートに移動
cd /var/www/html/
# PHPスクリプトをダウンロード
wget https://gist.githubusercontent.com/ConoHa/fb7c783153a37c7a4882/raw/87ea58fb87f1fc7bb0c096b95fff212d9344a73f/index.php
# Apacheのサンプルファイルを削除
rm -f index.html
もう一度ブラウザなどからhttp://[WEBサーバのIPアドレス]/にアクセスしてみましょう。確認ページが表示されればOKです。
おつかれさまでした。以上でWEBサーバについては終了です。次はロードバランサーの設定ですよ。
4. ロードバランサーを設定する
それではいよいよロードバランサーを作っていきます。ここからの作業はLBに対して行います。
4-1. HAPxoryをインストールする
まずはHAProxyをインストールします。
yum install haproxy
これは問題ありませんね。
4-2. HAProxyを設定する
HAProxyの設定ファイルは/etc/haproxy配下にあるhaproxy.cfgです。既にファイルがありますが、これはサンプルファイルです。今回はこれをベースに設定を進めていきます。
vim /etc/haproxy/haproxy.cfg
設定後のファイルを以下に用意しました。60行目まではサンプルのままで、見ていただく部分は60行目以降です。
### ↓60行目以降↓
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend main *:80
# acl url_static path_beg -i /static /images /javascript /stylesheets
# acl url_static path_end -i .jpg .gif .png .css .js
# use_backend static if url_static
acl url_favicon path_end -i favicon.ico
use_backend blackhole if url_favicon
default_backend app
#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
#backend static
# balance roundrobin
# server static 127.0.0.1:4331 check
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
balance roundrobin
server app1 192.168.0.12:80 check weight 1
server app2 192.168.0.13:80 check weight 1
backend blackhole
errorfile 403 /dev/null
「frontend」の部分がインターネット側の設定、「backend」の部分がローカルネットワーク側です。ローカルネットワーク側は先ほど設定したWebサーバのIPアドレスが記述されています。roundrobinとあるので交互にトラフィックを振り分ける設定となっています。
設定の意味がわかったところで、ファイルを編集しましょう。サーバ上のファイルの60行目以降を、上の内容に置き換えてください。(vimでは :set nu[Enter] と叩くと行番行が表示されます)
編集が難しいという方は、以下のようにファイルをこちらで用意したものに置き換えてしまってもかまいません。
cd /etc/haproxy
rm -f haproxy.cfg
wget https://gist.githubusercontent.com/ConoHa/859f26b94cd2204adb0a/raw/6847c7724fd4dc3716b607a86406df8c05664dad/haproxy.cfg
4-3. iptablesの設定
今回の設定では、HAProxyもWebサーバと同じようにTCP 80番を待ち受けます。そのためWebサーバと同じようにiptablesの設定が必要です。また、後に出てきますがHAProxyの統計情報を見られる管理機能を使うため、10080番も開放します。手順や設定内容はWebサーバの時と同じです。
vim /etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT # <<<==== この行を追加 =====
-A INPUT -m state --state NEW -m tcp -p tcp --dport 10080 -j ACCEPT # <<<==== この行を追加 =====
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
指定の行を追加して、ファイルを保存します。そしてリスタートして設定を反映させます。
service iptables restart
4-4. HAProxyを起動します。
いよいよHAProxyを起動します。以下のコマンドを実行しましょう。
service haproxy start
起動しましたか? Webブラウザなどから http://(LBのIPアドレス)/ にアクセスしてみましょう。ページが表示されるはずです。
ページの最上部に「このサーバのアドレス」という項目があります。これがWebサーバのアドレスです。ローカルネットワーク上のWebサーバのアドレスが表示されていて、リロードする度にWEB1とWEB2のアドレスが、交互に表示されるはずです。ラウンドロビンでトラフィックが振り分けられているのがわかります。
もう一つの確認方法として、WEB1とWEB2で以下のコマンドを実行してみてください。Webサーバのアクセスログが表示されます。ブラウザをリロードする度に、交互にログが表示されることが確認できるはずです。
tail -f /var/log/httpd/access_log
tailコマンドを終了するには「Ctrl+C」と入力します。
4-5. ログを出す
これでとりあえず動くようにはなりました。実際の運用では「ではログを見てみましょう・・・」となるのですが、実は今の状態ではどこにもログは出力されていません。
正確には、haproxyデーモンはログを送信しています。ただ、CentOSのsyslogデーモンであるrsyslogがUDP 514ポートでの通信がOFFになっているため受け取れていません。この設定を変更します。
rsyslogの設定ファイルは/etc/rsyslog.confです。このファイルを編集します
vim /etc/rsyslog.conf
一つ目の変更箇所は12行目付近です。以下の2行のコメントを外します。この設定によりUDP 514をListenするようになります
変更前:
# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514
変更後:
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
もう一つはsyslogのファシリティに関する設定です。HAProxyはlocal2ファシリティで出力されるので、これを/var/log/haproxy.logに出力するようにします。ファイルの末尾に以下の一行を追加します。
local2.* /var/log/haproxy.log
変更したらrsyslogをリスタートします
service rsyslog restart
これでログが出力されるようになりました。ログは/var/log/messagesに出力されます。以下のコマンドを実行した後、Webブラウザをリロードしてみてください。ログが出てくるはずです
tail -f /var/log/haproxy.log
[参考]: 「ファシリティ」と言うのを聞いたことがない方もいらっしゃると思います。syslogにはファシリティ(facility)という仕組みがあり、これを元にログを分類します。たとえば認証関連のログはauthやauthprivというファシリティで出力されますし、カーネルのログはkernファシリティで出力されます。syslogデーモンはファシリティ毎に出力するログファイルを変更したり、別のホストに転送したりします。最近のOSはデフォルトでsyslogの設定が済んでいるものが多く、普段はあまり意識しない部分かもしれませんね。
4-6. 統計情報を見る
HAProxyにはWebブラウザから統計情報を見ることができる機能があります。ログももちろん重要ですが、ブラウザから確認できるお手軽さはとても便利です。
HAProxyの設定ファイルを変更します
vim /etc/haproxy/haproxy.cfg
最下行に以下の記述を追加してください
# 統計情報の確認画面を有効にする
# http://[VPSのIPアドレス]:10080/?hastats
listen hastats *:10080
mode http
maxconn 64
stats enable
stats show-legends
stats uri /?hastats
# IDとパスワード
stats auth admin:conoha
保存したら、HAProxyをリスタートします。
service haproxy restart
これで統計情報を確認できるようになりました。ブラウザから「http://[VPSのIPアドレス]:10080/?hastats」にアクセスしてみましょう
4-7. Webサーバがダウンしたとき(時間があれば)
今回はWebサーバを2台用意しましたが、もしWebサーバがダウンした場合どうなるのでしょうか? やってみましょう。どちらかのWebサーバで以下のコマンドを実行してみてください
service httpd stop
これはWebサーバを停止するコマンドです。2つあるWebサーバのうち、片方がダウンしたという想定です。この状態でブラウザをリロードしてみてください。問題なく表示されているはずです。
HAProxyのログを見ると、Webサーバがダウンしたことを検知しています。HAProxyがダウンしたホストを切り離して、残りのホストだけにトラフィックを流しているのです。
Dec 10 17:41:43 localhost haproxy[5813]: Server app/app2 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 2ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
Webサーバを復旧してみましょう。先ほどと同じWebサーバで以下のコマンドを実行してみてください。
service httpd start
HAProxyのログを見ると、復旧を検知して再びラウンドロビンの動作に戻ります。
Dec 10 17:45:07 localhost haproxy[5813]: Server app/app2 is UP, reason: Layer4 check passed, check duration: 1ms. 2 active and 0 backup servers online. 0 sessions requeued, 0 total in queue.
なるほど、挙動はわかりました。さてここで、もう一度HAProxyの設定ファイルを見てみましょう。
backend app
balance roundrobin
server app1 192.168.0.12:80 check weight 1
server app2 192.168.0.13:80 check weight 1
何気なく設定していましたが、この「check」というのはヘルスチェックを行うという意味です。この設定を入れておくだけで、HAProxyがバックエンドサーバに対して定期的(デフォルト1秒)にTCP接続を行い、死活監視を行ってくれます。
なお、WebサーバではTCP接続ができただけでは、充分な死活監視ができない場合があります。接続ができても過負荷で500 Internal Server Errorになっている場合もあれば、デプロイのミスで404 Not Foundになっているかもしれません。HAProxyは設定を変更することで、HTTPでのコンテンツ取得までを死活監視に含めることもできます。今回はここまでは扱いませんが、興味のある方はマニュアルなどを調べてみてください。
4-8. バランス方法を変更する(時間があれば)
「バランス」というのは、複数あるバックエンドサーバに対しHAProxyがどのように通信を割り振るかを決定するロジックです。設定ファイル上は「balance」というディレクティブがあります(下記参照)。今の設定は「ラウンドロビン」となっていて、これはバックエンドサーバを順に選択していくというものです。また重み付けの機能や、死活監視を行いダウンしたホストの切り離し、復旧を自動で行ってくれる機能があります。
backend app
balance roundrobin
server app1 192.168.0.12:80 check weight 1
server app2 192.168.0.13:80 check weight 1
多くのケースでラウンドロビンは有用です。ただHAProxyは他のバランス方法もサポートしています。sourceというバランスを試してみましょう。この方法は接続元IPアドレスに応じて、振り分けるバックエンドサーバが変わるものです。つまり、同じ接続元なら常に同じバックエンドサーバに割り振られると言うことです。
では設定ファイルを編集します
vim /etc/haproxy/haproxy.cfg
balanceの設定を以下のように変更しましょう。
balance source
ファイルを変更したら保存して、haproxyをリロードします
service haproxy reload
それでは確認してみます。WEB1とWEB2で以下のコマンドを実行してみてください。Webサーバのアクセスログが表示されます。今までは交互にログが表示されていましたが、片方にしかログが出ていないはずです。
tail -f /var/log/httpd/access_log
この方式ですが、よくあるセッション管理が必要なWebアプリケーションで有用なことがあります。PHPなどはデフォルトでセッション管理をファイルベースで行います。つまりサーバ毎にローカルなセッション管理です。このようなケースでは、リクエストの度に別のバックエンドに割り振られると、セッション管理が行えなくなってしまうのです。(もちろん、設定などでセッション情報を共有することもできますが、一例として)
おわりに
以上でハンズオンの手順はすべて完了です。おつかれさまでした!