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では責務を分けて設計することが重要です。