Does not provide fallback content when JavaScript is not available. このサイトを視聴するにはJavaScriptを有効にしてください。Dockerのみでお手軽ロードバランシング&(ほぼ)0ダウンタイムデプロイ | blog.potproject.net

Dockerのみでお手軽ロードバランシング&(ほぼ)0ダウンタイムデプロイ

Dockerを結構本番運用をガッツリやる会社もよく聞くようになってきた気がします。

で、大体その手の話を聞くと、本番はいかに安定したシステムとネットワークを構築することが肝になるため、

k8sAnsibleCoreOSRancherOS、 コンテナなクラウドサービスの話になったりして・・・

これ以上その分野まで覚えようとすると大変すぎるし、自分はまあインフラエンジニアではないのでそこまではあまり興味が無かったりします。

そもそも、そこまでやるとするとかなりの知識が要りますし、かなり大変な作業となると思います。

でも、自分としてちゃんと問題なく動き、HTTPでロードバランシングでき、ダウンタイム0でのデプロイを実現できるWebシステムを構築したいわけです。 Dockerのみで。

このあたり、Webであればnginx-proxyで普通に行けるということを最近知りました。 しかも、めっちゃお手軽。

jwilder/nginx-proxyは主に複数のドメインを区切って同一サーバで複数のサービスを動かす目的として使用されています。 SSLなどもこれでリバースプロキシできるため、開発などのコンテナ作成時はかなりありがたい存在です。

version: '3'

services:
  nginx-proxy:
    image: jwilder/nginx-proxy:latest
    ports:
      - "8000:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
  whoami:
    image: jwilder/whoami
    environment:
      - VIRTUAL_HOST=localhost

jwilder/whoamiは、Webサーバで自分のコンテナIDを表示するDockerコンテナです。 ちゃんとロードバランシング出来ているかどうか非常にわかりやすいので使用しています。

で、実はこれ、同じドメインを複数のDockerに設定するとどうかというと、なんとそのままnginxの機能でhttpロードバランシングを組んでくれます。 実装例はこんな感じ。これだけです。

version: '3'

services:
  nginx-proxy:
    image: jwilder/nginx-proxy:latest
    ports:
      - "8000:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
  whoami_a:
    image: jwilder/whoami
    environment:
      - VIRTUAL_HOST=localhost
  whoami_b:
    image: jwilder/whoami
    environment:
      - VIRTUAL_HOST=localhost

見ての通りですが、ロードバランシング対象のサーバを同じバーチャルホストで増やすだけです。

この状態でlocalhost:8000にアクセスしてみると・・・ 普通に上手くバランシングして切り替わっていることがわかるはずです。

そして(ほぼ)ダウンタイム0デプロイですが、これは単純に対象の1つのコンテナを消して、新しく作りなおすという話です。 jwilder/nginx-proxyには、Dockerのsocketを見てコンテナが存在するかどうかを確認し、都度勝手に設定してくれる機能があります。 つまり、1つのサーバを止めるとそれを検知し、接続サーバから外してくれるということです。 (ほぼ)の理由として、nginx-proxyにあるnginxのリスタートが発火するからです。しかし本当に一瞬だとは思います。

新バージョンのサービスに切り替えたい時は、1つ消して新しくする、を個数分繰り返すだけです。 全てのサービスが停止されない限り、使用できない状態は無い、ということです。

#1つのコンテナを停止させる
docker-compose stop whoami_a
#ビルドする時はここでビルドして、新しく作り直す
docker-compose up --force-recreate whoami_a

また、nginx-proxyの中身を見てみましたが、こんな感じに書かれます。

普通にnginxのラウンドロビンでのロードバランシングとなります。 完全に自動で生成してくれるのはいいですね・・・。

# localhost
upstream localhost {
                        ## Can be connected with "default" network
                        # testloadbalance_whoami_a_1
                        server 172.19.0.4:8000;
                        ## Can be connected with "default" network
                        # testloadbalance_whoami_b_1
                        server 172.19.0.3:8000;
}
server {
        server_name localhost;
        listen 80 ;
        access_log /var/log/nginx/access.log vhost;
        location / {
                proxy_pass http://localhost;
        }
}

1秒ごとにcurlを打つスクリプトを組んでみましたが、タイムアウトやエラーになることはありませんでした。 これでdockerだけでHTTPロードバランシング&(ほぼ)ダウンタイム0デプロイが実現できました。 個人用レベルであれば、普通にこれで本番運用も十分行けると思います。