tl;dr
アプリケーション側のdeploy設定でレプリカ数を指定して、LBとしてhaproxyを置くことで実現した。冗長というよりも負荷分散かもしれない。
- docker-compose.yml
version: '3.7' services: app: ... deploy: mode: replicated replicas: 4 expose: - "8080" lb: image: haproxy:lts-alpine restart: always ports: - "8080:8080" depends_on: - app volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- haproxy.cfg
defaults mode http timeout client 10s timeout connect 5s timeout server 10s timeout http-request 10s frontend myfrontend bind 0.0.0.0:8080 default_backend myservers backend myservers server-template server 5 app:8080 check resolvers mydns init-addr none resolvers mydns parse-resolv-conf
背景、流れ
minikubeでアプリケーションをスケールさせればよいのだが、kubernetes勉強中にdocker-composeでもできそうな気がして先にそっちをやりたくなった。
(minikube tunnel
はうまく動かないし、 kubectl port-forward
をたたくのも手間でその先を調べるのがめんどくさくなった)
今の docker-compose.yml
version: '3.7' services: app: ... ports: - "8080:8080"
まずスケールさせる
この時にアプリケーション側のportsを expose にするのを知る。 スケールさせるとdocker側の待ち受けポートがかぶるので待ち受け側を明示できない
version: '3.7' services: app: ... deploy: mode: replicated replicas: 4 expose: - "8080"
haproxyにする
ググってるとnginxの例が出てくるがなんか違う気がしたのと、うまく設定できなかったのでさらに調べる。
以下のドキュメントではhaproxyを使ってて、こっちのほうが適任な気がすると採用。
このドキュメントで使っているイメージはdocker hubに見に行ってもDockerfileが見えなかったので haproxy 本家のコンテナイメージを使うことにした。
version: '3.7' services: app: ... deploy: mode: replicated replicas: 4 expose: - "8080" lb: image: haproxy:lts-alpine restart: always ports: - "8080:8080" depends_on: - app volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
haproxyの設定ファイル
設定ファイルの説明はこの記事がわかりやすかった。
ここを見ながらアプリケーションを列挙する標準形を作る
docker埋め込みDNSがサービス名で名前解決してくれるのでバックエンドのサーバは app
defaults mode http timeout client 10s timeout connect 5s timeout server 10s timeout http-request 10s frontend myfrontend bind 0.0.0.0:8080 default_backend myservers backend myservers server server1 app:8080 server server2 app:8080 server server3 app:8080 server server4 app:8080
スケールさせるとサーバ数だけ列挙するのが嫌なのと、docker-composeでスケールさせると1つの名前で docker 埋め込みDNSが複数のIPアドレスを返してくれるのでうまいこと活用したかった。
以下の記事でserver-templateが使えることがわかる。スケールさせる上限の数を書いておけば、名前解決でIPが返ってきた数だけサーバを増やしてくれる。
backend myservers server-template server 5 app:8080 check resolvers mydns init-addr none resolvers mydns parse-resolv-conf
docker埋め込みDNSサーバは /etc/resolv.conf
に記載されてるので、haproxyに指定するネームサーバは明示せず、resolv.confを読み込む指定を使う parse-resolv-conf
を指定した。
まとめ
これでだいたい求めていた構成になった。
- docker-compose.yml
version: '3.7' services: app: ... deploy: mode: replicated replicas: 4 expose: - "8080" lb: image: haproxy:lts-alpine restart: always ports: - "8080:8080" depends_on: - app volumes: - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- haproxy.cfg
defaults mode http timeout client 10s timeout connect 5s timeout server 10s timeout http-request 10s frontend myfrontend bind 0.0.0.0:8080 default_backend myservers backend myservers server-template server 5 app:8080 check resolvers mydns init-addr none resolvers mydns parse-resolv-conf