サービス断なしで進めるIstio OperatorからHelmへの移行

Istio OperatorからHelmへの移行イメージ

はじめに

こんにちは、SRE部プラットフォームSREブロックのさかべっちです。2025年度に新卒で入社しました。普段はZOZOTOWNにおけるプラットフォーム基盤の運用・改善を担当しています。

本記事では、Istio Operatorが非推奨となったことを受けて、サービス断を一切発生させることなくHelmへの移行を完遂させた取り組みをご紹介します。移行作業で直面した技術的な課題とその解決方法について、実際の経験をもとに解説します。

目次

背景

Istio Operatorは、Istioのコンポーネントを一元管理するためのオペレーターとして、ZOZOTOWNのプラットフォーム基盤で重要な役割を果たしてきました。IstioOperatorというカスタムリソース定義(CRD)を通じて、Istiod、Gatewayなどの設定を宣言的に定義できます。これにより、複雑なIstioの構成管理をIaC(Infrastructure as Code)として効率的に運用できました。

しかし、Istio公式から非推奨の発表があり、version 1.23以降へのアップグレードができないという制約が明らかになりました。

移行前時点での状況

  • ZOZOTOWNのプラットフォーム基盤のIstioはversion 1.23で運用
  • version 1.23のEOL(End of Life)が迫っている
  • 利用中のIstio Operatorではversion 1.23から先にUpgrade不可

このような背景から、後回しにしていた移行作業が急務となり、サービス稼働を継続しながら移行を実施する必要がありました。

移行方針

移行戦略と2つの重要なポイント

ポイント1: サービス断は絶対NG

ZOZOTOWNは24時間365日稼働しているECサイトであり、サービス断は避けなければいけません。

そのため、以下のような対策を徹底しました。

  • カナリアリリースを採用してサービス影響を最小化
  • 開発環境、検証環境で十分に手順検証と影響確認を実施してから本番環境で移行を実施
  • 問題が発生してもすぐに戻せるよう各ステップの変更に対して詳細な切り戻し手順を用意

ポイント2: いかに工数を最小限に抑えるか

移行手順の詳細検討の結果、弊ブロックで実施してきた従来のIstioアップグレード手順をベースにできることが判明しました。

この発見を活かし、v1.23.2のIstio Operatorからv1.25.3のHelmへの移行を実施しました。

このアプローチにより、EOL対応とIstio Operator脱却を同時に達成し、工数を大幅に削減できます。

ただし、サービス断なしの要件を満たすため、リスク管理には特に注意を払う必要がありました。特に、Upgradeに伴う変更内容も把握する必要があったので、Istioのリリースノートを確認したり、切り戻し手順の整備に充分な時間を確保しました。

各移行先の比較検討

以下の観点から各手法を詳細に検討しました。

項目 Istio Operator istioctl Helm
リソース管理方式 カスタムリソースで一括管理 CLIツールで直接デプロイ Helmチャートでコンポーネントごとに管理
GitOps対応 ◎ FluxCDで管理可能 × CLI実行が必要 ◎ HelmReleaseで完全対応
設定の柔軟性 ◎ IstioOperator API ◎ IstioOperator API △ valuesで対応しきれるかは不明
公式サポート × 非推奨(v1.23まで) ◎ 継続サポート ◎ 継続サポート
カナリアアップグレード ◎ 可能 ◎ 可能 ◎ 可能

非推奨の発表が出た段階で移行先の検討は過去に進められており、istioctlおよびHelmの2つが主な選択肢として検討されました。

当初、istioctl installは以下のメリットから有力候補でした。

  • IstioOperator APIをそのまま使用でき、移行が比較的スムーズ
  • カナリアアップグレードが引き続き可能
  • Istio公式が推奨する方法で今後もサポートが継続される

しかし、istioctl用のCI/CDが必要なこと、FluxCDとの統合が困難であること、GitOpsワークフローに組み込みにくいことが課題となりました。ZOZOTOWNでは「CIOpsからGitOpsへ。Flux2でマイクロサービスのデプロイを爆速にした話」で紹介しているように、FluxCDを使用したGitOps基盤を採用しています。この基盤との親和性が重要な要件でした。

一方、Istio Operatorの非推奨が発表された際、Helmはalpha版だったため、移行するリスクや難易度が高いと判断しました。そのため、すぐに対応が必要というほどの緊急度ではないとして、移行は後回しにされてきました。

しかし、version 1.23から先にUpgrade不可であることが判明し、Istio Operator脱却の温度感が高い状況になりました。そして、移行プロジェクトを開始する頃には、ZOZOTOWNのエコシステムでもHelmの利用が一般的になってきていたため、Helmを選択しました。

さらに、ZOZOTOWNで採用しているFluxCDのHelmReleaseを使用することで、既存のGitOpsへ統合できます。他のKubernetesアプリケーションと同じツールで宣言的に管理できることも大きな決め手となりました。

