5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ZOZOAdvent Calendar 2024

Day 2

ZOZOのIstio Upgrade(v1.21.4 to v1.23.2)

Posted at

はじめに

2024/11に、ZOZOTOWNのマイクロサービスが稼働するプラットフォーム基盤上において、IstioのVersionをv1.21.4からv1.23.2にUpgradeしました。
本記事では、ZOZOにおけるIstio Upgradeの方針やその際の実施内容を紹介します。

ZOZOでのIstio Upgrade方針

Canary Upgrade

以前は、Control Planeやistio-ingressgatewayのUpgradeはIstio Operatorを活用したin-place upgrade手法を採用していました。しかし、in-place upgradeは手軽であるものの、マイナーバージョンを2つ以上一気にUpgradeすることがサポートされておらず、Istioの各バージョンのEOLが短いことから頻繁にアップグレード作業が必要なため、運用コストの問題がありました。また、たとえばzozo-api-gatewayのistio-ingressgatewayにおいて、もしもアップグレードに伴う障害が起きた場合はマイクロサービス側へのリクエストがすべてエラーになってしまう可能性がありました。
そこで、Canary upgrade with external traffic shifting (advanced)を参考に、ALB加重ルーティングを利用したControl Planeとistio-ingressgatewayのCanary Upgradeを採用することにしました。これにより、アップグレード作業の運用コストを抑え、万が一Upgradeに問題があった場合も影響を最小限にとどめることができます。

なお、Data Plane(Sidecarのistio-proxyがInjectされているマイクロサービス側)は、ZOZOではFlaggerを用いたProgressive DeliveryによりCanary Releaseが可能なため、特別な考慮は必要ありません。

Upgradeするタイミング

現在利用しているバージョンより2バージョン新しいバージョンがリリースされたら、Upgradeを実施します。
EOLを遵守しつつも、Upgrade頻度をなるべく下げて、工数を抑えるためです。

対象環境と順序

ZOZOでは、主にdev/stg/prdの3環境が存在します。当然ながら、すべての環境をUpgradeします。また、dev/stgもCanary Upgradeで実施します。dev/stgはin-placeでも問題ないのですが、prdと同じ手順で実施して問題がないことを確認してから、prdをUpgradeするためです。

今回のUpgrade実施内容

今回実施した、v1.21.4からv1.23.2へのUpgrade内容を以下に示します。

事前作業

リリースノートの確認

以下のドキュメントをすべて確認し、今回のUpgradeにより、問題となる変更がないことを確認しました。

ただし、Istio Operatorが正式にv1.23でdeprecatedとなり、v1.24以降では利用できなくなるため、次回のUpgrade時には代替方法の検討が必要であることが分かりました。

IstioとKubernetesの対応バージョン確認

予定しているIstioバージョンがKubernetesバージョンをサポートしていることを確認しました。Istio Upgrade作業時のEKSクラスターのversionは1.29なので、問題ありませんでした。
https://istio.io/latest/docs/releases/supported-releases/#support-status-of-istio-releases

Istio___Supported_Releases.png

istioctlによるprecheck

Upgrade前にistioctl x precheckを実行し、問題がないことを確認しました。

>istioctl x precheck --context {CONTEXT_NAME}
✔ No issues found when checking the cluster. Istio is safe to install or upgrade!
  To get started, check out https://istio.io/latest/docs/setup/getting-started/

全体周知

slackで関係各所に、Istio Upgradeを実施する旨と予定スケジュールを事前に周知しました。

Upgrade作業

dev/stg/prd環境ごとに、6StepsでUpgradeを実施しました。

Step1: 新しいバージョンのControl Planeリソースとistio-ingressgatewayの作成

新しいバージョンのControl Planeリソースを作成しました。具体的には、以下のリソースです。

  • ClusterRole
  • ClusterRoleBinding
  • Deployment
  • Service
  • ServiceAccount
  • CustomResourceDefinition

