ry's Tech blog

Cloud Native技術などについて書いていきます。

Kubenews #54

2021-05-27

Progressive Delivery with Argo Rollouts : Blue-Green Deployment (click here to source)

Progressive Deliveryについてと、Argo Rolloutsを用いたProgressive Deliveryを取り入れていくための、挙動を知るためのデモが書かれている。

従来のCI/CDとプログレッシブデリバリー

各プロセスを以下のように説明している。

継続的インテグレーション(CI)は、ソフトウェア開発の変更を継続的に統合するのに役立つ自動化プロセスです。 ソースコードの構築、テスト、検証を自動化し、目標としては、最終的に展開するアーティファクトを作成することです。

継続的デリバリー(CD)は、ソフトウェアの変更をユーザーに展開するのに役立ちます。

プログレッシブデリバリーは、継続的デリバリーの一歩先を行くことであり、障害のリスクを軽減することで、制御された方法でソフトウェアアップデートを展開できます。

デフォルトの「RollingUpdate」Kubernetesデプロイ戦略の課題

Kubernetesは、現在、以下の制限があるデフォルトのRollingUpdate展開戦略を機能として備えている。

  • ロールアウトの速度の制御が少ない
  • 新しいバージョンへのトラフィックフローを制御できない
  • Readiness probesは、より深いストレス、または1回限りのチェックには適していない
  • アップデートしたものの状態を検証するために外部メトリクスを照会するといった機能がない
  • 進行を停止することはできますが、更新を自動的に中止してロールバックすることはできない

この後、Argo Projectの説明及び、上記のものと比較しながらArgo Rolloutsでできる機能を紹介している。

Lab/Hands-on of Argo Rollouts with Blue-Green Deployments

ここから簡単なDemoに入っていく。

Appendix

今回は手動でBlue-Greenをしたが、以下のようにPrometheusなどのメトリックを基に、切り替えたりできる。

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
  - name: service-name
  metrics:
  - name: success-rate
    interval: 5m
    # NOTE: prometheus queries return results in the form of a vector.
    # So it is common to access the index 0 of the returned array to obtain the value
    successCondition: result[0] >= 0.95
    failureLimit: 3
    provider:
      prometheus:
        address: http://prometheus.example.com:9090
        query: |
          sum(irate(
            istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m]
          )) / 
          sum(irate(
            istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
          ))

Prometheus - Argo Rollouts - Kubernetes Progressive Delivery Controller

これを用いて、Canary ReleaseやBlue-Greenができる。

  • Canary
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
...
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {duration: 5m}
      - analysis:
          templates:
          - templateName: success-rate
          args:
          - name: service-name
            value: guestbook-svc.default.svc.cluster.local

この例では、カナリアの重みを20%に設定し、5分間一時停止してから、分析を実行します。分析が成功した場合は、ロールアウトを続行します。

他にも、複数のAnalysisTemplateを指定もできる。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
...
  strategy:
    canary:
      analysis:
        templates:
        - templateName: success-rate
        - templateName: error-rate
        args:
        - name: service-name
          value: guestbook-svc.default.svc.cluster.local
  • Blue-Green

BlueGreen戦略を使用したロールアウトでは、事前プロモーションを使用してトラフィックを新しいバージョンに切り替える前に検証をして、成功または失敗により、ロールアウトがトラフィックを切り替えるか、ロールアウトを完全に中止するかが決まる。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
...
  strategy:
    blueGreen:
      activeService: active-svc
      previewService: preview-svc
      prePromotionAnalysis:
        templates:
        - templateName: smoke-tests
        args:
        - name: service-name
          value: preview-svc.default.svc.cluster.local

プロモーション後の分析を使用すると、トラフィックが新しいバージョンに切り替わった後に分析実行を開始できる。

プロモーション後の分析が失敗またはエラーになった場合、ロールアウトは中止状態になり、トラフィックを以前の安定したレプリカセットに戻す。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
...
  strategy:
    blueGreen:
      activeService: active-svc
      previewService: preview-svc
      scaleDownDelaySeconds: 600 # 10 minutes
      postPromotionAnalysis:
        templates:
        - templateName: smoke-tests
        args:
        - name: service-name
          value: preview-svc.default.svc.cluster.local

argoproj.github.io

Storage Capacity Tracking reaches GA in Kubernetes 1.24 (click here to source)

私たちが解決した問題

ストレージ容量追跡により、CSIドライバーは残りの容量に関する情報を参照できるようになった。

kube-schedulerは、そのPodにまだプロビジョニングが必要なボリュームがある場合、その情報を使用してPodに適したノードを選択する。

この情報がなければ、kube-schedulerは盲目的に選択する必要がある。

そのため、CSIドライバが管理するストレージシステムに十分な容量が残っておらず、ボリュームをプロビジョニングできないノードを選択してしまうということが発生する。

結果としてPodが適切なノードにスケジュールされずPending状態になるという可能性がある。

(参考)

以下の機能には2つのAPI拡張機能によって実現。

  • CSIStorageCapacityオブジェクト:
    • ドライバがインストールされている名前空間内のCSIドライバによって生成されます。
    • 各オブジェクトには、1つのストレージクラスの容量情報が含まれており、どのノードがそのストレージにアクセスできるかを定義します。
  • CSIDriverSpec.StorageCapacityフィールド:
    • trueに設定すると、KubernetesスケジューラはCSIドライバを使用するボリュームのストレージ容量を考慮します。

私たちが解決していない問題

Podが2つのボリュームを使用すると定義されていて、そのうちの1つだけをプロビジョニングできる状態であった場合、将来のすべてのスケジューリング決定はプロビジョニングされたボリュームによって制限される。

(2VolumeのうちどちらかがPodにプロビジョニングできてしまった場合、その時点でNodeが決まってしまい、万が一そのNodeでもう片方のVolumeが使えないとなったら、Podがスタックするという理解)

ただ、これを解決するためのアイデアは、KEPドラフトで提案されたらしい。

また、ボリュームのあるポッド用のクラスターオートスケーラーのサポートも解決されていない。

(Local Volume用のCSIなどがメインのターゲット???)