Istio Operator をやめよう

本記事は [ZOZO Advent Calendar 2022 vol.3](https://qiita.com/advent-calendar/2022/zozo) の14日目の記事です。
昨日は [@Otofuke](https://qiita.com/Otofuke) さんの [BigQuery移行で学んだクエリコスト削減Tips](https://qiita.com/Otofuke/items/adbe56e799ed11ed660a) でした。

本記事では、Istio Operator を活用した 1.13.X → 1.14.X のアップグレードで盛大にハマってしまったポイントを紹介し、Istio Operator でのインストール・アップグレードは早急にやめて、istioctl や Helm を使った管理を推奨する話をしたいと思います。

# TL;DR
本記事の主旨は以下になります。
- Istio Operator で 1.13.X → 1.14.X にアップグレードすると、Gateway Pod が正常に起動しない
- `spec.components.*` の設定を更新した Istio Operator の manifest を apply しても設定が更新されない
- **Istio Operator をやめよう**


Istio の構成管理としては、[Kustomize](https://kustomize.io/) を用いて、Istio Operator manifest の環境ごとの差分を overlay する手法を好んで利用していたのですが、
Istio Operator は現在もサポートされてはいるものの新しい機能は追加されない方針となりました。
現在は [istioctl](https://istio.io/latest/docs/setup/install/istioctl/) や [Helm](https://istio.io/latest/docs/setup/install/helm/) でのインストールが強く推奨されています。
> Use of the operator for new Istio installations is discouraged in favor of the Istioctl and Helm installation methods. While the operator will continue to be supported, new feature requests will not be prioritized.

引用元: https://istio.io/latest/docs/setup/install/operator/

Istio Operator を利用している方はインストール・アップグレード方法を早急に切り替えていきましょう。

ここからは、実際に Istio Operator を使ったアップグレードで、盛大にハマった具体例を紹介します。


## Istio Operator で 1.13.X → 1.14.X にアップグレードすると Gateway Pod が正常に起動しない
Istio Operator におけるアップグレードは大きく以下のようなステップになります。

[1] Istio Operator manifest 更新による Control Plane と Gateway の更新
[2] Data Plane の deploymentリソース を rollout restart することによる istio-proxy (sidecar) の更新

図で示すと以下のようになります。

![upgrade_with_istio_operator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55537/b0266e8a-3e08-001b-1ef0-d26506c843e4.png)


[1] では Istio Operator がアップグレードされると、Operator が Control Plane (istiod) と Gateway Pod をアップグレードします。
[2] の Data Plane のアップグレードは、istiod が istio-proxy (sidecar) を inject するタイミングで更新可能ですので、 rollout restart などで sidecar injection をトリガーする必要があります。

Istio Operator による 1.13.X → 1.14.X アップグレードにおいては、 [1] のタイミングで 新しい revision の Gateway Pod の起動ログで以下のようなメッセージが繰り返し出力され、Running Status にならないという問題に遭遇しました。

```
2022-10-12T05:31:16.683725Z warn    Failed to create directory for ./var/run/secrets/workload-spiffe-uds/socket: mkdir var/run/secrets/workload-spiffe-uds: read-only file system
2022-10-12T05:31:16.683797Z error   sds Failed to set up UDS path: failed to listen on unix socket "./var/run/secrets/workload-spiffe-uds/socket": listen unix ./var/run/secrets/workload-spiffe-uds/socket: bind: no such file or directory
2022-10-12T05:31:16.683813Z info    sds SDS server for workload certificates started, listening on "./var/run/secrets/workload-spiffe-uds/socket"
2022-10-12T05:31:16.683832Z info    xdsproxy    Initializing with upstream address "istiod.istio-system.svc:15012" and cluster "Kubernetes"
2022-10-12T05:31:16.683912Z info    sds Starting SDS grpc server
2022-10-12T05:31:16.683974Z warn    Failed to create directory for ./var/run/secrets/workload-spiffe-uds/socket: mkdir var/run/secrets/workload-spiffe-uds: read-only file system
2022-10-12T05:31:16.684006Z error   sds SDS grpc server for workload proxies failed to set up UDS: failed to listen on unix socket "./var/run/secrets/workload-spiffe-uds/socket": listen unix ./var/run/secrets/workload-spiffe-uds/socket: bind: no such file or directory
2022-10-12T05:31:16.684395Z info    starting Http service at 127.0.0.1:15004
2022-10-12T05:31:16.685529Z info    Pilot SAN: [istiod.istio-system.svc]
2022-10-12T05:31:16.687058Z info    Starting proxy agent
2022-10-12T05:31:16.687084Z info    Epoch 0 starting
2022-10-12T05:31:16.687112Z info    Envoy command: [-c etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --drain-strategy immediate --parent-shutdown-time-s 60 --local-address-ip-version v4 --file-flush-interval-msec 1000 --disable-hot-restart --log-format %Y-%m-%dT%T.%fZ  %l  envoy %n    %v -l warning --component-log-level misc:error]
2022-10-12T05:31:16.996590Z info    xdsproxy    connected to upstream XDS server: istiod.istio-system.svc:15012
2022-10-12T05:31:17.529450Z info    cache   generated new workload certificate  latency=845.662467ms ttl=23h59m59.470564871s
2022-10-12T05:31:17.529496Z info    cache   Root cert has changed, start rotating root cert
2022-10-12T05:31:17.529553Z info    cache   returned workload trust anchor from cache   ttl=23h59m59.4704497s
2022-10-12T05:31:17.684970Z warn    Failed to create directory for ./var/run/secrets/workload-spiffe-uds/socket: mkdir var/run/secrets/workload-spiffe-uds: read-only file system
2022-10-12T05:31:17.685072Z error   sds SDS grpc server for workload proxies failed to set up UDS: failed to listen on unix socket "./var/run/secrets/workload-spiffe-uds/socket": listen unix ./var/run/secrets/workload-spiffe-uds/socket: bind: no such file or directory
2022-10-12T05:31:19.686360Z warn    Failed to create directory for ./var/run/secrets/workload-spiffe-uds/socket: mkdir var/run/secrets/workload-spiffe-uds: read-only file system
2022-10-12T05:31:19.686433Z error   sds SDS grpc server for workload proxies failed to set up UDS: failed to listen on unix socket "./var/run/secrets/workload-spiffe-uds/socket": listen unix ./var/run/secrets/workload-spiffe-uds/socket: bind: no such file or directory
2022-10-12T05:31:23.687016Z warn    Failed to create directory for ./var/run/secrets/workload-spiffe-uds/socket: mkdir var/run/secrets/workload-spiffe-uds: read-only file system
2022-10-12T05:31:23.687094Z error   sds SDS grpc server for workload proxies failed to set up UDS: failed to listen on unix socket "./var/run/secrets/workload-spiffe-uds/socket": listen unix ./var/run/secrets/workload-spiffe-uds/socket: bind: no such file or directory
2022-10-12T05:31:31.691479Z warn    Failed to create directory for ./var/run/secrets/workload-spiffe-uds/socket: mkdir var/run/secrets/workload-spiffe-uds: read-only file system
2022-10-12T05:31:31.691552Z error   sds SDS grpc server for workload proxies failed to set up UDS: failed to listen on unix socket "./var/run/secrets/workload-spiffe-uds/socket": listen unix ./var/run/secrets/workload-spiffe-uds/socket: bind: no such file or directory
2022-10-12T05:31:47.692470Z warn    sds SDS grpc server could not be started
2022-10-12T05:31:55.711750Z warning envoy config    StreamSecrets gRPC config stream closed since 38s ago: 14, upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: immediate connect error: No such file or directory
2022-10-12T05:32:00.680270Z warning envoy config    StreamSecrets gRPC config stream closed since 43s ago: 14, upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: immediate connect error: No such file or directory
2022-10-12T05:32:01.936662Z warning envoy config    StreamSecrets gRPC config stream closed since 44s ago: 14, upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: immediate connect error: No such file or directory
2022-10-12T05:32:21.463608Z warning envoy config    StreamSecrets gRPC config stream closed since 63s ago: 14, upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: immediate connect error: No such file or directory
2022-10-12T05:32:23.629834Z warning envoy config    StreamSecrets gRPC config stream closed since 66s ago: 14, upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: immediate connect error: No such file or directory
```
こちらの問題の詳細は https://github.com/istio/istio/issues/38217 で報告されています。
エラーメッセージにある通り、 `/var/run/secrets/workload-spiffe-uds/` が read-only なので、 `/var/run/secrets/workload-spiffe-uds/socket` の mkdir に失敗しているようです。

こちらについては、Istio Operator を活用している OSS プロジェクトの以下の commit や Pull Request を参考に、 `/var/run/secrets/workload-spiffe-uds/` をマウントし、 write できるようにしようとしたのですが、私の環境では解決出来ませんでした。

https://github.com/banzaicloud/istio-operator/commit/398e5eb04e7e12b399262c40f69a7fccc9465178
https://github.com/gardener/gardener/pull/6339

引き続き自力で調査して、以下のワークアラウンドでの対処に落ち着きました。

1. `istioctl upgrade --dry-run` コマンドを実行する。
1. Istio Operator を利用して、 Control Plane と Gateway Pod をアップグレードする
1. `istioctl upgrade`コマンドにより生成される `MutatingWebhookConfiguration` リソースである `istio-revision-tag-default` を削除 
1. Data Plane を rollout restart していく

あくまでもワークアラウンドの対処なので、推奨する対処ではありません。
また、https://github.com/istio/istio/issues/38217 でも解決方法やワークアラウンドの提供、また Istio Operator の改修などは行われていません。

## `spec.components.*` の設定を更新した Istio Operator の manifest を apply しても 設定が更新されない

これまでの方法で、無事 Istio Operator を使って、1.13 → 1.14 へのアップグレードは実施できました。
ですが、1.14 系にアップグレードしてから、`spec.components.*` で指定する istiod や　Ingress / Egress Gatewayの設定（例えば、replicas や limits / requests など)を更新した Istio Operator の manifest を kubectl apply しても、設定が反映されなくなってしまいました。

この設定反映がされないタイミングでの Istio Operator のログは以下のようなものでした。
```
istio-operator-7849d8fc6-jxvnv istio-operator ✘ Ingress gateways encountered an error: failed to update resource with server-side apply for obj HorizontalPodAutoscaler/istio-system/istio-ingressgateway: failed to create typed patch object: .spec.metrics[0].resource.targetAverageUtilization: field not declared in schema
```

ここでは、Ingrees Gateway に対する Server Side Apply でリソース更新に失敗し、`.spec.metrics[0].resource.targetAverageUtilization`フィールドがスキーマで宣言されていないと警告されています。
こちらの問題も https://github.com/istio/istio/issues/41011 で報告されておりますので、詳細はこちらをご覧ください。

発生条件としては、以下のようです。
- 既にクラスタにデプロイされている istiod、Ingress / Egress Gateway には [HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) の設定がされている
- Istio Operator の `spec.components.*.k8s.hpaSpec` が宣言されていない

対処方法としては、https://github.com/istio/istio/issues/41011#issuecomment-1249010480 にもある通り、
Istio Operator で管理するすべての`spec.componentes.*`に対して、以下のように hpaSpec の設定を明示することです。

```
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  components:
    pilot:
      k8s:
        hpaSpec:
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
    ingressGateways:
    - enabled: true
      k8s:
        hpaSpec:
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
```
私たちの環境でも、上記の対応ですべて問題解決できました。

## Istio Operator をやめよう
Istio Operator を活用した 1.13.X → 1.14.X のアップグレードはご覧の通り、ハチャメチャにハマりました。
冒頭にも記載しましましたが、Istio Operator を活用したインストール・アップグレードはサポートはされているものの、新しい機能の提供は無く、現在は istioctl や Helm の使用が強く推奨されています。
本記事執筆時点では、[Istio 公式 Doc](https://istio.io/latest/docs/) で deprecated(非推奨) という表現までは見当たらないものの、[istio/istio](https://github.com/istio/istio) の issue や、[Istio Community の Slack](https://slack.istio.io/) を眺めていても、Istio Operator を利用する環境で発生した問題については、コミッター等から Istio Operator は deprecated なので、istioctl や Helm を使ってトライしてね、とアナウンスされているケースをしばしば見かけるようになりました。


これから Istio やってみようという方も、既に Istio を運用している方も、是非 [istioctl](https://istio.io/latest/docs/setup/install/istioctl/) や [Helm](https://istio.io/latest/docs/setup/install/helm/) でのインストール・アップグレードをご検討いただければと思います。