電通総研 テックブログ

電通総研が運営する技術ブログ

Argo CDを使ってIstioをバージョンアップする

こんにちは。X(クロス)イノベーション本部クラウドイノベーションセンターの柴田です。

この記事は 電通国際情報サービス Advent Calendar 2022 の5日目の投稿です。 前日の記事は宮澤さんの「お金をかけずにAWS Certified SysOps Administrator - Associateに合格した話」でした。

さて、この記事ではArgo CDを使ってIstioをバージョンアップする方法を紹介します。

はじめに

Istioとは

Istio はサービスメッシュを実現するOSSの1つです。

サービスメッシュとは、マイクロサービスにおけるトラフィック管理、可観測性、セキュリティなどを、インフラストラクチャレイヤーで透過的に実現する仕組みです。

サービスメッシュがどんな課題を解決するものかは、以下のスライドが参考になります。

サービスメッシュは本当に必要なのか、何を解決するのか / Service meshes - Do we really need them? What problems do they solve? - Speaker Deck

Istioはデータプレーンとコントロールプレーンの2つのコンポーネントから構成されます。

  • データプレーン : 実際にサービス間通信を行う部分です。 アプリケーションのプロキシとして Envoy を起動します (サイドカーコンテナとして起動するケースが多いです)。 Envoyはトラフィック管理、可観測性、セキュリティなどの機能を提供します。
  • コントロールプレーン : Envoyの設定を管理・更新します。

1

Istioのサポートポリシーは Supported Releases に定義されています。 概要は以下のとおりです。

  • 4半期に1回、マイナーリリースを行う。
  • 各マイナーリリースのサポート(=セキュリティパッチの提供など)はN+2マイナーリリースの6週間後まで提供される。
    • 例: v1.11 のサポートは v1.13.0 をリリースした6週間後まで提供される。

Argo CDとは

Argo CDKubernetes用の継続的デリバリーツールの1つです。

Argo CDは、gitリポジトリで管理されたKubernetesマニフェストの変更を、Kubernetesクラスタへデプロイします。

2

Argo CDは GitOps という手法に基づいています。 GitOpsはWeaveworks社が提唱した継続的デリバリー・継続的デプロイメントの方法であり、以下の特徴があります。

  • システム全体が宣言的に記述されていること。
  • マニフェストがgitで管理され、それが信頼できる唯一の情報源(Single Source of Truth)であること。
  • 承認されたマニフェストの変更が自動的にデプロイされること。またその際Kubernetesクラスタへの認証情報を外部(例えばCIサーバなど)に持たせる必要がないこと。
  • マニフェストKubernetesクラスタの間に差分がある場合、それを検知したり、自動的に修正したりできること。

Istioをどうやってバージョンアップするか

先述した通りIstioの各マイナーリリースはリリースから約6〜8ヶ月後にサポートが終了します。 そのため定期的にIstioをバージョンアップする必要があります。

公式ドキュメント には以下の3つのバージョンアップ方法が紹介されています。

  1. istioctl を使ってIn-place upgradeする方法
  2. istioctl を使ってCanary upgradeする方法
  3. Helmを使ってCanary upgradeする方法(α版)

なお、In-place upgradeの場合、バージョンアップ前後のバージョン差異は1マイナーリリース以内である必要があります。3 また、Canary upgradeの場合、バージョンアップ前後のバージョン差異は2マイナーリリース以内であることが推奨されています。4

実案件の多くは、Kubernetesマニフェストのデプロイを、Argo CDなどの継続的デリバリーツールを使って行います。 しかし、上述のドキュメントでは、Kubernetesクラスタ管理者が手元からコマンドを実行してバージョンアップする方法しか紹介されていません。 そこで本記事では、Argo CDを使ってIstioをバージョンアップする方法を紹介します。

今回は以下の理由から方法3をベースとします。

  • 公式ドキュメントではIn-place upgradeよりもCanary upgradeを推奨しているため。5
  • Argo CDをはじめ6、多くの継続的デリバリーツールがHelmをサポートしているため。

Argo CDを使ってIstioをバージョンアップする

想定する環境

本記事では以下の環境を前提とします。

  • Amazon EKS v1.23
  • Argo CD v2.4.14
  • Istio v1.13.4 → v1.15.3

またサンプルアプリケーションとしてIstio公式のサンプルアプリケーションである Bookinfoアプリケーション がデプロイされているものとします。

環境を構築する

Amazon EKS

