Brokerへのレビューコメントの送信¶
当社の書店メインダッシュボードには、読者が他のユーザーのコメントを表示し、テキスト入力エリアから自分のコメントを送信できるコメントセクションがあります。ボタンをクリックするとコメントが投稿されるというシンプルなプロセスに見えますが、その基礎となるメカニズムは堅牢なイベント駆動アーキテクチャによって実現されています。
どのようなKnative機能について学習しますか?¶
- Knative Eventing Broker
- Knative Eventing Sink
- Knative SinkBinding
成果物はどのようなものですか?¶
簡単に言うと、ユーザーがフロントエンドの送信ボタンをクリックすると、コメントがイベント表示サービスに表示されます。
実装¶
ステップ0:基本を理解する¶
マイクロサービスとREST APIの世界では、リクエストをサービス間の通信の主要な方法として参照することがよくあります。しかし、イベント駆動アーキテクチャでは、最小単位はイベントです。Knative EventingはCloudEvents仕様に準拠しているため、先に進む前にこの概念を理解することが不可欠です。先に進む前に、CloudEventsの詳細をこちらで学習してください!
ステップ1:Book Review Serviceの理解¶
Book Review Serviceは、イベント駆動アーキテクチャで重要な役割を果たすNode.js APIサーバーです。イベントを受信して適切に処理する方法を理解することが不可欠です。
主要概念:BrokerとSinkBinding
コードに進む前に、2つの重要な概念を明確にしておきましょう。
- Broker:イベント駆動アーキテクチャの中心的な役割を果たし、イベントを正しい宛先にルーティングします。
- SinkBinding:このKnative Eventingコンポーネントは、Brokerのアドレスを環境変数
K_SINK
に自動的に挿入するため、Node.jsサーバーは手動で更新することなく常に正しいアドレスを取得できます。
順を追ってより深く理解できるようになります。
node-server/index.js
ファイルの/add
関数を見てみましょう。ユーザーがフロントエンドからコメントを送信すると、最初にこのエンドポイントで受信されます。
app.post('/add', async (req, res) => {
try {
const receivedEvent = HTTP.toEvent({headers: req.headers, body: req.body});
const brokerURI = process.env.K_SINK;
if (receivedEvent.type === 'new-review-comment') {
const response = await fetch(brokerURI, {
method: 'POST',
headers: {
'Content-Type': 'application/cloudevents+json',
'ce-specversion': receivedEvent.specversion,
'ce-type': receivedEvent.type,
'ce-source': receivedEvent.source,
'ce-id': receivedEvent.id,
},
body: JSON.stringify(receivedEvent.data),
});
}
} catch (err) {
console.error(err);
}
});
イベントの受信:/add
エンドポイントは、フロントエンドからイベントを受信します。CloudEventsのSDKを使用して、受信リクエストをCloudEventオブジェクトに変換します。
const receivedEvent = HTTP.toEvent({headers: req.headers, body: req.body});
Brokerアドレスの決定:Brokerのアドレスはクラスタ内で動的に割り当てられます。Node.jsサーバーは、このアドレスを環境変数K_SINK
から取得します。
const brokerURI = process.env.K_SINK;
環境変数にアドレスを伝えたのは誰か疑問に思うかもしれませんね?それはKnative SinkBindingです。
イベントフィルタリング:サービスはイベントの種類をチェックします。new-review-comment
であれば、Brokerにイベントを転送します。
if (receivedEvent.type === 'new-review-comment') {
// logic that forwards the event, see below
}
イベント転送ロジック:適切なCloudEventヘッダーを使用して、イベントがBrokerに転送されます。
const response = await fetch(brokerURI, {
method: 'POST',
headers: {
'Content-Type': 'application/cloudevents+json',
'ce-specversion': receivedEvent.specversion,
'ce-type': receivedEvent.type,
'ce-source': receivedEvent.source,
'ce-id': receivedEvent.id,
},
body: JSON.stringify(receivedEvent.data),
});
その他の関数の調査
Node.jsサーバーには、同様のパターンに従う他の関数があり、詳細なコメントで機能が説明されています。
/insert
:CloudEventsを受信し、ペイロードをPostgreSQLデータベースに挿入します。/comment
:データベースからコメントを転送するために、フロントエンドとWebSocket接続を作成します。
ステップ2:Brokerの作成¶
Brokerはイベント駆動アプリケーションにおけるルーターとして機能し、イベントを受信して正しい宛先にルーティングします。
- 1:
node-server/config/200-broker.yaml
という名前の新しいYAMLファイルを作成し、次の内容を追加します。
node-server/config/200-broker.yaml
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
name: bookstore-broker
- 2:YAMLファイルを適用します。
kubectl apply -f node-server/config/200-broker.yaml
次の出力が表示されます。
broker.eventing.knative.dev/bookstore-broker created
または、Brokerを作成するには、Knative CLI kn
を使用します。
kn broker create bookstore-broker
次の出力が表示されます。
Broker 'bookstore-broker' successfully created in namespace 'default'.
検証
Brokerを一覧表示するには、次のコマンドを実行します。
kubectl get brokers
ステータスがTrue
のbookstore-broker
というBrokerが表示されます。
NAME URL AGE READY REASON
bookstore-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/bookstore-broker 7m30s True
トラブルシューティング
問題が発生した場合は、次のコマンドを使用して診断します。
kubectl describe broker bookstore-broker
ステップ3:Node.jsサーバーとBroker間のSinkBindingの作成¶
アプリケーションでKubernetesサービスに接続するためのURLをハードコーディングすると、制限的で柔軟性に欠けます。SinkBindingは、KubernetesサービスのURLをアプリケーションに動的に挿入します。
SinkBindingの詳細については、こちらと仕様スキーマを参照してください!
SinkBindingの作成
- 1:
node-server/config/300-sinkbinding.yaml
という名前の新しいYAMLファイルを作成し、次の内容を追加します。
node-server/config/300-sinkbinding.yaml
apiVersion: sources.knative.dev/v1
kind: SinkBinding
metadata:
name: node-sinkbinding
spec:
subject:
apiVersion: apps/v1
kind: Deployment
selector:
matchLabels:
app: node-server
sink: # In this case, the sink is our Broker, which is the eventing service that will receive the events
ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: bookstore-broker
- 2:YAMLファイルを適用します。
kubectl apply -f node-server/config/300-sinkbinding.yaml
次の出力が表示されます。
sinkbinding.sources.knative.dev/node-sinkbinding created
検証
以下のコマンドを実行して、sinkbinding を一覧表示します。
kubectl get sinkbindings
node-sinkbinding
という sinkbinding が、READY
ステータスがTrue
で表示されるはずです。
NAME SINK AGE READY REASON
node-sinkbinding http://broker-ingress.knative-eventing.svc.cluster.local/default/bookstore-broker 2m43s True
ステップ 4: イベント表示サービスの作成¶
イベント表示は、Knative Eventing のデバッグツールであり、イベントの一時的な送信先(別名シンク)として使用できます。
イベント表示サービスの作成
- 1:
node-server/config/100-event-display.yaml
という名前の新しいYAMLファイルを作成し、以下の内容を追加します。
node-server/config/100-event-display.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: event-display
spec:
replicas: 1
selector:
matchLabels:
app: event-display
template:
metadata:
labels:
app: event-display
spec:
containers:
- name: event-display
image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: event-display
spec:
selector:
app: event-display
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
- 2:YAMLファイルを適用します。
kubectl apply -f node-server/config/100-event-display.yaml
次の出力が表示されます。
deployment.apps/event-display created
service/event-display created
検証
以下のコマンドを実行して、pod を一覧表示します。
kubectl get pods
event-display-XXXXXXX-XXXXX
というpodが"実行中"ステータスで表示されるはずです。
NAME READY STATUS RESTARTS AGE
bookstore-frontend-7b879ffb78-9bln6 1/1 Running 0 91m
event-display-55967c745d-bxrgh 1/1 Running 0 4m44s
node-server-644795d698-r9zlr 1/1 Running 0 4m43s
ステップ 5: ブローカーとイベント表示を接続するトリガーの作成¶
トリガーは、CloudEvent の属性に基づいて、イベントを正しい送信先に転送できます。これは、ブローカーとイベント送信先の接続役です。
トリガー内のフィルタは、**フィルタ条件に基づいてイベントをフィルタリングします。** フィルタ条件は、トリガーのYAMLファイルで指定します。**フィルタを指定しない場合、トリガーはブローカーが受信したすべてのイベントを転送します。**
KnativeにはChannelという概念もあり、一般的に、フィルタなしのブローカーとトリガーは、ChannelとSubscriptionと同じように扱うことができます。
ブローカーとトリガーの詳細については、こちらをご覧ください!
トリガーの作成
ここでは、すべてのイベントをイベント表示に送信するトリガーを作成します。
- 1:
node-server/config/200-log-trigger.yaml
という名前の新しいYAMLファイルを作成し、以下の内容を追加します。
node-server/config/200-log-trigger.yaml
# This Trigger subscribes to the Broker and will forward all the events that it received to event-display.
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
name: log-trigger
spec:
broker: bookstore-broker
subscriber:
ref:
apiVersion: v1
kind: Service
name: event-display
- 2:YAMLファイルを適用します。
kubectl apply -f node-server/config/200-log-trigger.yaml
次の出力が表示されます。
trigger.eventing.knative.dev/log-trigger created
検証
以下のコマンドを実行して、トリガーの一覧表示します。
kubectl get triggers
log-trigger
というトリガーのREADY
ステータスがTrue
になっているはずです。
NAME BROKER SUBSCRIBER_URI AGE READY REASON
log-trigger bookstore-broker http://event-display.default.svc.cluster.local 6m2s True
検証¶
以下のコマンドで、イベント表示のログを開きます。
kubectl logs -l=app=event-display -f
検証
UIのコメントボックスに何かを入力して送信ボタンをクリックします。コメントは、以下の出力と共にイベント表示サービスに表示されるはずです。
☁️ cloudevents.Event
Validation: valid
Context Attributes,
specversion: 1.0
type: new-review-comment
source: bookstore-eda
id: unique-comment-id
datacontenttype: application/json
Extensions,
knativearrivaltime: 2024-05-19T05:27:36.232562628Z
Data,
{
"reviewText": "test"
}
次のステップ¶
先に進む前に、検証テストに合格していることを確認してください。