Istio 1.6.0 のアップグレード機能をお試し(In place upgrades編)

ちょっと前に「Istio 1.5が出たなぁ」って少し触ってみたんだけど。

bufferings.hatenablog.com

そうこうしてるうちに、もう1.6が出てしまった。3ヶ月ってはやいな。

Istio / Announcing Istio 1.6

そう。1.6が出たってことは1.5もあと3ヶ月の命。そんな風にライフサイクルが短いからIstio自体のアップグレードが大変だよなぁと思っているんだけど、今回、コントロールプレーンのアップグレード方法が改善されたみたい。カナリアリリースもサポートしたよって書いてある。面白そう。

Istio / Safely Upgrade Istio using a Canary Control Plane Deployment

ということで、触ってみようと思う。

## 環境

GKE立ち上げた。

❯ kubectl get nodes
NAME                                       STATUS   ROLES    AGE   VERSION
gke-cluster-1-default-pool-019aa731-6ztc   Ready    <none>   21m   v1.16.8-gke.15
gke-cluster-1-default-pool-019aa731-spbj   Ready    <none>   21m   v1.16.8-gke.15
gke-cluster-1-default-pool-019aa731-ztjz   Ready    <none>   21m   v1.16.8-gke.15

インストール用の設定ファイルはこんな感じにしておいた。Stackdriverの連携をしてるだけ。今回はStackdriver使わんからあんまり関係ないけど。

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: default

  addonComponents:
    prometheus:
      enabled: false

  values:
    global:
      proxy:
        tracer: "stackdriver"
      logAsJson: true
    telemetry:
      v2:
        enabled: true
        prometheus:
          enabled: false
        stackdriver:
          enabled: true
          logging: true
          monitoring: true
          # topology: true
          configOverride: {}

## 2通りのアップグレード方法

ここを読みながらやってみる:

Istio / Upgrade Istio

2つのアップグレード方法が紹介されてる。

  • Canary upgrades
  • In place upgrades

In place upgradesを最初にやってみて、その後Canary upgradesをやろうと思う。アップグレード前のバージョンはv1.5.4にしようかな。そこからv1.6.0へのアップグレードを試してみよう。

## (1) In place upgrades

まずはIn place upgradesから。この方法は以前からあったのかもしれない?

前提条件は:

  • 現在のIstioのバージョンが1.4.4以降であること
  • 現在のIstioがistioctlでインストールされていること

### Install Istio 1.5

じゃ、1.5を入れる。

❯ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.5.4 sh - 

❯ cd istio-1.5.4

# 上で書いた設定を config.yaml という名前で置いておいた
❯ bin/istioctl manifest apply -f config.yaml                   
- Applying manifest for component Base...
✔ Finished applying manifest for component Base.
- Applying manifest for component Pilot...
✔ Finished applying manifest for component Pilot.
  Waiting for resources to become ready...
  Waiting for resources to become ready...
  Waiting for resources to become ready...
  Waiting for resources to become ready...
  Waiting for resources to become ready...
  Waiting for resources to become ready...
- Applying manifest for component IngressGateways...
✔ Finished applying manifest for component IngressGateways.


✔ Installation complete

それから、いつものbookinfoアプリを入れる。

# サイドカーの自動インジェクションを有効に
❯ kubectl label namespace default istio-injection=enabled
namespace/default labeled

# Bookinfoサービスをデプロイ
❯ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created

# Gatewayをデプロイ
❯ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created

# LBのIPアドレスを取得export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

# ブラウザで開く(Ubuntu)
❯ xdg-open http://$INGRESS_HOST/productpage

見慣れたページが表示された。

### Upgrade to Istio 1.6

注意点として「トラフィック断が発生する可能性があるから、断を最小化するためにそれぞれのコンポーネントを少なくとも2つ以上動かしておいて PodDisruptionBudgets で1個は起動し続けるようにしておきましょう」って書いてある。今回は、そういうの何にもしてない。

1.6をダウンロード:

❯ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.0 sh - 

❯ cd istio-1.6.0

# 上で書いた設定を config.yaml という名前で置いておいた

このistio-1.6.0に入ってる istioctl を使う。まずはこのistioctlがサポートしてるバージョンの確認

❯ bin/istioctl manifest versions

Binary version is 1.6.0.

This version of istioctl can:
  Install Istio 1.6.0
  Update Istio from >=1.5.0 to 1.6.0
  Update Istio from  <1.7 to 1.6.0

大丈夫だね。それと今のバージョンを確認しておこうか:

❯ bin/istioctl version          
client version: 1.6.0
control plane version: 1.5.4
data plane version: 1.5.4 (7 proxies)