下図に示すように、Istio OperatorとHelmはどちらもIaCとして宣言的に管理できる点で本質的には共通しています。Helmは業界標準のパッケージマネージャーとして、エコシステムとの統合性に優れています。

Istio OperatorとHelmの比較図

Helmを選択したものの、Istio OperatorからHelmへの移行には課題が残っていました。

まず、Istio公式のHelm upgrade手順では、HelmベースのIstioインストール間でのアップグレード手順のみが記載されていました。Operator環境からの移行に必要な既存リソースの扱い方や完全削除の方法といった移行方法は言及されていませんでした。また、IstioOperatorとHelm valuesでは設定の階層構造とパラメータ名が大きく異なり、全ての設定を1対1でマッピングできるかが不明でした。特にZOZOTOWNのプラットフォーム基盤ではIstioのIngressGatewayを利用しており、かなり細かい設定が適用されていました。それらを網羅しないとサービス断につながるため、慎重な移行計画が必要でした。

これらの課題をどのように解決したかについては、「技術的な課題と解決方法」で詳しく説明します。

技術的な課題と解決方法

前述した移行プロジェクトで直面した技術的な課題とその解決方法を詳しく解説します。Istio OperatorからHelmへの移行は、単純な置き換えではなく、いくつかの固有の課題への対応が必要でした。

移行は大きく3つのフェーズ(Control Plane導入、Data Planeのカナリアアップグレード、Istio Operator削除)で実施しました。Data PlaneのカナリアアップグレードはIstio公式のHelm upgrade手順を参考にしました。しかし、Control Plane導入とIstio Operator削除のフェーズを中心にIstio Operator特有の課題がいくつか発生しました。

これから、主に3つの課題とその解決方法を解説していきます。

課題1: Istio OperatorとHelmのリソース競合

第1の課題は、IstioにおけるCRDの管理権限を、Istio OperatorからHelmに移転する方法でした。

IstioのCRD管理にはistio-baseというHelmチャートが用意されています。しかし、istio-baseをデプロイしようとすると以下のようなエラーが発生します。

エラー例:

Warning InstallFailed: Helm install failed for release istio-system/istio-base with chart base@1.25.3:
Unable to continue with update: CustomResourceDefinition "wasmplugins.extensions.istio.io" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata

以下の図でこのエラーの状態を説明します。まず、Istio OperatorやHelmにおけるリソース管理は、各リソースに所有者情報がメタデータとして記録されます。 istio-baseによってデプロイされるリソースは、すでにIstio Operatorのコントローラーが作成しています。その状態でistio-baseをデプロイすると同じリソース名でcreateの処理が走ります。Kubernetesでは同じ名前でリソースをデプロイしようとすると、名前の競合によりエラーになってしまうので、Helmの管理下に置き換わっていない状態です。

Istio CRDの切り替えPart1

解決方法:

既存のリソースにHelm管理用のラベル・アノテーションを付与するスクリプトを作成し実行しました。

#!/bin/bash
kubectl label sa istio-reader-service-account -n istio-system app.kubernetes.io/managed-by=Helm --overwrite
kubectl annotate sa istio-reader-service-account -n istio-system meta.helm.sh/release-name=istio-base --overwrite
kubectl annotate sa istio-reader-service-account -n istio-system meta.helm.sh/release-namespace=istio-system --overwrite

kubectl label customresourcedefinition wasmplugins.extensions.istio.io app.kubernetes.io/managed-by=Helm --overwrite   
kubectl annotate customresourcedefinition wasmplugins.extensions.istio.io meta.helm.sh/release-name=istio-base --overwrite
kubectl annotate customresourcedefinition wasmplugins.extensions.istio.io meta.helm.sh/release-namespace=istio-system --overwrite
...

Istio CRDの切り替えPart2

このラベルとアノテーションにより、Helmが既存のリソースを認識し、管理下に置くことができました。これにより、既存のCRDを削除せずに、Helmの管理下にスムーズに移行できました。

課題2: Helm Chartで提供されない項目の設定方法

第2の課題は、Helm Chartのvaluesとして提供されないが、IstioOperatorで細かく設定される項目の設定方法でした。

特にZOZOTOWNで運用しているIngressGatewayの設定は数百行の設定が存在していました。これらの設定を全てHelmに移行する必要がありました。

Helmでは、以下のようにvaluesを通じて設定をカスタマイズできる仕組みが提供されています。valuesファイルに定義された設定が処理され、最終的なKubernetesマニフェストが生成・applyされます。以下はFluxCDのカスタムリソースであるHelmReleaseを用いた例です。

valuesでの設定例(HelmRelease)

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: istio-ingressgateway
  namespace: default
spec:
  interval: 5m
  chart:
    spec:
      chart: gateway
      version: 1.25.3
      sourceRef:
        kind: HelmRepository
        name: istio
        namespace: istio-system
  dependsOn:
    - name: istiod
      namespace: istio-system
  values:
    resources:
      limits:
        cpu: "2"
        memory: "3Gi"
      requests:
        cpu: "2"
        memory: "3Gi"