Amazon EKSクラスタを構築します。

本記事では詳細な手順は割愛します。 詳しくは Amazon EKS クラスターの作成 - Amazon EKS をご参照ください。

Argo CD

KubernetesクラスタへArgo CDをデプロイします。

本記事では詳細な手順は割愛します。 詳しくは以下の公式ドキュメントをご参照ください。

Istio

IstioのHelm chartは以下の3つを使用します。

本記事では以下の手順でKubernetesクラスタにIstio v1.13.4がインストールされているものとします。

  1. 必要なnamespaceを作成します。
$ kubectl create namespace istio-system
$ kubectl create namespace istio-ingress
  1. istio-ingress namespaceに automatic sidecar injection を有効にするためのlabelを設定します。
$ kubectl label namespace istio-ingress istio-injection=enabled
  1. 以下のArgo CDのApplication CRを kubectl apply コマンドでデプロイします。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istio-base
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: base
    targetRevision: 1.13.4
    helm:
      releaseName: istio-base
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-system
  ignoreDifferences:
  - group: admissionregistration.k8s.io
    kind: ValidatingWebhookConfiguration
    name: istiod-default-validator
    jsonPointers:
    - /webhooks/0/failurePolicy
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istiod
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: istiod
    targetRevision: 1.13.4
    helm:
      releaseName: istiod
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-system
  ignoreDifferences:
  - group: admissionregistration.k8s.io
    kind: MutatingWebhookConfiguration
    name: istio-sidecar-injector
    jsonPointers:
    - /webhooks/0/clientConfig/caBundle
    - /webhooks/1/clientConfig/caBundle
    - /webhooks/2/clientConfig/caBundle
    - /webhooks/3/clientConfig/caBundle
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istio-ingress
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: gateway
    targetRevision: 1.13.4
    helm:
      releaseName: istio-ingress
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-ingress
  1. 上述のApplication CRについてArgo CDのWeb UIからsyncを実行してIstioをデプロイします。
    • syncは istio-baseistiodistio-ingress の順に実行します。
    • 本記事ではArgo CDのWeb UIのアクセス方法および操作方法に関する説明は割愛します。詳細は Argo CDの公式ドキュメント をご参照ください。

サンプルアプリケーション

本記事ではサンプルアプリケーションとして default namespaceにIstio公式のサンプルアプリケーションである Bookinfoアプリケーション がデプロイされているものとします。

  1. default namespaceに automatic sidecar injection を有効にするためのlabelを設定します。
$ kubectl label namespace default istio-injection=enabled
  1. Bookinfoアプリケーション をデプロイします。
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/1.13.4/samples/bookinfo/platform/kube/bookinfo.yaml
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/1.13.4/samples/bookinfo/networking/bookinfo-gateway.yaml
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/1.13.4/samples/bookinfo/networking/destination-rule-all.yaml
  1. Gateway bookinfo-gateway.spec.selectoristio=ingressgateway から istio=ingress へ変更します。
$ kubectl patch gateways.networking.istio.io bookinfo-gateway --type=merge -p '{"spec":{"selector":{"istio":"ingress"}}}'

手順1. Canary upgradeが可能か確認する

以下の条件を満たしているか確認します。

  • Istioのバージョンアップ前後のバージョン差異が2マイナーリリース以内であること。
    • 例えば、現在のバージョンが 1.13.x の場合、 1.14.x1.15.x へバージョンアップできます。
  • istio/baseistio/gateway 、CRDに破壊的変更がないこと。
    • これらのリソースはバージョンアップ前後で共有されるためです。
  • istio/istiod がバージョンアップ前後で独立しており同じリソースを共有しないこと。
    • 古いバージョンの istio/istiod を安全に削除するためです。
    • なお istio/istiod のパラメータ revision にはバージョンアップ前後で異なる値を設定します。
  • kubectl rollout restart コマンドでアプリケーションのPodを安全に再作成できること。
    • PodがGraceful Shutdownするよう実装・設定されているか。
    • PodのUpdate strategyが適切に設定されているか。
  • 以下の手順でバージョンアップ前後の互換性が確認できていること。
    1. 更新後のバージョンの istioctlGitHubのリリース からダウンロードする。
    2. istioctl x precheck コマンドを実行して互換性を確認する。
$ istioctl x precheck
✔ 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/>