では、アップグレード:

❯ bin/istioctl upgrade -f config.yaml 
2020-05-23T04:57:09.273649Z     info    proto: tag has too few fields: "-"
Control Plane - ingressgateway pod - istio-ingressgateway-7f76b9fc9f-66rv4 - version: 1.5.4
Control Plane - pilot pod - istiod-6558b7b7f4-v2jhw - version: 1.5.4                                      

2020-05-23T04:57:10.295956Z     warn    found 6 CRD of unsupported v1alpha1 security policy: [clusterrbacconfigs.rbac.istio.io meshpolicies.authentication.istio.io policies.authentication.istio.io rbacconfigs.rba
c.istio.io servicerolebindings.rbac.istio.io serviceroles.rbac.istio.io]. The v1alpha1 security policy is no longer supported starting 1.6. It's strongly recommended to delete the CRD of the v1alpha1 security pol
icy to avoid applying any of the v1alpha1 security policy in the unsupported version
Upgrade version check passed: 1.5.4 -> 1.6.0.

しばらく待つと、差分が表示された:

Upgrade check: Warning!!! The following IOPS will be changed as part of upgrade. Please double check they are correct:
components:                                          
  galley: map[enabled:false k8s:map[replicaCount:1 resources:map[requests:map[cpu:100m]]
    strategy:map[rollingUpdate:map[maxSurge:100% maxUnavailable:25%]]]] ->
  ingressGateways:                                   
    '[#0]':                                          
      k8s:                                           
        service:                                     
          ports:                                     
            '[#0]':                                  
              port: 15020 -> 15021                   
              targetPort: 15020 -> 15021                                                                  
            '[#1]':                                  
              targetPort: 80 -> 8080                                                                      
            '[#2]':                                  
              targetPort: -> 8443                    
            '[3->?]': map[name:kiali port:15029 targetPort:15029] ->                                      
            '[4->?]': map[name:prometheus port:15030 targetPort:15030] ->
            '[5->?]': map[name:grafana port:15031 targetPort:15031] ->                                    
            '[6->?]': map[name:tracing port:15032 targetPort:15032] ->                                    
            '[8->?]': map[name:tcp port:31400] ->                                                         
  istiodRemote: -> map[enabled:false]                                                                     
  nodeAgent: map[enabled:false] ->                   
  pilot:                                             
    k8s:                                             
      readinessProbe:                                
        initialDelaySeconds: 5 -> 1                                                                       
        periodSeconds: 5 -> 3                        
      resources: map[requests:map[cpu:500m memory:2048Mi]] ->                                             
  sidecarInjector: map[enabled:false k8s:map[replicaCount:1 strategy:map[rollingUpdate:map[maxSurge:100%
    maxUnavailable:25%]]]] ->                        
installPackagePath: /tmp/istio-install-packages/istio-1.5.4/install/kubernetes/operator
  ->                                                 
