2019年7月13日土曜日

docker Swarm 環境にロードバランサを導入する

概要

docker Swarm には Ingress という機能がありこれを使うことで分散配置されたコンテナにどのコンテナホストからもアクセスすることができるようになります
エンドポイントも複数に分散してしまいます
今回は Ingress の更に上にロードバランサを設けて Ingress で publish したポートを一つのエンドポイントでアクセスする方法を紹介します

環境

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

準備

この手順 で docker Swarm 環境を構築しました
また今回は Ingress 用のバランサも作る必要があるので VM を 3 台にしています
Swarm クラスタが 2 台で残り 1 台はクラスタに入れないようにします

stack deploy

まずは stack deploy でコンテナを作成しましょう
クラスタ内のコンテナホストは 2 台なのでそれぞれにコンテナができるように replicas: 2 にしましょう

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

services:
  nginx:
    image: valian/nginx-test-page
    ports:
      - "80:80"
    deploy:
      replicas: 2
  • docker stack deploy -c docker-compose.yml test
  • docker stack ls
NAME SERVICES ORCHESTRATOR test 1 Swarm
  • docker service ls
ID NAME MODE REPLICAS IMAGE PORTS ouh22aumey6x test_nginx replicated 2/2 valian/nginx-test-page:latest *:80->80/tcp
  • docker stack ps test
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS tql4b06k241l test_nginx.1 valian/nginx-test-page:latest vm02 Running Running 2 minutes ago uz4mk5orsl5r test_nginx.2 valian/nginx-test-page:latest vm01 Running Running 2 minutes ago
  • curl vm01
HOSTNAME=efc280b9eead

vm02 からもコンテナにアクセスできることを確認しましょう

ingress サーバからバランシングする (nginx)

やり方はいろいろあると思いますが今回は nginx を使ってみます
新たに追加した vm03 サーバをロードバランサにします

  • vim default.conf
server {
   listen 80;
   location / {
      proxy_pass http://test;
   }
}
upstream test {
   server 172.28.128.3;
   server 172.28.128.4;
}

vm01 と vm02 は IP で指定しています
バランシングする nginx コンテナから Swarm クラスタ内のコンテナホストにアクセスします
その際に名前を引けないので IP を指定しています

nginx コンテナを起動しましょう

  • docker run -d -p 80:80 -v $(pwd)/default.conf:/etc/nginx/conf.d/default.conf --name web nginx

vm03 にアクセスして Ingress と通して vm01 と vm02 に配置されたコンテナにアクセスできることを確認します

  • curl vm03
HOSTNAME=efc280b9eead

片方のコンテナをダウンさせてみる

今回 stack deploy で 2 台のコンテナを起動させています
インシデントのシミュレーションとして片方のコンテナをダウンさせてみます
vm01 or vm02 のコンテナホストにログインして直接コンテナを停止してみましょう

  • docker stop 0dfc9f942286

curl vm03 を続けていると挙動を確認できます
デフォルトの nginx の状態だとダウンしたコンテナにもリクエストを投げてしまうのでたまに 502 になるのが確認できます
stack deploy の場合 replicas: 2 で指定したコンテナ数以下になると自動でコンテナを再作成するのでそのうち 502 は発生しなくなります

502 を発生させないようにするには基本的には nginx を haproxy に置き換えるのが良いと思います

ingress サーバからバランシングする (haproxy)

ということで haproxy もやってみたいと思います
先程同様に vm03 上で動作させます

  • vim haproxy.cfg
frontend web_proxy
    default_backend test
    bind *:80

backend test
    option redispatch
    retries 3
    server vm01 172.28.128.3:80 weight 1
    server vm02 172.28.128.4:80 weight 1

redispatch を指定することでダウンしたコンテナにアクセスしないようにします

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

起動して動作確認しましょう

  • while true:; do curl vm03; sleep 1; done

これで先程同様にコンテナを停止してみましょう
すると 502 は出ずにコンテナが再作成されるまで片方のコンテナにだけアクセスし続けるのが確認できると思います

おまけ: クラスタ内のコンテナホストの IP を取得する方法

  • for NODE in $(docker node ls --format '{{.Hostname}}'); do echo -e "${NODE} - $(docker node inspect --format '{{.Status.Addr}}' "${NODE}")"; done

おまけ: dockerd のジャーナルログの確認

  • sudo journalctl -u docker

tail したい場合は -f オプションも使います
ただ今回の動作確認のようなコンテナのダウンや再作成のログは表示されないようです
表示させたい場合はログレベルを debug にする必要があります

  • sudo vim /etc/docker/daemon.json
  • sudo kill -SIGHUP $(pidof dockerd)

最後に

docker Swarm の Ingress の機能で publish したポートを更にロードバランサで分散してみました
nginx と haproxy を使ってみましたが基本は haproxy を使ったほうが良いかなと思います

参考サイト

0 件のコメント:

コメントを投稿