Argo Rolloutsの新機能「Experiments」を試す

[Argo Rollouts](https://github.com/argoproj/argo-rollouts/)というプロジェクトはご存知でしょうか？
これはKubernetesのDeploymentにBlue GreenやCanaryリリースの機能を追加するようなプロジェクトです。

具体的にはDeploymentではなく、新しく作られるRolloutというリソースを使うことになるのですが、その定義が非常に似てるため、簡単な書き換えで上記のような多彩なデプロイができるようになります。

この記事では2019年11月にリリースされたv0.6.0で新たに追加された*Experiments*という機能について紹介します。

私はこの機能をKubeCon NA 2019の[Leveling Up Your CD: Unlocking Progressive Delivery on Kubernetes](https://kccncna19.sched.com/event/Uaaj/leveling-up-your-cd-unlocking-progressive-delivery-on-kubernetes-daniel-thomson-jesse-suen-intuit)の発表で知り、もう少し調べてみたいと思い今回のテーマとしました。

※この記事は、[Z Lab](https://qiita.com/organizations/zlab)の業務の一環として作成したものです。

# Experimentsとは

ExperimentsはいくつかのReplicaSetをデプロイし、それらの生成するPodに対していくつかの分析を実行するための仕組みです。
利用者はExperimentsというCRDで定義されているリソースを作ることでこの分析の実行を指示できます。

# 想定されている利用例

- 2つのバージョンのアプリケーションを一定時間デプロイし、その後[Kayanta](https://github.com/spinnaker/kayenta)のようなツールで2つのバージョンのメトリクスの違いなどを分析します。
- A/B/Cと異なるバージョンを長い間同時に実行し続けます。
- 新しいアプリケーションを別のラベルで立ち上げます。これにより新しいバージョンのアプリケーションにはServiceによるロードバランスがされず、静かな環境でテストを実施することができます。

# 動作の様子

githubにあるサンプルを試してみます。

Experimentsの定義は下記です。インラインで説明を入れています。

```yaml

apiVersion: argoproj.io/v1alpha1
kind: Experiment  # Experimentリソースです。
metadata:
  name: experiment-with-analysis # 名前です。なんでも良いです。
spec:
  templates: # ここはDeploymentのためのTemplateです。 実験したいバージョン分だけ配列を続けます
  - name: purple # 1つ目のDeploymentです
    selector:
      matchLabels:
        app: rollouts-demo
    template: # ここはPodのためのTemplateです
      metadata:
        labels:
          app: rollouts-demo
          v: purple
      spec:
        containers:
        - name: rollouts-demo
          image: argoproj/rollouts-demo:purple # ここでバージョン指定です。ここだけがもう一つと違います。
          imagePullPolicy: Always
  - name: orange # 2つ目のDeploymentです
    selector:
      matchLabels:
        app: rollouts-demo
    template:
      metadata:
        labels:
          app: rollouts-demo
          v: orange
      spec:
        containers:
        - name: rollouts-demo
          image: argoproj/rollouts-demo:orange # ここでバージョン指定です。ここだけがもう一つと違います。
          imagePullPolicy: Always
  analyses: # 試したい分析の数だけ続きます。今回は2つの分析を登録しています。
  - name: pass
    templateName: pass # 分析の方法を参照しています。定義は別途紹介。
  - name: random
    templateName: random-fail # 分析の方法を参照しています。定義は別途紹介。
```

ExperimentsはDeploymentとよく似たリソースのリストと、Analysisという分析タスクのリストを合わせたリソースです。
それぞれ分析対象のワークロードとその分析タスクを表しています。


下記は絶対に成功するというAnalysisです。

```yaml

kind: AnalysisTemplate
apiVersion: argoproj.io/v1alpha1
metadata:
  name: pass
spec:
  metrics:
  - name: pass
    interval: 5s
    failureLimit: 1
    provider:
      job:
        spec:
          template:
            spec:
              containers:
              - name: sleep
                image: alpine:3.8
                command: [sh, -c]
                args: [exit 0]
              restartPolicy: Never
          backoffLimit: 0
```

下記はランダムに失敗するAnalysysです。

```yaml

kind: AnalysisTemplate
apiVersion: argoproj.io/v1alpha1
metadata:
  name: random-fail
spec:
  metrics:
  - name: random-fail
    interval: 5s
    failureLimit: 1
    provider:
      job:
        spec:
          template:
            spec:
              containers:
              - name: sleep
                image: alpine:3.8
                command: [sh, -c]
                args: [FLIP=$(($(($RANDOM%10))%2)) && exit $FLIP]
              restartPolicy: Never
          backoffLimit: 0
```

このように任意のコマンドをAnalysisとして実行することができます。
この例では役に立たない2つのAnalysisを定義していますが、この部分をCurlにしたりhttpのベンチマークスクリプトにすることで有用な分析を行うことができそうです。
ここで紹介した2つのproviderはjobですが、他にもprometheusやKayentaなどを指定することができます。

Prometheusを使う場合はPromQLで条件を記載することができます。また[Kayenta](https://github.com/spinnaker/kayenta)は以前のバージョンとカナリアリリースのバージョンでのメトリクスの比較を行い、異常がないかを判断するための専用の分析ツールであり非常に有用そうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100375/ccf9952d-abbb-b273-6afd-c52dcf99acd2.png)

(↑ リポジトリにはまだprometheusの例がありませんでしたがKubeCon NA 2019の発表資料には上図のような例が挙げられていました。ここではPromQLでAnalysisを記述しつつ、さらにargsというワークロードから指定できる引数を受け取るという例になっています。)


さて、上記のマニフェストをクラスタにデプロイして様子を見てみましょう。

まずはArgo Rollout自体をデプロイします。

```bash

$ kubectl create namespace argo-rollouts
$ kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
```

またExperimentsの状態をビジュアルに確認するためのkubectl pluginを導入します

```bash
$ curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v0.6.0/kubectl-argo-rollouts-darwin-amd64
$ chmod +x ./kubectl-argo-rollouts-darwin-amd64
$ sudo mv ./kubectl-argo-rollouts-darwin-amd64 /usr/local/bin/kubectl-argo-rollouts
```

（参考： https://argoproj.github.io/argo-rollouts/features/kubectl-plugin/ ）


次に上記で紹介したExperiments, AnalysisTempalteをデプロイします。

しばらく経ったのちにkubectlで状況を確認してみます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100375/55fe945d-cfbe-7047-4d2f-0a29332ef0a2.png)


ExperimentsとしてはFailedという状態になって停止しています。
もう少し詳しくみてみると`experiment-with-analysis-random`が2回Failしていることがわかります。
一方`experiment-with-analysis-pass`は2回中2回成功しています。

そして、規定回数以上に失敗したAnalysisがあったためExperiments対象だったDeploymentが終了したことがわかります。

このようにExperimentリソースに記載した通りにワークロードを実行し、かつ指定した分析を行い、その結果が記録されることが確認できました。

# まとめ

Argo Rolloutsの新しい機能であるExperimentsについて動作を確認しました。
Experimentsで行なっていることは、複数バージョンのデプロイと、それに対するテストです。これは単純にDeploymentやJobを一つ一つ手で実行しても同じことが実現できますが、Experimentsを使うことで、「宣言的」にそのテストを行えるというのが良いところなのかなと思いました。

また今回は紹介しませんでしたが、Argo Rolloutsのメインの機能であるBlue/GreenデプロイやCanalyデプロイの前段階にこのExperimentsを実行することもできるため、本番環境での動作テストを行なったのちに問題がなければ新しいバージョンを展開する。などといったロジック付きのデプロイが実現できるというのがExperimentsが役立つ場面だと思います。特にKayentaを使って以前のワークロードと新しいワークロードの総合的な比較を行うことで「以前と比べて何かおかしい」といった人が行う判断に近いやり方でのテストは今後流行るのでは？と感じました。

(Kayentaとの連携は試してみたかったのですが簡単なデプロイ手順が見つからず断念しました。誰か・・試してみた人がいたら教えて欲しいです。)