Canary VirtualServiceのTimeoutをDelegate VirtualServiceに移行する際の落とし穴

# はじめに
本記事では、FlaggerのCanary VirtualService（以降VSと記載）に存在していたTimeout設定をdelegate VSに移行する際の検証した際の備忘録です。

事前の検証でCanaryリソースからtimeout設定を削除した際に、Canary VSから自動でtimeout削除が適用されない事象がありました。その際、手動でtimeout設定を削除する必要があったため、備忘録として記事を書きます。
結果として、PRマージ後に検証で発生していた事象は発生せず、**自動的に Canary VS から timeout が削除されることを確認しました。**

# Flaggerとは
Flaggerとはプログレッシングデリバリーを実現するKubernetes Operatorです。

Flaggerについての詳細な導入内容については以下も合わせてご覧ください。

https://techblog.zozo.com/entry/progressive-delivery-by-flagger#Flagger%E3%81%A8%E3%81%AF

# 既存の設定(before)

現在、一部のマイクロサービスでは、リトライやタイムアウトの設定が Canary VirtualService (VS) と Delegate VirtualService の両方に分散して管理されています。

しかし、この状態では Delegate VS 側で「特定のパスに対してのみタイムアウトを変更する」といった細かい制御ができません。

今回の変更では、外部サービスへのリクエストが発生しますが、その外部サービスの応答時間は、これまで共通で設定されていた 3.4秒 を超えることが予想されます。そこで、Delegate VS にタイムアウトの設定を移行し、外部サービスへのリクエストに対しては適切にタイムアウトを延長する 必要がありました。

## Canaryの設定
```yaml
# Canaryリソース
k get canary -n zozo-hoge -o yaml
apiVersion: v1
items:
- apiVersion: flagger.app/v1beta1
  kind: Canary
  spec:
    << 中略 >>
    service:
      delegation: true
      name: zozo-hoge-api
      timeout: 3.4s # canary.yamlの設定をもとにCanary VSが作成される
```
```yaml
# Canary VSリソース
k get vs -n zozo-hoge -o yaml
apiVersion: v1
items:
- apiVersion: networking.istio.io/v1
  kind: VirtualService
  metadata:
    name: zozo-hoge-api
    namespace: zozo-hoge
    ownerReferences:
    - apiVersion: flagger.app/v1beta1
      kind: Canary
      name: zozo-hoge-api
  spec:
    hosts: []
    http:
    - route:
      - destination:
          host: zozo-hoge-api-primary
        weight: 100
      - destination:
          host: zozo-hoge-api-canary
        weight: 0
    timeout: 3.4s # zozo-hoge-api-{primary|canary}に来たリクエストは全てtimeoutは3.4sとなる
```

## Delegate VSの設定
```yaml
- apiVersion: networking.istio.io/v1
  kind: VirtualService
  metadata:
    labels:
      app: zozo-hoge-api
      kustomize.toolkit.fluxcd.io/name: zozo-hoge-api
      kustomize.toolkit.fluxcd.io/namespace: zozo-hoge
    name: zozo-hoge-api-delegate
    namespace: zozo-hoge
  spec:
    hosts:
    - zozo-hoge-api
    http:
    - delegate:
        name: zozo-hoge-api
        namespace: zozo-hoge
      match:
      - uri:
          prefix: /
      name: default
      retries:
        attempts: 1
        retryOn: 5xx
```

# 変更後（After）

## canary.yaml
Canaryリソースからtimeoutを削除する
```yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: zozo-hoge-api
spec:
  service:
    delegation: true
    name: zozo-hoge-api
    port: 80
    targetPort: 8080
    timeout: 3.4s # timeoutを削除
```

## virtual-service.yaml
Delegate VSのdefaultにtimeout追加する。
```yaml
- apiVersion: networking.istio.io/v1
  kind: VirtualService
  metadata:
    labels:
      app: zozo-hoge-api
    name: zozo-hoge-api-delegate
    namespace: zozo-hoge
  spec:
    hosts:
    - zozo-hoge-api
    http:
    - delegate:
        name: zozo-hoge-api
        namespace: zozo-hoge
      match:
      - uri:
          prefix: /
      name: default
      retries:
        attempts: 1
        retryOn: 5xx
      timeout: 3.4s # timeoutを追加
```

# 手動作業
想定であれば、上記のcanary.yamlからtimeoutを削除し`kubectl apply`をすると、canary vsからもtimeoutが削除される。

一方でapply後に、canary vsからtimeoutが削除されない事象が発生しており、以下のように`kubectl edit`で直接Canaryリソースからtimeoutの行を消す必要がありました。

```bash
kubectl edit canary zozo-hoge-api -n zozo-hoge
 
service:
    delegation: true
    name: zozo-hoge-api
    port: 80
    targetPort: 8080
    timeout: 3.4s # 削除
  skipAnalysis: true
```

## 動作確認
### timeoutが機能しているか確認
1. zozo-hoge-api→Delayを設定したmockに対してcurlしtimeoutで504が返ることを確認しました。

2. また、一時的にCanary VSとDelegate VSにtimeoutが存在することになりますが、この時も正常にtimeoutになることが確認できました。

### annotationsが残っている場合に復活しないか確認
手動でCanaryリソースからtimeoutを削除後、annotationにtimeoutが残っている事象がありました。
```bash
## canary virtual-service
k get vs zozo-hoge-api -n zozo-hoge -o yaml | grep -2 -n timeout                        

3-metadata:
4-  annotations:
5:    flagger.kubernetes.io/original-configuration: 
'{"hosts":[],"http":[{"route":[
{"destination":{"host":"zozo-hoge-api-primary"},"weight":100},
{"destination":{"host":"zozo-hoge-api-canary"},"weight":0}
],"timeout":"3.4s"}]}' # timeoutがなぜか残っている
6-    
```

そのため、以下２つを検証し、timeoutが復活してしまわないか検証を行いました。結果として、どちらの検証でも正常にCanary VSのtimeoutが復活しないことが確認できました！
1. Progressing Delivery(PD) 
2. Canary VSの削除、再アプライ

# まとめ
本記事では、Canary VSからDelegate VSにタイムアウト設定を移行する際に起きた事象とその対策を紹介しました。
timeout設定に限らずCanary VSの設定を変更する場合（特に削除）は`kubectl apply`だけでは削除されないことがあるため、apply後に設定が反映されているか確認することをお勧めします。