リソースのmanifestは以下のコマンドを実行して取得しました。ただし、古いバージョンのmanifest上でCRDのみ削除する必要があります。削除しないと、同一名のCRDが両バージョンで重複してしまうからです。

$ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.23.2 sh -
$ istio-1.23.2/bin/istioctl operator dump --revision 1-23-2 > istio-operator.yaml

動作確認として、istio-operator-1-23-2のPodで想定外のエラーログがないことを確認しました。

続いて、新しいバージョンのistio-ingressgateway関連のリソースを作成しました。具体的には、以下のリソースです。

  • IstioOperator
  • istiodのPod
  • 各種マイクロサービスのistio-ingressgatewayのPod
    • すべてのマイクロサービスでistio-ingressgatewayが存在するわけでなく、EKSクラスター外部から一次受けする可能性があるマイクロサービスにのみ用意しています

動作確認として、各Podで想定外のエラーログがないことを確認しました。

Step2: 新しいバージョンのistio-ingressgatewayに10%加重ルーティング

Ingressリソース(つまり、ALB)のannotationを更新し、新しいバージョンのistio-ingressgatewayに10%の加重ルーティングを行いました。以下は、zozo-api-gatewayのIngressリソースの例です。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: "internal-api-gateway-ingress"
  annotations:
    alb.ingress.kubernetes.io/actions.forward-multiple-tg: >
      { "Type":"forward", "ForwardConfig": {"TargetGroups": [ {"ServiceName":"api-gateway-istio-ingressgateway-1-21-4","ServicePort":"80","Weight":90},{"ServiceName":"api-gateway-istio-ingressgateway-1-23-2","ServicePort":"80","Weight":10} ] }}

Datadog Metrics Explorerを確認し、10%のリクエストが新しいバージョンに流れていることを確認しました。想定外のエラーが発生していないことも確認しました。

Step3: 新しいバージョンのistio-ingressgatewayに100%加重ルーティング

Ingressのannotationを更新し、新しいバージョンのistio-ingressgatewayに100%の加重ルーティングを行いました。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.forward-multiple-tg: |
      { "Type":"forward", "ForwardConfig": {"TargetGroups": [ {"ServiceName":"api-gateway-istio-ingressgateway-1-23-2","ServicePort":"80","Weight":100} ] }}

同じく、Datadog Metrics Explorerを確認し、100%のリクエストが新しいバージョンに流れていることを確認しました。想定外のエラーが発生していないことも確認しました。

Step4: NamespaceのRevisionラベルを修正する

Data Planeのnamespaceのmetadata.labels.isito.io/revに新しいバージョンのRevisionを指定しました。以下は、zozo-api-gatewayのNamespaceリソースの例です。

apiVersion: v1
kind: Namespace
metadata:
  name: api-gateway
  labels:
    istio.io/rev: 1-23-2 # here

Step5: Data Planeリソースを再起動する

Data PlaneのDeploymentのannotationを更新し、Progressive Deliveryを実施します。
以下は、zozo-api-gatewayのDeploymentリソースの例です。

apiVersion: apps/v1
kind: Deployment
namespace: api-gateway
metadata:
  name: api-gateway
spec:
  template:
    metadata:
      annotations:
        last-canary-retry-timestamp: "2024-11-06T19:02:00+0000" # here
...

Podが生まれ変わり、SidecarにInjectされているistio-proxyが新しいバージョンのものになったことを確認しました。
Podが作成される際に、KubernetesのAdmission Controllerがnamespaceに付与されているistio.io/revラベルの値を読み取り、そのrevisionのIstio Control Planeに接続して、そのバージョンのistio-proxyをPodにInjectしています。

Step6: 古いバージョンのControl Planeとistio-ingressgatewayを削除する

