0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

API Gateway → Lambda の考え方で理解する Kubernetes / Knative のAPI設計

0
Posted at

API Gateway → Lambda の考え方で理解する Kubernetes / Knative のAPI設計

はじめに

AWSでサーバレスAPIを作る場合、よくある構成は次のような形です。

この構成では、API Gateway が外部からのリクエストを受け付け、Lambda が実際の処理を行います。

では、これを Kubernetes / Knative で考えるとどうなるのでしょうか。

この記事では、API Gateway → Lambda の構成を、Kubernetes / Knative の構成に置き換えながら整理します。


まず全体像

AWS の API Gateway → Lambda 構成を、Kubernetes / Knative に置き換えると、ざっくり以下のようになります。

対応関係をかなりざっくり書くと、以下です。

AWS Kubernetes Knative
API Gateway Gateway API / Ingress Ingress Gateway / Knative Route
Resource / Path HTTPRoute / Ingress path Knative Route
Lambda Pod 上のコンテナ Knative Service / Revision / Pod
Lambda Version コンテナイメージタグ Revision
Lambda Alias Service selector など traffic split
自動スケール HPA / KEDA Knative Autoscaler
scale to zero 標準Deploymentだけでは難しい 可能

ただし、完全に1対1で対応するわけではありません。

Lambda は AWS が実行基盤を管理してくれるサービスです。
一方、Kubernetes / Knative では、クラスタ、ネットワーク、スケーリング、監視なども含めて自分たちで設計する必要があります。


AWS構成で何が行われているか

API Gateway → Lambda のリクエストフローは以下のように考えられます。

API Gateway は、単なる中継ではなく、以下のような役割を持ちます。

API Gateway の役割 内容
入口 外部からのHTTPリクエストを受ける
ルーティング path / method / header などで振り分ける
認証・認可 IAM / Authorizer / Cognito など
リクエスト変換 Lambda に渡す形式へ変換
レスポンス変換 Lambda の戻り値を HTTP レスポンスにする

Kubernetes / Knative で設計する場合も、この役割をどこに持たせるかを考えることになります。


AWSの箱をKubernetesに置き換える

AWS構成をKubernetesに置き換えると、次のようになります。

Kubernetesでは、API Gatewayの役割を1つのコンポーネントがすべて担うというより、複数のコンポーネントに分けます。

AWS側 Kubernetes側 説明
API Gateway Gateway / Ingress 外部からのHTTP入口
Resource / Method HTTPRoute / Ingress Rule パスやホスト名によるルーティング
Lambda Pod 実際のアプリケーション処理
Lambda Function Deployment Podを管理する単位
Lambdaの公開先 Service Podへの安定した入口

Kubernetes構成のリクエストフロー

KubernetesでAPIを公開する場合、基本的な流れは以下です。

図にすると、以下のような構成です。

各コンポーネントの役割

コンポーネント 役割
Gateway / Ingress 外部からのHTTPリクエストを受ける
HTTPRoute / Ingress Rule Host / Path に応じて Service へ振り分ける
Service Podへの安定した入口を提供する
Pod アプリケーションを実行する

Gateway API の HTTPRoute は、Host / Path / Header などを条件にして、Kubernetes Service などのバックエンドへHTTPトラフィックを転送できます。
参考: Gateway API HTTPRoute


Gateway API の例

例えば、以下のようなAPIを考えます。

GET /users  -> user-service
GET /orders -> order-service

構成図は以下です。

HTTPRouteの例です。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
spec:
  parentRefs:
    - name: api-gateway
  hostnames:
    - api.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /users
      backendRefs:
        - name: user-service
          port: 80

    - matches:
        - path:
            type: PathPrefix
            value: /orders
      backendRefs:
        - name: order-service
          port: 80

この場合、API GatewayのResourceに近いものは、HTTPRouteの path です。


Lambdaに相当するものは何か

KubernetesでLambdaに近いのは、Pod上で動くアプリケーションコンテナです。

ただし、LambdaとPodは完全に同じものではありません。

対応関係は以下のように考えると分かりやすいです。

AWS Lambda Kubernetes
Lambda Function Deployment / コンテナアプリケーション
Lambda Runtime コンテナイメージ
Lambda 実行環境 Pod
Lambda の同時実行 Pod数 / HPA
Lambda のログ Pod logs

Deployment と Service の例

Podを直接管理するのではなく、通常はDeploymentで管理します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: user-api
  template:
    metadata:
      labels:
        app: user-api
    spec:
      containers:
        - name: user-api
          image: ghcr.io/example/user-api:1.0.0
          ports:
            - containerPort: 8080

ServiceでPodへの安定した入口を作ります。

apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-api
  ports:
    - port: 80
      targetPort: 8080

構成図は以下です。


KubernetesだけではLambdaと同じではない

KubernetesのDeploymentは、基本的に指定した数のPodを起動し続けます。

replicas: 2

これは、常に2つのPodを起動しておくという意味です。

Lambdaのように、

リクエストがないときはゼロ
リクエストが来たら起動
負荷に応じて自動スケール

という動きを、通常のDeploymentだけで実現するのは難しいです。

このようなサーバレスに近い動きをKubernetes上で実現するための選択肢が Knative です。


AWSの箱をKnativeに置き換える

AWS構成をKnativeに置き換えると、次のようになります。

Knativeでは、アプリケーションはKnative Serviceとして定義します。

