HAProxyをkeepalivedで冗長化

=========================

## 環境

- CentOS 6.5 or Ubuntu 14.04 Trusty

## Overview

HAProxyをkeepalivedで冗長化したい。

## Install

2014/11現在yumからインストール出来るHAProxyはまだ1.4系のためSSLに対応していないので、SSL対応済みの最新版ソースからインストールします。Ubuntuは既に1.5系が使えるのでパッケージマネージャから入れても大丈夫です。

### HAProxy

- 依存パッケージインストール

RHEL系の場合

```
yum install openssl-devel pcre-devel make gcc socat
```

Debian系の場合

```
apt-get install build-essential socat zlib1g-dev libpcre3-dev libssl-dev
```

- HAProxy用ユーザの作成

```
useradd haproxy -s /sbin/nologin
```

- ソースDL

```
curl -L -O http://www.haproxy.org/download/1.5/src/haproxy-1.5.8.tar.gz
```

- 解凍 & make & make install

```
tar xvf haproxy-1.5.8.tar.gz
cd haproxy-1.5.8
make TARGET=linux2628 CPU=x86_64 USE_OPENSSL=1 USE_ZLIB=1 USE_PCRE=1
make install
```

`USE_OPENSSL`でSSLを有効にしています

- HAProxyのフォルダを作成

```
mkdir /var/lib/haproxy
mkdir /etc/haproxy
```

- HAProxyの実行ファイルをパスが通るところにコピー

```
cp /usr/local/sbin/haproxy* /usr/sbin/
```

- initスクリプトを作成(RHEL系)

CentOSはサンプルのinitスクリプトをコピーするだけでOKです。

```
cp examples/haproxy.init /etc/init.d/haproxy
```

- initスクリプトを作成(Debian系)

Ubuntuはサンプルのinitスクリプトでは動かなかったのでUbuntu用のinitスクリプトを作成します。

```
curl -L -o /etc/init.d/haproxy http://efemoral.lovius.net/wp-content/uploads/2013/02/init.d.haproxy.txt
```

参照: http://efemoral.lovius.net/wp-content/uploads/2013/02/init.d.haproxy.txt

- 実行権限を与える

```
chmod +x /etc/init.d/haproxy
```

- HAProxyの設定を作成

```
global
    daemon
    maxconn 50000
    stats socket /var/lib/haproxy/haproxy.sock mode 0600 level admin
defaults
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend front_in
    bind 192.168.40.100:80
    ##  SSL binding ##
    # bind 192.168.40.100:443 ssl crt /etc/ssl/certs/server.pem
    maxconn 30000
    default_backend ju_backend

backend ju_backend
    mode http
    ##  Force SSL ##
    # redirect scheme https if !{ ssl_fc }
    balance roundrobin
    server s1 192.168.40.10:8080 maxconn 30000 check inter 2000 rise 2 fall 5
    server s2 192.168.40.11:8080 maxconn 30000 check inter 2000 rise 2 fall 5
    option forwardfor

listen stats :8181
   mode http
   stats enable
   stats realm Haproxy\ Statistics
   stats uri /
   stats auth haproxy:ju
```

解説: `stats`で`hatop`や`socat`等外部ツールから操作するためのソケットファイルを作成しています。`front_in`でVIP`192.168.40.100`の80番に来たリクエストをbackendの`ju_backend`の`server s1`、`server s1`の8080番にそれぞれ`roundrobin`方式で均等に割り振っています。

- VIPにbind出来るようカーネルパラメータを変更

```
sysctl -w net.ipv4.ip_nonlocal_bind=1
```

- HAProxyを有効にする(Debian系)

```
echo "ENABLED 1" > /etc/default/haproxy
```

- HAproxy起動

```
service haproxy start
chkconfig haproxy on
```

### keepalived

- レポジトリからインストール

RHEL系

```
yum install keepalived
```

Debian系

```
apt-get install keepalived
```

- 設定ファイル作成

/etc/keepalived/keepalived.confに

```/etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
}

vrrp_script chk_haproxy {
   script "killall -0 haproxy"   # verify the pid existance
   interval 2                    # check every 2 seconds
   weight 2                      # add 2 points of prio if OK
}

vrrp_instance VI_1 {
   interface eth1                # interface to monitor
   state MASTER
   virtual_router_id 51          # Assign one ID for this route
   priority 100                  # 101 on master, 100 on backup
   virtual_ipaddress {
       192.168.34.100            # the virtual IP
   }
   track_script {
       chk_haproxy
   }
}
```

を書き込みます。

解説: HA構成を組むクラスタで`virtual_router_id`の値は同じにし、`priority`の値はアクティブ側とスタンバイ側で別の値にしています。値が高いほうにVIPが割り当てられます。
`killall -0 haproxy`は`-0`を付けているのでプロセスは殺さず、プロセスが存在するかのみ確認だけしています。haproxyが稼働していなければスタンバイ側にVIPが引き継がれます。

## Ansible

上記手順はAnsible playbookとしても公開しています。

https://github.com/shufo/ansible-haproxy-keepalived

```
git clone git@github.com:shufo/ansible-haproxy-keepalived.git
```

でソースを落としてvagrant仮想マシン起動

```
vagrant up
```

でHA構成のHAProxyが2台立ち上がり動作確認することが出来ます。

```
$ vagrant ssh haproxy1
Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-39-generic x86_64)

〜中略〜

$ curl http://192.168.40.100/

<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>

↑まだbackendに何もサービスを起動していないので503として返されます。
```

リモートのサーバに対して適用する場合は`ansible_hosts`ファイルを編集し

```ansible_hosts
default ansible_ssh_host=xxx.xxx.xxx.xxx ansible_ssh_port=22
```

playbookを直接実行してください。

```
ansible-playbook site.yml -i ansible_hosts
```


### hatop

HAProxyをインタラクティブに操作出来る[hatop](http://feurix.org/projects/hatop/)を起動してみます。

```
$ hatop -s /var/lib/haproxy/haproxy.sock

 HATop version 0.7.7                                                                                                                                                           Thu Nov  6 07:20:42 2014 

  HAProxy Version: 1.5.8  (released: 2014/10/31)        PID: 7021 (proc 1)

         Node: haproxy1 (uptime 0d 0h29m09s)

        Pipes: [                                                       0/0]
  Connections: [                                                   0/50000]

  Procs:   1   Tasks:     8    Queue:     1    Proxies:   3   Services:    6

NAME                                W STATUS           CHECK                       ACT           BCK            QCUR            QMAX             SCUR             SMAX             SLIM             STOT

>>> front_in                                                                                                                                                                                            
FRONTEND                            0 OPEN                                           0             0               0               0                0                0            30000                0

>>> ju_backend                                                                                                                                                                                          
s1                                  1 DOWN             L4CON                         1             0               0               0                0                0            30000                0
s2                                  1 DOWN             L4CON                         1             0               0               0                0                0            30000                0
BACKEND                             0 DOWN                                           0             0               0               0                0                0             3000                0

>>> stats                                                                                                                                                                                               
FRONTEND                            0 OPEN                                           0             0               0               0                0                0             2000                0
BACKEND                             0 UP                                             0             0               0               0                0                0              200                0
```

`ju_backend`内がどちらもDOWNしていることが分かります。
該当するサーバをカーソルで選び


|キー|操作|
|--:|:--|
|F4|Weightリセット|
|F5|Weight -10|
|F6|Weight -1|
|F7|Weight +1|
|F8|Weight +10|
|F9|有効化|
|F10|無効化|

でインタラクティブにバランシングを変更出来ます。