Cloud Run のリビジョン トラフィック管理を試してみた

# はじめに

こんにちは、京セラコミュニケーションシステム 福留（@kccs_kazuo_fukudome）です。

今回は、Cloud Run や Cloud Functions（第 2 世代）で利用できるリビジョントラフィックの管理について紹介したいと思います。
この機能は、1 年くらい前から知っていましたが、デプロイしたモジュールの切り戻しで利用したのみでした。そのため、トラフィックの割り当てを 0% や 100% 以外の割合で使った場合、どのようになるんだろうと気になってたので、この機能についての紹介もかねて、記事を作成してみました。

:::note info
本記事は 2023 年 7 月ごろに作成しております。
Google Cloud の機能を利用した場合は、利用料が発生します。
:::

## Cloud Run の リビジョントラフィックとは

Cloud Run でデプロイしたモジュールについて、トラフィック管理を行う機能となります。
たとえば、Cloud Run で実行しているモジュールをバージョンアップしリリースしたとします。ですが、リリースしたモジュールに不具合があり、前のバージョンに戻したいといった状況が発生した場合、この機能の出番となります。
この機能を利用しない場合、前のバージョンに戻すには、前のソースコードでデプロイし直す必要があります。しかし、リビジョントラフィックを利用すると、Cloud Run の設定画面から簡単に前のバージョンに戻すことができます。
また、段階的にリリースをするカナリアリリースにも利用できます。
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/c50a7f7a-6e7a-f78f-31d6-5d054cebfbcf.png)
私も、この機能を利用し新しいバージョンで、どこに問題が発生したのか？原因調査のために、トラフィックコントロール機能で切り戻しをよくします。ただ、25% とかの割合にした場合、どういった動きになるのか試してみました。

## 事前準備

説明が長くなりましたが、改めてリビジョントラフィックを検証するため、 python で簡単なプログラムを作成しました。
このプログラムは、HTTP リクエストを受けると、DB（PostgreSQL）の version テーブルに、バージョンを登録するものです。このプログラムを Cloud Run へデプロイします。

<details><summary>Version1のプログラム</summary><div>

```main.py（Version1）
import os
import psycopg2
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/")
def main():
    # データベースに接続
    connection = psycopg2.connect(host='DBサーバーのIP',
                                  user='DBサーバーのユーザー',
                                  password='DBサーバーのパスワード',
                                  database='DBマネージャー名')

    with connection:
      with connection.cursor() as cursor:
        # レコードの登録
        sql = "INSERT INTO version (version) VALUES (%s)"
        cursor.execute(sql, ('1'))

        # コミット
        connection.commit()

    res_str = "insert success v1"
    return res_str

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
```

</div></details>

<details><summary>Version2のプログラム</summary><div>

```main.py（Version2）
import os
import psycopg2
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/")
def main():
    # データベースに接続
    connection = psycopg2.connect(host='DBサーバーのIP',
                                  user='DBサーバーのユーザー',
                                  password='DBサーバーのパスワード',
                                  database='DBマネージャー名')

    with connection:
      with connection.cursor() as cursor:
        # レコードの登録
        sql = "INSERT INTO version (version) VALUES (%s)"
        cursor.execute(sql, ('2'))

        # コミット
        connection.commit()

    res_str = "insert success v2"
    return res_str

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
```

</div></details>

## 検証

Cloud Run にデプロイ後、リビジョントラフィックを設定します。
リビジョントラフィックは、Cloud Run の リビジョンタグ にある、”トラフィックを管理"のリンクから設定できます。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/5f26aa34-a4ac-5d2a-7c9c-5a791c07f730.png)
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/791ded82-729f-6b1a-c739-04adeb306b5d.png)

検証は、次の設定内容で リクエストを 100 回ずつ 3 回に分けて行いました。

1. バージョン 1 25%、バージョン 2 75% の場合
2. バージョン 1 50%、バージョン 2 50% の場合
3. バージョン 1 75%、バージョン 2 25% の場合

## 結果

結果は、SQL の count 関数を利用して求めました。ここでは、その結果をエビデンスとして記載します。

###### バージョン 1 25%、バージョン 2 75% の場合

1 回目
![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/e6891864-f866-a014-9bb0-ba5bf41c16e4.png)
2 回目
![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/0d1a43e6-423a-b630-5610-1133cbfe7061.png)
3 回目
![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/0c4da44f-83a9-9197-25f2-301ffa90c28d.png)

###### バージョン 1 50%、バージョン 2 50% の場合

1 回目
![image7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/94c67edb-3957-9ef4-273e-d314ed0e8f7b.png)
2 回目
![image8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/f3ab7aab-6162-ee6a-c0ef-8a77ff129e17.png)
3 回目
![image9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/6a7a5ded-ca5c-95c7-4a9d-e43a1ab02d21.png)

###### バージョン 1 75%、バージョン 2 25% の場合

1 回目
![image10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/ae9e4676-83f1-abae-a0f0-939957694eed.png)
2 回目
![image11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/feb9a1c7-173b-8130-b13a-b1771e2043d0.png)
3 回目
![image12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852633/1f9f1b13-ffff-b2bc-6962-ca6267aac9f2.png)

## まとめ

試行回数が不足していた為でしょうか？私個人の意見としては、数値に少し偏りがあったので、期待していた結果と少し違うかな？と思いました。皆さんは、どのように思いましたか？もし、意見がありましたらコメントを頂ければと思います。
先に説明した通り、この機能を用いることで、段階的なリリースができたり、トラブル発生時の切り戻しも簡単に行う事ができます。私は、アプリケーション開発業務が中心のため、 普段は 0% か 100% の設定しか使いません。ですが、運用チームなどに配属された場合は、この機能も利用してみたカナリアリリース等もできればいいなと思いました。