↓ のニュースを見て面白そうだったので遊んでみました。
GoogleがロードバランサーSeesawをオープンソース化(Go言語で書かれている)
まだドキュメントが心もとないので、ソースを斜め読みしながら設定しました。
https://github.com/google/seesaw
試した環境は CentOS 7.2 on vSphere ESXi です。せっかくなのでメモとして残しておきます。
構成
既存のテスト環境に入れているので、アドレスは適当です。
* Seesaw は node01 にインストール
* node01 のインタフェースは IPアドレスを振った方が Node用で、無い方が LB の VIP用
* Requirement には Node のインタフェースは2つで、いずれも同じ L2 セグメントにするように書かれている
* VIP は 192.168.37.200
* client, server ともに同じセグメントで DSR 構成
+--------------+
| |
| node01 |
192.168.37.0/24 | |
+--------------+
.76| | <== (プロセスが起動するとここに .200 が来る)
eno16777728 eno33554960
| |
+--------------------------------------------------+
| | |
.172| .71| |.72
+--------+ +-----------+ +-----------+
| client | | backend01 | | backend02 |
+--------+ +-----------+ +-----------+
ソースの最新コミットは df04a7468ba6a2cacdcc771c05833b18cf3b07ff でした。
ここではエニーキャストには触れません。
インストール
README は Debian/Ubuntu での例でしたが、個人的に慣れている CentOS でいきます。
## テストなので・・・
# setenforce 0
## 必要なものを準備
# yum install -y git golang protobuf-compiler libnl3-devel
## パスは適当、root で作業しても気にしない
# mkdir go
# export GOPATH=/root/go
# go get -u golang.org/x/crypto/ssh
# go get -u github.com/dlintw/goconf
# go get -u github.com/golang/glog
# go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
# go get -u github.com/miekg/dns
## ビルドしてみる
# export PATH=$PATH:${GOPATH}/bin
# go get -u github.com/google/seesaw
# cd /root/go/src/github.com/google/seesaw/
# make test
# make install
## README のやり方だと Upstart 用の設定があるのでそこだけ飛ばす
# SEESAW_BIN="/usr/local/seesaw"
# SEESAW_ETC="/etc/seesaw"
# SEESAW_LOG="/var/log/seesaw"
# install -d "${SEESAW_BIN}" "${SEESAW_ETC}" "${SEESAW_LOG}"
# install "${GOPATH}/bin/seesaw_cli" /usr/bin/seesaw
# for component in {ecu,engine,ha,healthcheck,ncc,watchdog}; do
install "${GOPATH}/bin/seesaw_${component}" "${SEESAW_BIN}"
done
# install "etc/seesaw/watchdog.cfg" "${SEESAW_ETC}"
# /sbin/setcap cap_net_raw+ep "${SEESAW_BIN}/seesaw_ha"
# /sbin/setcap cap_net_raw+ep "${SEESAW_BIN}/seesaw_healthcheck"
設定ファイル
よく分かっていないながらも、それっぽい設定ファイルを書きます。
config_server に何も無いと seesaw-config.example.com を参照してしまうようなので、別の設定を書いて hosts で解決できるようにして止めておきます。
[cluster]
anycast_enabled = false
name = test
node_ipv4 = 192.168.37.76
## peer_ipv4 は、ここでは存在しない 2台めの Seesaw ノード用
#peer_ipv4 = 192.168.37.77
## vip_ipv4 はここの構成だと意味がなさそうだが、入れておかないと動かない
vip_ipv4 = 192.168.37.80
[config_server]
## example では URL になっているけど、違うかも
## とりあえず仮で埋めておく
primary = https://seesaw-config.localdomain/
[interface]
node = eno16777728
lb = eno33554960
127.0.0.1 seesaw-config.localdomain
セグメントを分けるのが面倒だったので DSR 構成で試します。
バックエンドは適切に設定してあるものとします。
seesaw_vip: <
fqdn: "seesaw-vip.localdomain."
ipv4: "192.168.37.80/24"
status: TESTING
>
node: <
fqdn: "node01.localdomain."
ipv4: "192.168.37.76/24"
status: TESTING
>
#node: <
# fqdn: "node02.localdomain."
# ipv4: "192.168.37.77/24"
# status: TESTING
#>
vserver: <
name: "test-vserver"
entry_address: <
fqdn: "lb-test.localdomain."
ipv4: "192.168.37.200/24"
status: TESTING
>
rp: "admin@localdomain"
vserver_entry: <
protocol: TCP
port: 80
scheduler: RR
healthcheck: <
type: HTTP
port: 80
mode: DSR
proxy: false
tls_verify: false
>
>
backend: <
host: <
fqdn: "backend01.localdomain."
ipv4: "192.168.37.71/24"
status: TESTING
>
weight: 1
>
backend: <
host: <
fqdn: "backend02.localdomain."
ipv4: "192.168.37.72/24"
status: TESTING
>
weight: 1
>
>
Seesaw を実行
/usr/local/seesaw/seesaw_watchdog
を実行して、動かしてみましょう。
フォアグラウンドでプロセスが残ります。ログを確認してみます。
F0131 18:57:34.972241 5389 ipvs.go:40] IPVS initialisation failed: failed to resolve family name
どうやら正しく動いていません。
自分で ip_vs モジュールをロードしておく必要があるようです。
# echo ip_vs > /etc/modules-load.d/ipvs.conf
# systemctl restart systemd-modules-load.service
あらためて起動。
F0131 19:38:11.393617 20543 core.go:274] Failed to initialise LB interface: Failed to initialise sysctls: open /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established: no such file or directory
別のログファイルにエラーが出ています。
さらにモジュールをロードします。
# echo nf_conntrack_ipv4 > /etc/modules-load.d/nf_conntrack.conf
# systemctl restart systemd-modules-load.service
3度目のトライ。
F0131 20:03:08.723735 1775 core.go:274] Failed to initialise LB interface: Failed to get dummy interface: no such network interface
まだ怒られますね。
どうやら DummyInterface が無いのが問題なようです。ソース中のデフォルトインタフェース名は dummy0 のようで、設定ファイルから変更できるか分からないので、名前を合わせて作ってみます。
# ip link add dummy0 type dummy
そして起動。
F0201 08:55:13.497926 18909 core.go:607] Failed to bring LB interface up: Failed to get IPv4 default route: Default route not found
今度は、以下のあたりで問題になっています。
40 routeDefaultIPv4Regexp = regexp.MustCompile(
41 `^default via (\d+\.\d+\.\d+\.\d+) dev ([a-z]+[0-9]) `)
264 if dr := routeDefaultIPv4Regexp.FindStringSubmatch(out); dr != nil {
265 return net.ParseIP(dr[1]).To4(), nil
266 }
267 return nil, fmt.Errorf("Default route not found")
私の環境だと eno16777728 のようになっているため、NIC の名前が合っていません。仕方ないのでソースに手を加えてビルドし直します。
デフォルトルートが Seesaw ノードに設定されていなくてもエラーになるようなので、未設定の場合は設定しておきます。
--- ncc/ip.go.org 2016-01-31 07:17:00.039679149 +0900
+++ ncc/ip.go 2016-02-01 11:44:38.874337074 +0900
@@ -38,7 +38,7 @@
ifaceNameRegexp = regexp.MustCompile(`^\w+\d+(\.\d+)?$`)
ipv6AddrRegexp = regexp.MustCompile(`^\s*inet6 ([a-f0-9:/]+) .*$`)
routeDefaultIPv4Regexp = regexp.MustCompile(
- `^default via (\d+\.\d+\.\d+\.\d+) dev ([a-z]+[0-9]) `)
+ `^default via (\d+\.\d+\.\d+\.\d+) dev ([a-z]+[0-9]+) `)
)
// validateInterface validates the name of a network interface.
影響範囲が分からないのでバイナリは全て install し直します。
# cd $GOPATH/src/github.com/google/seesaw
# make install
## 環境変数は前に設定したものが残っている想定
# install "${GOPATH}/bin/seesaw_cli" /usr/bin/seesaw
# for component in {ecu,engine,ha,healthcheck,ncc,watchdog}; do
install "${GOPATH}/bin/seesaw_${component}" "${SEESAW_BIN}"
done
# install "etc/seesaw/watchdog.cfg" "${SEESAW_ETC}"
# /sbin/setcap cap_net_raw+ep "${SEESAW_BIN}/seesaw_ha"
# /sbin/setcap cap_net_raw+ep "${SEESAW_BIN}/seesaw_healthcheck"
改めて /usr/local/seesaw/seesaw_watchdog
を起動すると、ついに動きました。
動作確認
## backend で指定したサーバにヘルスチェックが来ています
# tail -f /var/log/nginx/access.log ## backend01
192.168.37.76 - - [01/Feb/2016:12:48:35 +0900] "GET / HTTP/1.1" 200 3700 "-" "Go 1.1 package http" "-"
# tail -f /var/log/nginx/access.log ## backend02
192.168.37.76 - - [01/Feb/2016:12:48:36 +0900] "GET / HTTP/1.1" 200 3700 "-" "Go 1.1 package http" "-"
## client (192.168.37.172) から GET してみると、round robin されました
# curl http://192.168.37.200/hogehoge > /dev/null ## from client
# curl http://192.168.37.200/hogehoge > /dev/null ## from client
# grep hogehoge /var/log/nginx/access.log ## backend01
192.168.37.172 - - [01/Feb/2016:13:42:59 +0900] "GET /hogehoge HTTP/1.1" 404 3650 "-" "curl/7.29.0" "-"
# grep hogehoge /var/log/nginx/access.log ## backend02
192.168.37.172 - - [01/Feb/2016:13:43:03 +0900] "GET /hogehoge HTTP/1.1" 404 3650 "-" "curl/7.29.0" "-"
## seesaw の cli から状態を確認できます
# seesaw -c "show nodes"
Nodes
[1] node01.localdomain. enabled
# seesaw -c "show backends"
Backends
[ 1] backend01.localdomain.
[ 2] backend02.localdomain.
# seesaw -c "show vservers"
Vserver
Name: test-vserver
Hostname: lb-test.localdomain.
Status: enabled (override state default; config state enabled)
IPv4 Address: 192.168.37.200/24
IPv6 Address: <not configured>
Services:
IPv4 TCP/80 (DSR, rr scheduler)
State: enabled, healthy, active
Watermarks: Low 0.00, High 0.00, Currently 1.00
## LVS なので、ipvsadm コマンドでも状態を見ることもできます
# yum install -y ipvsadm
# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.37.200:80 rr
-> 192.168.37.71:80 Route 1 0 0
-> 192.168.37.72:80 Route 1 0 0
FWM 65536 rr
-> 192.168.37.71:0 Route 1 0 6
FWM 65537 rr
-> 192.168.37.72:0 Route 1 0 10
ただ、まだ設定は改善が必要そうです。
lb=
に設定したインタフェースは MAC アドレスが変更されており、仮想MACアドレスを意識したものと思われますが今回の構成では node=
に設定した NIC の MAC アドレスで ARP 応答されています。
遊び時間が足りませんでしたが、いずれ調べたいです。
## Seesaw ノード
# ip a show dev eno33554960
3: eno33554960: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:00:5e:00:01:3c brd ff:ff:ff:ff:ff:ff
inet 192.168.37.80/24 brd 192.168.37.255 scope global eno33554960
valid_lft forever preferred_lft forever
inet 192.168.37.200/24 brd 192.168.37.255 scope global secondary eno33554960
valid_lft forever preferred_lft forever
inet6 fe80::200:5eff:fe00:13c/64 scope link
valid_lft forever preferred_lft forever
## client からの見え方
# ip n show to 192.168.37.200
192.168.37.200 dev enp3s0.37 lladdr 00:0c:29:94:66:fc STALE
真面目に使うときにはユニットファイルを書くことになると思います。
Upstart 向け設定では limit nofile 8192 8192
が書かれているので、ユニットファイルを作る際は LimitNOFILE
を入れておくと良さそうです。
Config Server も試したかったのですが、理解が足りていないのでいつか・・・