Knative Serviceを作ると、内部的にRoute、Configuration、Revisionなどが管理されます。
Knative Servingの主要リソースは Service / Route / Configuration / Revision です。
参考: Knative Serving


Knative Serving の構成図

Knative Servingでは、以下のようにリソースが関係します。

Knativeリソース 役割
Service アプリケーションのトップレベルリソース
Route リクエストをRevisionへルーティング
Configuration Revisionを作るための設定
Revision ある時点のコードと設定のスナップショット
Pod 実際のコンテナ実行単位

Revisionは、Knative Serviceの変更ごとに作られるコードと設定のスナップショットです。
参考: Knative Revisions


Knativeのリクエストフロー

KnativeでHTTPリクエストを受ける流れは以下です。

通常のKubernetes構成と比べると、Knative Route / Revision / Autoscaler が入ることで、サーバレスに近い動きができます。


Knative Service の例

Knative Serviceの例です。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: user-api
spec:
  template:
    spec:
      containers:
        - image: ghcr.io/example/user-api:1.0.0
          ports:
            - containerPort: 8080

この定義により、KnativeがRoute / Configuration / Revisionを管理します。


scale to zero のイメージ

Knativeの大きな特徴は、リクエストがないときにPodを0まで落とせることです。

Knativeでは、scale to zero が有効な場合、リクエストがないアプリケーションを0レプリカまでスケールダウンできます。
参考: Knative scale to zero

設定例です。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: user-api
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "0"
        autoscaling.knative.dev/max-scale: "10"
    spec:
      containers:
        - image: ghcr.io/example/user-api:1.0.0

ただし、商用APIで初回遅延を避けたい場合は、min-scale: "1" 以上にして常時起動させる設計もあります。


Revision と Traffic Split

Knativeでは、Revision単位でトラフィックを分割できます。

これは Lambda Alias の重み付きルーティングに近い考え方です。

例です。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: user-api
spec:
  traffic:
    - revisionName: user-api-v1
      percent: 90
    - revisionName: user-api-v2
      percent: 10
  template:
    spec:
      containers:
        - image: ghcr.io/example/user-api:2.0.0

Lambda Proxy Integrationとの違い

API Gateway + Lambda Proxy Integrationでは、Lambdaが以下のような形式でレスポンスを返します。

{
  "statusCode": 200,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": "{\"message\":\"hello\"}"
}

一方、Kubernetes / Knativeでは、アプリケーションは普通のHTTPサーバとして動きます。

例えばFastAPIなら以下のように書けます。

from fastapi import FastAPI

app = FastAPI()

@app.get("/hello")
def hello():
    return {"message": "hello"}

つまり、Kubernetes / Knativeでは以下のようになります。

Lambdaのイベント形式に合わせるというより、通常のHTTPリクエストを受け取り、通常のHTTPレスポンスを返す設計になります。


3つの設計パターン

パターン1: Kubernetes + Gateway API

常時起動のWeb APIなら、この構成が分かりやすいです。

向いているケース:

  • 常時アクセスがある
  • 初回遅延を避けたい
  • 商用API
  • Web API / BFF / 管理API
  • scale to zero が不要

パターン2: Knative Serving

リクエスト駆動でPodを起動したい場合は、Knative Servingが候補になります。

向いているケース:

  • リクエストが少ない
  • 開発環境や検証環境のコストを下げたい
  • 社内ツール
  • PoC
  • scale to zero を使いたい

注意点:

  • 初回リクエストで cold start が発生する可能性がある
  • 商用APIでは min-scale の設計が重要
  • Kubernetesクラスタ自体の運用は必要

パターン3: Knative Eventing

LambdaはAPI Gatewayだけでなく、EventBridgeやSQSなどのイベントでも起動できます。

Kubernetes / Knativeでイベント駆動を作るなら、Knative Eventingが候補になります。

向いているケース:

  • イベント駆動で処理したい
  • Producer と Consumer を疎結合にしたい
  • HTTPリクエスト以外のトリガーも扱いたい

最後に比較表

観点 API Gateway + Lambda Kubernetes Knative
API入口 API Gateway Gateway / Ingress Ingress Gateway / Route
実行単位 Lambda Function Pod / Container Knative Service / Revision / Pod
ルーティング Resource / Method HTTPRoute / Ingress Knative Route
バージョン Lambda Version イメージタグ Revision
トラフィック分割 Lambda Alias Service Mesh等で実現 traffic split
scale to zero 標準で可能 標準Deploymentだけでは難しい 可能
運用責任 AWS側が大きい 利用者側が大きい 利用者側が大きい

まとめ

API Gateway → Lambda の考え方を Kubernetes / Knative に当てはめると、以下のように整理できます。

Kubernetesでは、API Gatewayのような単一サービスにすべてを任せるのではなく、責務を分けて設計します。

責務 Kubernetes / Knative
APIの入口 Gateway API / Ingress
ルーティング HTTPRoute / Ingress / Knative Route
実処理 Pod / Container
自動スケール HPA / KEDA / Knative Autoscaler
scale to zero Knative Serving
イベント駆動 Knative Eventing

常時起動の安定したAPIなら Kubernetes + Gateway API。
リクエスト駆動でゼロスケールしたいなら Knative Serving。
イベント駆動で疎結合にしたいなら Knative Eventing。

Lambdaの考え方をそのまま持ち込むのではなく、Kubernetesでは責務を分けて設計することが重要です。


参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?