しかし、Helmチャートで公開されているvaluesスキーマ(gateway/values.yamlで確認可能)は、すべての設定項目をカバーしているわけではありません。version 1.25.3現在、ZOZOTOWNのIstio IngressGatewayで設定していた以下の項目が、Helmチャートでは対応できないことが判明しました。

  • コンテナのライフサイクル設定(最新versionはvaluesで設定可能)
  • DNS設定のカスタマイズ

解決方法:

この問題を解決するため、HelmReleaseのPost Renderers機能を活用しました。Post Renderersは、Helmがテンプレートからマニフェストを生成した後、それをKubernetes環境へ適用する前に、任意の変換処理を挿入できる機能です。FluxCDのHelmReleaseでは、Post Renderersを宣言的に定義できるため、GitOpsワークフローとシームレスに統合されます。

我々は、KustomizeをPost Renderersとして使用し、valuesでカバーできない設定を追加するアプローチを採用しました。

HelmReleaseのPostRenderers

Post Renderers利用での設定例(HelmRelease)

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: istio-ingressgateway
  namespace: default
spec:
  interval: 5m
  chart:
    spec:
      chart: gateway
      version: 1.25.3
      sourceRef:
        kind: HelmRepository
        name: istio
        namespace: istio-system
  dependsOn:
    - name: istiod
      namespace: istio-system
  values:
    resources:
      limits:
        cpu: "2"
        memory: "3Gi"
      requests:
        cpu: "2"
        memory: "3Gi"
  postRenderers:
    - kustomize:
        patches:
          - patch: |
              apiVersion: apps/v1
              kind: Deployment
              metadata:
                name: istio-ingressgateway
                namespace: default
              spec:
                template:
                  spec:
                    dnsConfig:
                      options:
                        - name: "ndots"
                          value: "1"

このPost Renderersを使用したアプローチにより、IstioOperatorのすべての設定をHelmReleaseに移行できました。

課題3: Istio Operatorをいかに安全に削除するか

第3の課題は、Istio Operatorの安全な削除方法の確立でした。

IstioOperatorにはKubernetesのFinalizerが付与されています。Finalizerとは、対象リソースの依存関係を考慮した削除処理を行う仕組みです。例えば、リソースを削除するとFinalizerで定義された処理が走り、その処理が完了するまで対象リソースは削除されません。IstioOperatorの場合、自身が管理するリソースを削除してから自身を削除する動作となっています。この仕様により、不用意なIstioOperator削除は、稼働中のIstioコンポーネントの完全削除につながり、サービス断のリスクがありました。

istio-operatorの削除Part1

検証でこの動作を確認したところ、CRDの所有権は既にHelmへ置き換わっているので、Istio OperatorのコントローラがCRDを削除しようとしても、Helmによって保護されます。そして、IstioOperatorはDeletionTimestampが設定された状態で永続に残り続けてしまう問題がありました。

解決方法:

この問題を解決するため、以下の手順を確立しました。

  1. IstioOperatorからFinalizerを削除
  2. 不要となった旧バージョンのIstiodやIngressGatewayを個別に削除
  3. Finalizerがない状態でのIstioOperatorリソース削除

istio-operatorの削除Part2

このアプローチにより、稼働中のサービスに影響を与えることなく、安全にIstioOperatorを削除できました。

# Finalizerを削除
kubectl patch istiooperator istio-control-plane-1-23-2 -n istio-system \
  --type='merge' -p '{"metadata":{"finalizers":[]}}'

# 関連リソースも合わせて削除
kubectl delete deployment istiod-1-23-2 -n istio-system
kubectl delete deployment istio-ingressgateway-1-23-2 -n istio-system
kubectl delete serviceaccount istio-operator -n istio-system
kubectl delete clusterrole istio-operator
kubectl delete clusterrolebinding istio-operator

各コンポーネントの削除後、カスタムリソースのIstioOperatorを削除し、最後にコントローラーとして役目を終えたistio-operator(deployment)を削除しました。

結果

上記の技術的課題を解決し、以下の成果を達成しました。

  • 段階的な切り替えと詳細な切り戻し手順によりサービス断なしでの移行を実現
  • v1.23.2 → v1.25.3へのアップグレードを同時に実施し、工数を大幅削減
  • 今後も継続してIstio Upgradeが可能

まとめ

本記事では、Istio OperatorからHelmへの移行における詳細な手順と技術的な課題の解決方法を紹介しました。

移行作業では「サービス断は絶対NG」という前提を守りつつ、Istioのバージョンアップと工数圧縮も同時に実現できました。

今後は、Helmベースでの運用を継続し、より安定的で保守しやすいIstioの運用体制を構築していきます。同様の移行を検討されている方の参考になれば幸いです。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

hrmos.co

corp.zozo.com

カテゴリー