meshConfig: -> map[enablePrometheusMerge:false]                                                           
values:                                                                                                                                                                                                             
  base: -> map[validationURL:]                                                                                                                                                                                      
  galley: map[enableAnalysis:false image:galley] ->                                                                                                                                                                 
  gateways:                                                                                                                                                                                                         
    istio-ingressgateway:                                                                                                                                                                                           
      meshExpansionPorts:                                                                                                                                                                                           
        '[#3]':                                                                                                                                                                                                     
          targetPort: 853 -> 8853                                                                                                                                                                                   
      sds: map[enabled:false image:node-agent-k8s resources:map[limits:map[cpu:2000m                                                                                                                                
        memory:1024Mi] requests:map[cpu:100m memory:128Mi]]] ->                                                                                                                                                     
      zvpn:                                                                                                                                                                                                         
        enabled: false ->                                                                                                                                                                                           
        suffix: global ->                                                                                                                                                                                           
  global:                                                                                                                                                                                                           
    disablePolicyChecks: true ->                                                                                                                                                                                    
    enableTracing: true ->                                                                                                                                                                                          
    imagePullPolicy: IfNotPresent ->                                                                                                                                                                                
    istiod:                                                                                                                                                                                                         
      enableAnalysis: -> false                                                                                                                                                                                      
    k8sIngress: map[enableHttps:false enabled:false gatewayName:ingressgateway] ->                                                                                                                                  
    localityLbSetting: map[enabled:true] ->                                                                                                                                                                         
    mtls: map[auto:true enabled:false] ->                                                                                                                                                                           
    outboundTrafficPolicy: map[mode:ALLOW_ANY] ->                                                                                                                                                                   
    policyCheckFailOpen: false ->                                                                                                                                                                                   
    proxy:                                                                                                                                                                                                          
      accessLogEncoding: TEXT ->                                                                                                                                                                                    
      concurrency: 2 ->                                                                                                                                                                                             
      dnsRefreshRate: 300s ->                                                                                                                                                                                       
      envoyAccessLogService: map[enabled:false host:<nil> port:<nil>] ->                                                                                                                                            
      envoyMetricsService: map[enabled:false host:<nil> port:<nil> tcpKeepalive:map[interval:10s                                                                                                                    
        probes:3 time:10s] tlsSettings:map[caCertificates:<nil> clientCertificate:<nil>
        mode:DISABLE privateKey:<nil> sni:<nil> subjectAltNames:[]]] ->
      includeInboundPorts: '* ->'                    
      protocolDetectionTimeout: 100ms ->                                                                  
    sds:                                             
      enabled: false ->                              
    tracer:                                          
      lightstep:                                     
        secure: true ->                              
  grafana:                                                                                                                                                                                                          
    ingress: map[annotations:<nil> enabled:false hosts:[grafana.local] tls:<nil>]                                                                                                                                   
      ->                                                                                                                                                                                                            
  istiodRemote: -> map[injectionURL:]                                                                                                                                                                               
  kiali:                                                                                                                                                                                                            
    dashboard:                                                                                                                                                                                                      
      auth: -> map[strategy:login]                                                                                                                                                                                  
    ingress: map[annotations:<nil> enabled:false hosts:[kiali.local] tls:<nil>] ->
    service: -> map[annotations:map[]]                                                                    
    tag: v1.15 -> v1.18                              
  mixer:                                             
    telemetry:                                       
      reportBatchMaxEntries: 100 ->                                                                       
      reportBatchMaxTime: 1s ->                      
  nodeagent: map[image:node-agent-k8s] ->                                                                 
  pilot:
    enableProtocolSniffingForInbound: false -> true
    ingress: map[ingressClass:istio ingressControllerMode:STRICT ingressService:istio-ingressgateway]
      ->
    meshNetworks: map[networks:map[]] ->
  prometheus:
    ingress: map[annotations:<nil> enabled:false hosts:[prometheus.local] tls:<nil>]
      ->
  security: map[dnsCerts:map[istio-pilot-service-account.istio-control:istio-pilot.istio-control]
    enableNamespacesByDefault:true image:citadel selfSigned:true] ->
  sidecarInjectorWebhook:
    image: sidecar_injector ->
    selfSigned: false ->
  tracing:
    ingress: map[annotations:<nil> enabled:false hosts:<nil> tls:<nil>] ->
    zipkin:
      probeStartupDelay: 200 -> 10
      resources:
        limits:
          cpu: 300m -> 1000m
          memory: 900Mi -> 2048Mi
      tag: 2.14.2 -> 2.20.0

Confirm to proceed [y/N]?

めっちゃ差分でるやん・・・。とりあえず y 押しとこか。

- Processing resources for Istio core.
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete
Upgrade rollout completed. All Istio control plane pods are running on the target version.


Control Plane - ingressgateway pod - istio-ingressgateway-669dfc8fc4-b6dvz - version: 1.6.0
Control Plane - ingressgateway pod - istio-ingressgateway-669dfc8fc4-zbhtk - version: 1.6.0
Control Plane - pilot pod - istiod-564bb6fbc6-r9dpf - version: 1.6.0

Success. Now the Istio control plane is running at version 1.6.0.

To upgrade the Istio data plane, you will need to re-inject it.
If you’re using automatic sidecar injection, you can upgrade the sidecar by doing a rolling update for all the pods:
    kubectl rollout restart deployment --namespace <namespace with auto injection>
If you’re using manual injection, you can upgrade the sidecar by executing:
    kubectl apply -f < (istioctl kube-inject -f <original application deployment yaml>)

となりでwatchしてたのはこんな感じ。istiodとistio-ingressgatewayが更新されてる。

