Knative Event経由でKnative Serviceを呼び出す

# 概要

以前、Knative上で[トラフィック管理する記事](https://qiita.com/tobita_yoshiki/items/a90ce1d698811a6875fd)と[オートスケーリングする記事](https://qiita.com/tobita_yoshiki/items/cd3e0250587036b063e5)を執筆しました。

今回は、Knative Eventingについて取り上げます。
Knative Eventingは、Knative上でイベント駆動型のシステムを実現するメカニズムです。

この記事では、Knative Eventingを利用して、Knative Serviceを呼び出す方法について説明します。具体的には、Flaskを使ったシンプルなWebアプリケーションをコンテナ化し、Knative Serviceとしてデプロイします。その後、PingSourceを利用して定期的にこのサービスを呼び出す仕組みを構築します。

## 1\. Flaskを使った簡単なWebアプリケーションの作成

まず、Flaskを使ったシンプルなWebアプリケーションを作成します。このアプリケーションは、HTTPリクエストのペイロードをログに記録し、同じ内容をレスポンスとして返します。

以下のPythonコードは、そのアプリケーションの内容です。

```python
from flask import Flask, request
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    logger.info(request.get_json())
    return f"echo: {request.get_json()}"

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

このコードでは、`/`エンドポイントに対してGETまたはPOSTリクエストを受け付け、リクエストボディをログに記録し、その内容を"echo"という形式で返します。

## 2\. Dockerコンテナの作成

次に、このアプリケーションをコンテナ化します。以下の`Dockerfile`を使用して、Flaskアプリケーションをコンテナイメージとしてビルドします。

```Dockerfile
FROM python:3.12-slim

WORKDIR /app
RUN pip install flask

COPY web-echo.py /app

ENTRYPOINT python web-echo.py
```

この`Dockerfile`は、Python 3.12の軽量イメージをベースに、Flaskをインストールし、`web-echo.py`をアプリケーションとして実行するものです。

コンテナイメージのビルドは以下のコマンドで行います。

```
docker build . -t yoshikit/web-echo:latest
```

こちらのイメージはDocker Hubで利用可能です:  
[https://hub.docker.com/r/yoshikit/web-echo](https://hub.docker.com/r/yoshikit/web-echo)

## 3\. Knative Serviceのデプロイ

次に、このコンテナイメージをKnative Serviceとしてデプロイします。以下の`KnativeService.yaml`ファイルを使用します。

```yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: web-echo
spec:
  template:
    spec:
      containers:
      - image: yoshikit/web-echo:latest
        imagePullPolicy: Always
        ports:
            - containerPort: 80
```

このYAMLファイルは、`yoshikit/web-echo:latest`イメージを使用してKnative Serviceをデプロイする設定です。`containerPort`は80に設定されており、HTTPリクエストを受け付けます。

このファイルを適用するには、以下のコマンドを使用します。

```
kubectl apply -f KnativeService.yaml
```

これで、Knative Serviceがクラスタにデプロイされます。

## 4\. PingSourceを使ったイベントの送信

最後に、Knative Eventingの機能を利用して、定期的にこのサービスを呼び出すためにPingSourceを設定します。以下の`PingSource.yaml`ファイルを使用します。

```yaml
apiVersion: sources.knative.dev/v1
kind: PingSource
metadata:
  name: ping-source
spec:
  schedule: "*/1 * * * *"
  data: '{"message": "Hello world!"}'
  contentType: application/json
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: web-echo
```

このPingSourceは、毎分`{"message": "Hello world!"}`というJSONデータを`web-echo`という名前のKnative Serviceに送信します。

この設定を適用するには、以下のコマンドを使用します。

```
kubectl apply -f PingSource.yaml
```

## 5\. 動作確認

全ての設定が完了したら、Knative Serviceが正常にイベントを受信し、レスポンスを返すことを確認します。Kubernetesのログを確認して、`web-echo`サービスのログに"Hello world!"というメッセージが記録されていることを確認します。

```
kubectl logs -l serving.knative.dev/service=web-echo
```

上記コマンドでログを確認し、定期的に"echo: {'message': 'Hello world!'}"というメッセージが出力されていれば成功です。

実際に出力されたログ:

```
Defaulted container "user-container" out of: user-container, queue-proxy
INFO:__main__:{'message': 'Hello world!'}
INFO:werkzeug:127.0.0.1 - - [03/Sep/2024 12:25:00] "POST / HTTP/1.1" 200 -
INFO:__main__:{'message': 'Hello world!'}
INFO:werkzeug:127.0.0.1 - - [03/Sep/2024 12:26:00] "POST / HTTP/1.1" 200 -
INFO:__main__:{'message': 'Hello world!'}
INFO:werkzeug:127.0.0.1 - - [03/Sep/2024 12:27:00] "POST / HTTP/1.1" 200 -
INFO:__main__:{'message': 'Hello world!'}
INFO:werkzeug:127.0.0.1 - - [03/Sep/2024 12:28:00] "POST / HTTP/1.1" 200 -
INFO:__main__:{'message': 'Hello world!'}
INFO:werkzeug:127.0.0.1 - - [03/Sep/2024 12:29:00] "POST / HTTP/1.1" 200 -
```

## まとめ

この記事では、Knative Eventingを利用して、PingSourceからKnative Serviceを呼び出す方法を説明しました！