Istioで割合でTraffic Managementするときにユーザごとにセッションを固定する
解決したい課題
Istioでweightによってサービスのバージョンを切り替えているとき、 リクエストの割合ベースで切り替えているだけなので、 同一ユーザでも異なるバージョンが表示されてしまう。 ユーザには少なくとも一定期間は同じバージョンを見せたいケースが多いと思うので今回はその方法を検証してみた。
Istioに用意されているSession Affinity機能
IstioではDestinationRuleで、ユーザごとに一定期間バージョンを固定化してルーティングするよう宣言できる。 https://istio.io/docs/reference/config/networking/destination-rule/#LoadBalancerSettings-ConsistentHashLB だがこれはConsistent Hashアルゴリズムによって実装されているため、PodがHPAでスケールアウト、スケールインしたときにルーティングされる向き先が変わってしまう。 また、この機能はweightの指定によってルーティングを設定しているときには併用してつかうことができない。 この機能はIstioというよりは実際にはEnvoyが担っていて、Envoy側のIssueを見る限りまだ解決されている様子はない。 https://github.com/envoyproxy/envoy/issues/8167
ではどうすればよいのか?
今回はWorkAround的な手法として、Cookieを用い、下記の方法を考えた。
あるバージョンに割り振られたトラフィックに対して、レスポンスにSetCookieヘッダーを付与し、 そこにサービスのバージョン情報を付与する、という方針を考えた。
具体的な実装
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: sample-service-gateway spec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: sample-service-gateway-vs spec: hosts: - "*" gateways: - sample-service-gateway http: - match: - headers: Cookie: exact: sample-service-version=v1 route: - destination: host: sample-service subset: v1 port: number: 8080 - match: - headers: Cookie: exact: sample-service-version=v2 route: - destination: host: sample-service subset: v2 port: number: 8080 - route: - destination: host: sample-service subset: v1 port: number: 8080 weight: 50 headers: response: add: "Set-Cookie": sample-service-version=v1; Max-Age=2592000 - destination: host: sample-service subset: v2 port: number: 8080 weight: 50 headers: response: add: "Set-Cookie": sample-service-version=v2; Max-Age=2592000 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: sample-service spec: host: sample-service subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2
これで実際にアクセスしてみると、最初は50%の確率でどちらかに割り振られ、それ以降のリクエストは同じバージョンへルーティングされる。
まとめ
今回はIstioでCookieを用いることで、バージョンを固定したルーティングを行った。 A/Bテストなど、ユーザには一貫した結果を出したい場合に活用したい。