まず、古いバージョンのリソースをマニフェスト上から削除しました。
ZOZOではFluxによるGitOpsを導入しているのですが、ZOZOではIstio関連のリソースはFlux対象外のため、自動では削除されません。したがって、以下のリソースを手動で削除しました。

  • istiooperator
    • clusterrolebinding
    • clusterrole
    • service
    • serviceaccount
  • istio-ingressgateway
    • deployment
    • service
    • horizontalpodautoscaler
    • poddisruptionbudget
    • serviceaccount
  • istiod
    • poddisruptionbudget
    • clusterrolebinding
    • clusterrole
  • MutatingWebhookConfiguration
  • ValidatingWebhookConfiguration

以下のコマンドを実行し、古いバージョンのリソースが残っていないことを確認しました。

$ k get all  -A | grep 1.21.4
$ k get clusterrolebinding,clusterrole,pdb,mutatingwebhookconfiguration,validatingwebhookconfiguration,sa -A| grep istio | grep 1.21.4

トラブル

CRDを削除してしまった

dev環境のUpgrade時に、誤ってstg/prd環境のistioperatorのCRDを削除してしまいました。本来は、古いバージョンのCRDをmanifestから削除する際には、同時に新しいバージョンのCRDを追加するべきだったのですが、stg/prdではそれが抜けていました。ZOZOのプラットフォーム基盤を構成管理するGitHubリポジトリでは、baseディレクトリで管理し、各環境でkustomizationによるoverlayをする構成になっています。dev環境のUpgradeのPull Request(以降、PR)では、baseからCRDを削除していたにもかかわらず、devの新しいバージョンのCRDしか追加していませんでした。このようなPRを作成してしまった理由は、前回のUpgrade時のPRをそのまま模倣してしまったからです。前回までのUpgradeでは、ZOZOのplatform基盤ではKubernetesのpruneを利用しない方式としていました。したがって、manifestからリソースを削除しても自動では削除されず、全環境のUpgradeが終わってからまとめて削除する手筈でした。しかしながら、今回のIstio Upgrade作業の少し前くらいからpruneを利用する方式に変わっており、baseのマニフェストからCRDを削除したタイミングで、クラスター上のCRDリソースに対して削除処理が走ってしまいました。
ただし、実際には、CRが残っていたため、CRDは削除中の状態(deletionTimestampが設定されているが存在する状態)で留まってくれていました。CRDが削除されなかったので、istio-ingressgatewayなどのPodはかろうじて残っており、サービス影響はありませんでした。不幸中の幸いです。しかしながら、その影響でistio-ingressgatewayなどのリソースを変更することができない状態になってしまいました。この状態を解消するためにIstio OperatorのCRとCRDを安全に再作成することにしました。実施した復旧手順は以下です。

  1. baseディレクトリを使用せずに、各環境のディレクトリでControl Planeのすべてのリソースを定義し、manifest上でstg/prdの1-21-4のCRDを追加した。
  2. istio-operatorのdeploymentのreplicasを0に変更し、Podを削除した。
  • kubectl scale deployment istio-operator-1-21-4 --replicas=0 -n istio-operator
  1. IstioOperatorのCRとCRDを削除した
  • 具体的には、IstioOperator CRのfinalizersを空のスライスにした。
  • kubectl patch istiooperator istio-control-plane-1-21-4 -n istio-system -p '{"metadata":{"finalizers":[]}}' --type=merge
  • 削除されてしばらくすると、自動でCRとCRDが起動する。これは、手順1で追加したmanifest上の1-21-4のCRDをFluxが検知し、CRDを作成するため。

Step6でistiooperatorが削除されない

Step6の手順で、古いバージョンのistiooperatorリソースを手動で削除したのですが、削除されませんでした。これは、kubectl editで該当リソースのfinalizerの値を空のスライスにすることで削除されるようになりました。ただし、deleteコマンドを実行してから、少し時間(数分ほど)待ってからeditしないと、予期せずゴミリソースが残ってしまうため、注意が必要でした。
いずれにせよ、今後はIstio Operatorがdeprecatedになるため、あまり気にする必要はなくなります。

最後に

本記事では、ZOZOでのIstio Upgradeの方針ややり方、そして今回のUpgrade実施内容について紹介しました。
Istioの運用をされている方の参考になれば幸いです。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?