手順2. istio/base (CRDを含む)を更新する

  1. Application CR istio-basetargetRevision を更新します。これによりCRDなどが更新されます。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istio-base
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: base
    targetRevision: 1.15.3
    helm:
      releaseName: istio-base
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-system
  ignoreDifferences:
  - group: admissionregistration.k8s.io
    kind: ValidatingWebhookConfiguration
    name: istiod-default-validator
    jsonPointers:
    - /webhooks/0/failurePolicy

本来、 helm upgrade コマンドや helm uninstall コマンドでhelm chartを更新/削除しても、CRDは更新/削除されません。7 ただし、Argo CDは helm template で生成したマニフェストkubectl apply しているため、Helm chartを更新することで、CRDを更新できます。

手順3. 新しいバージョンの istio/istiod を追加する

  1. 新しいバージョンの istio/istiod のApplication CRをデプロイします。
    • このとき、以下のフィールドは更新後のバージョンにあわせて変更します。
      • .metadata.name
      • .spec.source.targetRevision
      • .spec.source.helm.valuesrevision (*1)
      • .spec.ignoreDifferences 8
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istiod-1-15-3
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: istiod
    targetRevision: 1.15.3
    helm:
      releaseName: istiod
      values: |
        revision: "1-15-3"
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-system
  ignoreDifferences:
  - group: admissionregistration.k8s.io
    kind: MutatingWebhookConfiguration
    name: istio-sidecar-injector-1-15-3
    jsonPointers:
    - /webhooks/0/clientConfig/caBundle
    - /webhooks/1/clientConfig/caBundle
  1. istio-system namespaceに新しいバージョンの istiod が作成されたことを確認します。
$ kubectl -n istio-system get pods,svc,mutatingwebhookconfigurations
NAME                                 READY   STATUS    RESTARTS   AGE
pod/istiod-1-15-3-59d4cf9474-gklrs   1/1     Running   0          11s
pod/istiod-579df55f96-n4tk8          1/1     Running   0          21m

NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                 AGE
service/istiod          ClusterIP   172.20.91.227   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP   21m
service/istiod-1-15-3   ClusterIP   172.20.213.98   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP   11s

NAME                                                                                      WEBHOOKS   AGE
mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector          4          21m
mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector-1-15-3   2          11s
mutatingwebhookconfiguration.admissionregistration.k8s.io/pod-identity-webhook            1          38m
mutatingwebhookconfiguration.admissionregistration.k8s.io/vpc-resource-mutating-webhook   1          37m

手順4. データプレーンを更新する

アプリケーションのPodのサイドカーコンテナとして起動しているEnvoy(以降では istio-proxy と呼びます)を更新します。

今回は automatic sidecar injection を有効にしているため、 istio-proxy はPod作成時にサイドカーコンテナとして自動的に追加されます。 この場合、 automatic sidecar injection が有効なnamespaceについて、namespaceのlabelを更新した後、Podを再作成することで、 istio-proxy を更新できます。

今回対象となるnamespaceは以下の2つです。

  • default namespace
  • istio-ingress namespace

まず default namespaceに対して以下の手順を実施します。

  1. 現在の istio-proxy の状態を確認します。
$ istioctl -n default proxy-status
NAME                                             CLUSTER        CDS        LDS        EDS        RDS        ECDS         ISTIOD                      VERSION
details-v1-6bd666858f-wq2fr.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-579df55f96-n4tk8     1.13.4
productpage-v1-7f6655c647-s8gdf.default          Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-579df55f96-n4tk8     1.13.4
ratings-v1-7cc7df5fd5-slqgd.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-579df55f96-n4tk8     1.13.4
reviews-v1-68c7d56667-nvv5q.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-579df55f96-n4tk8     1.13.4
reviews-v2-759496d8df-gkgdh.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-579df55f96-n4tk8     1.13.4
reviews-v3-7545ff7c75-68n7b.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-579df55f96-n4tk8     1.13.4
  1. namespaceのlabelを更新します。
    • istio.io/rev=<(*1)と同じ文字列> labelを設定します。
    • istio-injection labelが存在する場合は削除します。
$ kubectl label namespace default istio.io/rev=1-15-3
$ kubectl label namespace default istio-injection-
  1. 先程のnamespaceのPodを再作成します。
$ kubectl -n default rollout restart deployment
  1. 変更後の istio-proxy の状態を確認します。
    • 特に ISTIOD 列と VERSION 列が新しくなっていることを確認します。