istio-system   istiod-564bb6fbc6-r9dpf                                     0/1     Pending   0          0s
istio-system   istiod-564bb6fbc6-r9dpf                                     0/1     Pending   0          0s
istio-system   istiod-564bb6fbc6-r9dpf                                     0/1     ContainerCreating   0          0s
istio-system   istiod-564bb6fbc6-r9dpf                                     0/1     Running             0          10s
istio-system   istiod-564bb6fbc6-r9dpf                                     1/1     Running             0          10s
istio-system   istiod-6558b7b7f4-v2jhw                                     1/1     Terminating         0          60m
istio-system   istiod-6558b7b7f4-v2jhw                                     0/1     Terminating         0          60m
istio-system   istio-ingressgateway-669dfc8fc4-b6dvz                       0/1     Pending             0          0s
istio-system   istio-ingressgateway-669dfc8fc4-b6dvz                       0/1     Pending             0          0s
istio-system   istio-ingressgateway-669dfc8fc4-b6dvz                       0/1     ContainerCreating   0          0s
istio-system   istio-ingressgateway-669dfc8fc4-b6dvz                       0/1     Running             0          8s
istio-system   istio-ingressgateway-669dfc8fc4-b6dvz                       1/1     Running             0          8s
istio-system   istio-ingressgateway-7f76b9fc9f-66rv4                       1/1     Terminating         0          60m
istio-system   istiod-6558b7b7f4-v2jhw                                     0/1     Terminating         0          61m
istio-system   istiod-6558b7b7f4-v2jhw                                     0/1     Terminating         0          61m
istio-system   istio-ingressgateway-7f76b9fc9f-66rv4                       0/1     Terminating         0          60m
istio-system   istio-ingressgateway-669dfc8fc4-zbhtk                       0/1     Pending             0          0s
istio-system   istio-ingressgateway-669dfc8fc4-zbhtk                       0/1     Pending             0          0s
istio-system   istio-ingressgateway-669dfc8fc4-zbhtk                       0/1     ContainerCreating   0          0s
istio-system   istio-ingressgateway-7f76b9fc9f-66rv4                       0/1     Terminating         0          60m
istio-system   istio-ingressgateway-7f76b9fc9f-66rv4                       0/1     Terminating         0          60m
istio-system   istio-ingressgateway-669dfc8fc4-zbhtk                       0/1     Running             0          8s
istio-system   istio-ingressgateway-669dfc8fc4-zbhtk                       1/1     Running             0          9s

これでControl Planeの更新は終わり。次はData Plane。まだ今はこんな感じ:

❯ bin/istioctl version
client version: 1.6.0
control plane version: 1.6.0
data plane version: 1.6.0 (1 proxies), 1.5.4 (6 proxies)

Data Planeでいっこだけ1.6.0なのはIngressGatewayのことだと思う。では、ロールアウト:

❯ kubectl rollout restart deployment
deployment.apps/details-v1 restarted
deployment.apps/productpage-v1 restarted
deployment.apps/ratings-v1 restarted
deployment.apps/reviews-v1 restarted
deployment.apps/reviews-v2 restarted
deployment.apps/reviews-v3 restarted

しばらく待つと全部1.6になった。

❯ bin/istioctl version
client version: 1.6.0
control plane version: 1.6.0
data plane version: 1.6.0 (7 proxies)

Bookinfoも動いてる。

## (1-2) In place downgrades

ダウングレードもサポートされてるっぽい。ダウングレード先のバージョンのistioctlを使う。

cd istio-1.5.4

❯ bin/istioctl manifest versions

Operator version is 1.5.4.

The following installation package versions are recommended for use with this version of the operator:
  1.5.0

The following installation package versions are supported for upgrade by this version of the operator:
  >=1.4.0
   <1.6

1.6からのダウングレードは大丈夫みたいね。今はこういう状態:

❯ bin/istioctl version
client version: 1.5.4
control plane version: 1.6.0
data plane version: 1.6.0 (7 proxies)

適用してみよう。ドキュメントには experimental をつけてねって書いてあるけど、それは1.4の場合っぽいな。1.5でやってみたら「もう卒業したから外してね!」って言われた。ということで、外して実行!

❯ bin/istioctl upgrade -f config.yaml                                                                                                                                                                              
Control Plane - ingressgateway pod - istio-ingressgateway-669dfc8fc4-b6dvz - version: 1.6.0
Control Plane - pilot pod - istiod-564bb6fbc6-r9dpf - version: 1.6.0

2020-05-23T05:34:52.325447Z     info    Error: upgrade version check failed: 1.6.0 -> 1.5.4. Error: upgrade is currently not supported: 1.6.0 -> 1.5.4

Error: upgrade version check failed: 1.6.0 -> 1.5.4. Error: upgrade is currently not supported: 1.6.0 -> 1.5.4

(´・ω・`)ショボーン サポートされてないって言われたwどういうことなの?

1.5にダウングレードしたらそのままCanary upgradesをやろうと思ってたけど、ちょうどいいし今回はここまでにしてクラスターをシャットダウンしとこ。Canary upgradesは次回。

追記

読み直してみて気づいたけど、ダウングレードのサポートのとこ

  <1.6

って書いてあるから1.6は含まれてないやん!そっか。1.6系から、1.5系には戻せないってことだな。