kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Envoy の route.HeaderMatcher を使う「Implementing Blue / Green Rollouts」を試した

今回は「Try Envoy」「Implementing Blue / Green Rollouts」を紹介する.Envoy でサポートされている様々なルーティング設定の中から「HTTP Header ベースルーティング」「加重ラウンドロビン」を学べる.

Implementing Blue / Green Rollouts

手順は以下の「計6種類」ある.

  • Step.1 「Envoy Base Configuration」
  • Step.2 「Header-Based Routing」
  • Step.3 「Deploy Header-Based Routing」
  • Step.4 「Weighted Load Balancing」
  • Step.5 「Rollout 20% Traffic」
  • Step.6 「Rollout 100% Traffic」

www.envoyproxy.io

www.katacoda.com

Step.1 「Envoy Base Configuration」

Step.1 では envoy.yaml を読み解き,クイズに正解する必要がある.理解度確認になって非常に良いと思うし,Katacoda ってクイズ形式も作れるんだ!というプラットフォームの機能の幅広さに驚いたりもした.

  • Question: How many routes have been defined within the configuration?
  • Question: How many clusters have been defined within the configuration?

f:id:kakku22:20200112132842p:plain

Step.2 「Header-Based Routing」

ユーザーに影響を出さず,新機能をテストすることを「ダークリリース (Dark Releases)」と言う(とコンテンツに書いてある).Envoy の route_config は上から順番に比較し,最初に一致したルーティング設定を使うことになるため,今回は /service/2 に対して2種類のルーティング設定をしている.今回は HTTP Header x-canary-versionservice2a という値が設定されている場合に Cluster service2a にルーティングする.

route_config:
  virtual_hosts:
  - name: backend
    domains:
    - "*"
    routes:
    - match:
        prefix: "/service/1"
      route:
        cluster: service1
    - match:
        prefix: "/service/2"
        headers:
        - name: "x-canary-version"
          exact_match: "service2a"
      route:
        cluster: service2a
    - match:
        prefix: "/service/2"
      route:
        cluster: service2

Envoy は routes の設定として route.RouteMatch を使えば,細かくルーティングを制御できる.今回は route.HeaderMatcher を使って HTTP Header ベースのルーティングを実現している.高機能ロードバランサとして機能が揃っている!

www.envoyproxy.io

Step.3 「Deploy Header-Based Routing」

次に Envoy と katacoda/docker-http-server を起動する.katacoda/docker-http-serverv1 を2個 / v2 を2個 / v3 を1個起動する.構成図は以下のようになる.

$ docker run -d --name proxy1 -p 80:8080 -v /root/:/etc/envoy envoyproxy/envoy

$ docker run -d katacoda/docker-http-server:v1
$ docker run -d katacoda/docker-http-server:v1
$ docker run -d katacoda/docker-http-server:v2
$ docker run -d katacoda/docker-http-server:v2
$ docker run -d katacoda/docker-http-server:v3

f:id:kakku22:20200112132915p:plain

katacoda/docker-http-server とコンテナ ID の関係を整理しておくと,以下のようになる.

$ docker ps -q | xargs -n 1 docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} {{ .Config.Hostname }} {{ .Config.Image }}' | sed 's/ \// /'
172.18.0.7 fdf5019381c2 katacoda/docker-http-server:v3
172.18.0.6 64724167bc8d katacoda/docker-http-server:v2
172.18.0.5 63a9ff40f850 katacoda/docker-http-server:v2
172.18.0.4 efab265b509a katacoda/docker-http-server:v1
172.18.0.3 c985d2391163 katacoda/docker-http-server:v1
172.18.0.2 9814e5b162f4 envoyproxy/envoy

動作確認として,まず http://localhost/service/2 にリクエストを送ると,Cluster service2 を経由して efab265b509a にルーティングされる.そして http://localhost/service/2 に HTTP Header を乗せてリクエストを送ると,Cluster service2a を経由して 63a9ff40f850 にルーティングされる.構成図の通りになっている.

# HTTP Header なし
$ curl http://localhost/service/2
<h1>This request was processed by host: efab265b509a</h1>
$ curl http://localhost/service/2
<h1>This request was processed by host: efab265b509a</h1>

# HTTP Header あり
$ curl -H "x-canary-version: service2a" http://localhost/service/2
<h1>New Release! Now v2! This request was processed by host: 63a9ff40f850</h1>
$ curl -H "x-canary-version: service2a" http://localhost/service/2
<h1>New Release! Now v2! This request was processed by host: 63a9ff40f850</h1>

Step.4 「Weighted Load Balancing」

次は「カナリアリリース」のように使える「加重ラウンドロビン」を試す.ルーティング設定に weighted_clusters を追加すると,weight に設定した割合に従ってルーティングされる.今回は /service/3 にリクエストを送ると 80% は Cluster service3a に,そして 20% は Cluster service3b にルーティングされる.

route_config:
  virtual_hosts:
  - name: backend
    domains:
    - "*"
    routes:
    - match:
        prefix: "/service/1"
      route:
        cluster: service1
    - match:
        prefix: "/service/2"
        headers:
        - name: "x-canary-version"
          exact_match: "service2a"
      route:
        cluster: service2a
    - match:
        prefix: "/service/2"
      route:
        cluster: service2
    - match:
        prefix: "/service/3"
      route:
        weighted_clusters:
          clusters:
          - name: service3a
            weight: 80
          - name: service3b
            weight: 20

Step.5 「Rollout 20% Traffic」

設定変更を反映するため Envoy を再起動する.構成図は以下のようになる.

f:id:kakku22:20200112132930p:plain

さっそく http://localhost/service/3 に対してリクエストを送ると,割合に従ってルーティングされる.繰り返し実行していると,キレイに 80% / 20% にならないこともあった.

$ for i in {1..10}; do curl -s http://localhost/service/3; done
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Another Release! Now v3! This request was processed by host: fdf5019381c2</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Another Release! Now v3! This request was processed by host: fdf5019381c2</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>

なお,今回は手順を簡単にするために Envoy を再起動したけど,Route Discovery Service (RDS) を使えば,自動的に反映できるようになる.xDS 関連は以下の Try Envoy が参考になる.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

Step.6 「Rollout 100% Traffic」

最後は割合を 100% にする.100% なら weighted_clusters を使う必要はなさそうだけど,実際に動くことを確認する手順になっていた.

route_config:
  virtual_hosts:
  - name: backend
    domains:
    - "*"
    routes:
    - match:
        prefix: "/service/1"
      route:
        cluster: service1
    - match:
        prefix: "/service/2"
        headers:
        - name: "x-canary-version"
          exact_match: "service2a"
      route:
        cluster: service2a
    - match:
        prefix: "/service/2"
      route:
        cluster: service2
    - match:
        prefix: "/service/3"
      route:
        weighted_clusters:
          clusters:
          - name: service3b
            weight: 100

構成図は以下のようになる.

f:id:kakku22:20200112133003p:plain

まとめ

  • 「Try Envoy」のコンテンツ「Implementing Blue / Green Rollouts」を試した
  • Envoy は「高機能ロードバランサ」の側面として様々なルーティング設定ができることを学んだ

引き続き,進めていくぞ!

プルリクエスト

試しながら気付いた誤りを修正してプルリクエストを送っておいた!

github.com

Try Envoy 関連