2019年7月14日日曜日

haproxy サーバに複数の IP を振って IP ベースのバランシングをしてみた

概要

haproxy の dst 機能を使えば IP ベースのバランシングが可能です
例えば haproxy サーバは一台しか用意できないが IP アドレスは複数用意できる場合に使えます

環境

  • macOS 10.14.5
  • Vagrant 2.1.1
  • Ubuntu 16.04 LTS
  • docker 18.09.7

準備

基本はこの手順 で構築します

今回は haproxy サーバが複数の IP を持っている想定なので Vagrantfile は以下のように書き換えます

  • vim Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.define "vm01" do |v|
    v.vm.box = "ubuntu/xenial64"
    v.vm.network "private_network", type: "dhcp"
    v.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
  end
  config.vm.define "vm02" do |v|
    v.vm.box = "ubuntu/xenial64"
    v.vm.network "private_network", type: "dhcp"
    v.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
  end
  config.vm.define "vm03" do |v|
    v.vm.box = "ubuntu/xenial64"
    v.vm.network "private_network", type: "dhcp"
    v.vm.network "private_network", type: "dhcp"
    v.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
  end
end

ポイントは vm03 に network が複数ある点です

  • vagrant up

haproxy.cfg の設定

dst を使った定義をします
今回 haproxy サーバ (vm03) に振られた IP は「172.28.128.5」「172.28.128.6」の 2 つとします

  • vim haproxy.cfg
frontend web
    default_backend test
    bind :80
    acl is_dst_test dst -i 172.28.128.5
    acl is_dst_test2 dst -i 172.28.128.6
    use_backend test if is_dst_test
    use_backend test2 if is_dst_test2

backend test
    option redispatch
    retries 3
    server vm01_test 172.28.128.3:80 weight 1
    server vm02_test 172.28.128.4:80 weight 1

backend test2
    option redispatch
    retries 3
    server vm01_test2 172.28.128.3:81 weight 1
    server vm02_test2 172.28.128.4:81 weight 1

ポイントは dst です
ここに haproxy サーバに割り当てられた IP を指定します
そして IP ごとに backend を定義すれば OK です
またコンテナを起動する際にも注意が必要です

  • docker run -d -p 80:80 -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg --name web --net=host haproxy

--net=host を必ず付与するようにしましょう
そうしないと destination の IP がコンテナ内部の IP になってしまいうまく dst でバランシングできなくなってしまいます

動作確認用の stack deploy

2 つの stack をデプロイします
それぞれの stack に dst で振り分けます

  • vim docker-compose.yml
version: '3.4'

services:
  nginx:
    image: valian/nginx-test-page
    ports:
      - "80:80"
    deploy:
      replicas: 2

これが「172.28.128.5」にアクセスしたときに振られる stack です

  • vim docker-compose2.yml
version: '3.4'

services:
  nginx:
    image: valian/nginx-test-page
    ports:
      - "81:80"
    deploy:
      replicas: 2

そしてこれが「172.28.128.6」にアクセスしたときに振られる stack です
ポートを 80 と 81 で LISTEN するようにしましょう

  • docker stack deploy -c docker-compose.yml test
  • docker stack deploy -c docker-compose2.yml test2

デプロイが完了して以下のようになっていれば OK です

  • docker service ls
ID NAME MODE REPLICAS IMAGE PORTS hbzcyfhc6zn0 test2_nginx replicated 2/2 valian/nginx-test-page:latest *:81->80/tcp bf6xj2lgy42r test_nginx replicated 2/2 valian/nginx-test-page:latest *:80->80/tcp

動作確認

  • curl 172.28.128.5

で test のサービスとしてデプロイしたコンテナからのみ応答が返ってくることを確認します

  • curl 172.28.128.6

では test2 からのコンテナからのみ応答が返ってくることを確認します

最後に

docker + haproxy の dst を使って IP ベースのバランシングを実現してみました
ポイントは docker network の host ドライバを使う点でした
ネットで調べると transparent mode が有効になってる haproxy で tombull/haproxy というのがありこれを使えばできるという紹介記事もあったのですが使わないでも実現できました

あと気になったのは haproxy コンテナのスケールアウトです
今回の場合、haproxy 用のコンテナホストを増やすと IP も追加になるはずです
そうなるとエンドポイントが複数に分かれてしまうのでまた上位にバランサを置かなければならなくなります
それだと永遠にスケールしないのでおそらく DNS を使うしかないんじゃないかなと思っています
もしくはバーチャル IP みたいなのを用意すればできるのだろうか、、

参考サイト

0 件のコメント:

コメントを投稿