$ istioctl proxy-status
NAME                                             CLUSTER        CDS        LDS        EDS        RDS        ECDS         ISTIOD                             VERSION
details-v1-5954bb9d8-xn5j6.default               Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-15-3-59d4cf9474-gklrs     1.15.3
productpage-v1-7f6bff5ddd-ms4b4.default          Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-15-3-59d4cf9474-gklrs     1.15.3
ratings-v1-6f8d5bf8d4-f2jmm.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-15-3-59d4cf9474-gklrs     1.15.3
reviews-v1-785b65d7c4-6j4wq.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-15-3-59d4cf9474-gklrs     1.15.3
reviews-v2-86b446779b-9wx5q.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-15-3-59d4cf9474-gklrs     1.15.3
reviews-v3-5b5b976fbb-cc2j9.default              Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED     NOT SENT     istiod-1-15-3-59d4cf9474-gklrs     1.15.3

次に istio-ingress namespaceに対しても同様の手順を実施します。 default namespaceと同じ内容のため詳細は割愛します。

Canary upgradeではこのようにnamespace単位で徐々にデータプレーンを更新できます。 また、もし問題が発生した場合はnamespaceのlabelをもとに戻してPodを再作成することでデータプレーンの更新をロールバックできます。

手順5. istio/basedefaultRevision を更新する

  1. Application CR istio-base.spec.source.helm.valuesdefaultRevision を(*1)と同じ文字列へ更新します。 これによりValidatingWebhookConfiguration istiod-default-validator の宛先が古いバージョンの istiod から新しいバージョンの istiod へ変更されます。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istio-base
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: base
    targetRevision: 1.15.3
    helm:
      releaseName: istio-base
      values: |
        defaultRevision: "1-15-3"
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-system
  ignoreDifferences:
  - group: admissionregistration.k8s.io
    kind: ValidatingWebhookConfiguration
    name: istiod-default-validator
    jsonPointers:
    - /webhooks/0/failurePolicy

手順6. istio/gateway を更新する

  1. Application CR istio-ingresstargetRevision を更新します。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istio-ingress
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: gateway
    targetRevision: 1.15.3
    helm:
      releaseName: istio-ingress
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-ingress

手順7. 古いバージョンの istio/istiod を削除する

  1. 古いバージョンの istio/istiod のApplication CRにfinalizerを設定します。
    • Application CRの削除と同時に関連するリソースを削除するためです。9
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: istiod
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://istio-release.storage.googleapis.com/charts
    chart: istiod
    targetRevision: 1.13.4
    helm:
      releaseName: istiod
  destination:
    server: https://kubernetes.default.svc
    namespace: istio-system
  ignoreDifferences:
  - group: admissionregistration.k8s.io
    kind: MutatingWebhookConfiguration
    name: istio-sidecar-injector
    jsonPointers:
    - /webhooks/0/clientConfig/caBundle
    - /webhooks/1/clientConfig/caBundle
    - /webhooks/2/clientConfig/caBundle
    - /webhooks/3/clientConfig/caBundle
  1. 古いバージョンの istio/istiod のApplication CRを削除します。
  2. istio-system namespaceから古いバージョンの istio/istiod が削除されたことを確認します。
$ kubectl -n istio-system get pods,svc,mutatingwebhookconfigurations
NAME                                 READY   STATUS    RESTARTS   AGE
pod/istiod-1-15-3-59d4cf9474-gklrs   1/1     Running   0          6m1s

NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                 AGE
service/istiod-1-15-3   ClusterIP   172.20.213.98   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP   6m1s

NAME                                                                                      WEBHOOKS   AGE
mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector-1-15-3   2          6m1s
mutatingwebhookconfiguration.admissionregistration.k8s.io/pod-identity-webhook            1          43m
mutatingwebhookconfiguration.admissionregistration.k8s.io/vpc-resource-mutating-webhook   1          43m

おわりに

この記事ではArgo CDを使ってIstioをバージョンアップする方法を紹介しました。

バージョンアップはシステムをセキュアな状態に維持するために欠かせない作業です。 一方でIstioのバージョンアップは、サービスメッシュ上の全アプリケーションに影響のある作業でもあります。 安全かつ効率的なバージョンアップ方法を確立していきたいですね。

最後までお読みいただき、ありがとうございました。


私たちは同じチームで働いてくれる仲間を探しています。クラウドアーキテクトの業務に興味がある方のご応募をお待ちしています。

執筆:@shibata.takao、レビュー:寺山 輝 (@terayama.akira)Shodoで執筆されました