KnativeでPython Webアプリケーションのオートスケーリングを試してみた

## 概要

以前、[自作したPythonのWebアプリにKubernetesのHorizontal Pod Autoscalerを適用した記事](https://qiita.com/tobita_yoshiki/items/eb9956045ac21f15a921)を書きました。

今回は、自作のWebアプリに対して、  
KNativeを使ってオートスケーリングしてみた内容について共有させていただきます。

## サンプルアプリケーションの準備

サンプルアプリケーションとして、  
以下のような自身に負荷を与えるWebアプリを作成しました。

HTTPリクエストを受信すると、負荷を発生させるために平方根の計算を多数行います。

```python:app.py
from bottle import route, run
import math

@route('/')
def index():
    x = 0.0001
    for i in range(0, 1000000):
        x += math.sqrt(i)
    return "OK: {}".format(x)

if __name__ == '__main__':
    run(host='0.0.0.0', port=80)
```

```Dockerfile:Dockerfile
FROM python:3.12-slim

WORKDIR /app
RUN pip install bottle

COPY app.py /app

ENTRYPOINT python app.py
```

```shell:ビルド方法
docker build . -t yoshikit/knative-autoscale-app:latest
```

WebアプリはDocker Hubで公開しています:  
[https://hub.docker.com/repository/docker/yoshikit/knative-autoscale-app/general](https://hub.docker.com/repository/docker/yoshikit/knative-autoscale-app/general)

## KNativeサービスのデプロイ

続いて、KNativeを使用してサービスをデプロイします。以下は、KNativeのサービス定義ファイル（`knative-service.yaml`）です。

```yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: autoscale-simple-app
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/target: "10" # 1つのPodが同時に処理するリクエストの数の目標値
    spec:
      containers:
      - image: yoshikit/knative-autoscale-app:latest
        ports:
            - containerPort: 80
```

この定義ファイルを使用して、サービスをKNativeにデプロイします。

```
$ kubectl apply -f knative-service.yaml
```

デプロイが成功すると、以下のようにポッドが作成されます。

```
$ kubectl get pods
NAME                                                     READY   STATUS    RESTARTS   AGE
autoscale-simple-app-00001-deployment-67946fffb6-gxc27   2/2     Running   0          6s
```

## デプロイされたサービスのURL取得

デプロイされたサービスのURLを取得するために、以下のコマンドを実行します。

```
$ kubectl get ksvc autoscale-simple-app
NAME                   URL                                                      LATESTCREATED                LATESTREADY                  READY   REASON
autoscale-simple-app   http://autoscale-simple-app.default.127.0.0.1.sslip.io   autoscale-simple-app-00001   autoscale-simple-app-00001   True    
```

この`http://autoscale-simple-app.default.127.0.0.1.sslip.io`がWebアプリケーションのアクセスURLとなります。

## 負荷テスト

次に、`hey`コマンドを使って、デプロイされたサービスに対して負荷テストを行います。負荷テストでは、50の同時接続で30秒間リクエストを送り続けました。

```
$ hey -z 30s -c 50 \
  "http://autoscale-simple-app.default.127.0.0.1.sslip.io" \
  && kubectl get pods
```

### 負荷テスト結果

負荷テストの結果、以下のようなデータが得られました。

```
Summary:
  Total:        31.0204 secs
  Slowest:      19.7201 secs
  Fastest:      0.0406 secs
  Average:      1.8368 secs
  Requests/sec: 25.8539
  
  Total data:   16779 bytes
  Size/request: 21 bytes
```

負荷テスト中に、新しいポッドが自動的にスケールアウトされたことが確認できました。以下のコマンドで、複数のポッドが起動していることがわかります。

```
$ kubectl get pods
NAME                                                     READY   STATUS    RESTARTS   AGE
autoscale-simple-app-00001-deployment-67946fffb6-2b5fw   2/2     Running   0          29s
autoscale-simple-app-00001-deployment-67946fffb6-cqp2g   2/2     Running   0          27s
autoscale-simple-app-00001-deployment-67946fffb6-ctkrs   2/2     Running   0          27s
autoscale-simple-app-00001-deployment-67946fffb6-gxc27   2/2     Running   0          69s
autoscale-simple-app-00001-deployment-67946fffb6-mtgqf   2/2     Running   0          27s
autoscale-simple-app-00001-deployment-67946fffb6-nd2b6   2/2     Running   0          20s
autoscale-simple-app-00001-deployment-67946fffb6-nmmbg   2/2     Running   0          25s
autoscale-simple-app-00001-deployment-67946fffb6-svkh9   2/2     Running   0          25s
autoscale-simple-app-00001-deployment-67946fffb6-thr6q   2/2     Running   0          29s
```

## おわりに

今回、Knativeを使用してPython Webアプリケーションのオートスケーリングを試みました。負荷テストによって、自動スケーリングの動作を確認できました。Knativeを使うことで、必要に応じてリソースを自動的に増減させることができ、効率的なリソース管理が可能となります。