API Gateway、Kubernetes Gateway、およびService Meshの包括的な比較
June 9, 2023
APIゲートウェイ、Kubernetesゲートウェイ、およびサービスメッシュについて、依然として多くの混乱が存在します。その理由は以下の通りです:
- これらの技術が、カナリアデプロイメント、レート制限、サービスディスカバリーなどの同じキーワードで言及されることが多いため。
- これらの技術はすべてリバースプロキシを使用しているため。
- 一部のAPIゲートウェイは独自のKubernetesゲートウェイやサービスメッシュを持ち、その逆もまた然りであるため。
- これら3つの技術を比較し、どれが優れているかを結論付ける記事や動画が多く存在するため。
この記事では、これらの技術を説明し、それらが根本的にどのように異なり、異なるユースケースに対応しているかを共有します。
APIゲートウェイ
APIゲートウェイは、クライアントアプリケーションとAPIの間に位置します。すべてのクライアントリクエストを受け取り、必要なAPIに転送し、クライアントに応答を返します。
基本的には、多くの機能を備えたリバースプロキシです。
さらに、APIゲートウェイは認証、セキュリティ、細かいトラフィック制御、監視などの機能も備えており、API開発者はビジネスニーズにのみ集中できます。
多くのAPIゲートウェイソリューションが利用可能です。人気のある無料およびオープンソースのソリューションには以下があります:
- Apache APISIX: Nginx上に構築された高性能で拡張可能なクラウドネイティブAPIゲートウェイ。
- Gloo Edge: Envoyプロキシ上に構築されたAPIゲートウェイ。
- Kong: Nginx上に構築されたプラグ可能なAPIゲートウェイ。
- Tyk: Goで書かれたAPIゲートウェイで、REST、GraphQL、TCP、gRPCプロトコルをサポート。
GCP、AWS、Azureなどのクラウドプラットフォームも独自のAPIゲートウェイを提供しています。
APIゲートウェイ、Kubernetesゲートウェイ、サービスメッシュは、カナリアデプロイメント(新しいソフトウェアバージョンを一般公開する前に、少数のユーザーに段階的に展開する)をサポートしています。
以下の例は、Apache APISIXでカナリアデプロイメントを設定する方法を示しています。
以下の設定でAPISIX Admin APIにリクエストを送信できます:
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri":"/*",
"plugins":{
"traffic-split":{
"rules":[
{
"weighted_upstreams":[
{
"upstream":{
"name":"api-v1",
"type":"roundrobin",
"nodes":{
"api-v1:8080":1
}
},
"weight":95
},
{
"weight":5
}
]
}
]
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"api-v2:8080":1
}
}
}'
APISIXは、トラフィックの95%をapi-v1サービスに、5%をapi-v2サービスにルーティングします。
Kubernetesゲートウェイ
Kubernetesゲートウェイは、KubernetesネイティブのAPIゲートウェイです。つまり、Kubernetes APIを使用してこれらのAPIゲートウェイを管理できます。これは、KubernetesのPod、サービス、デプロイメントと同様です。
Kubernetesでは、APIはクラスター内にデプロイされたPodやサービスです。その後、Kubernetesゲートウェイを使用して外部トラフィックをクラスターに誘導します。
Kubernetesは、これを実現するために2つのAPIを提供しています。Ingress APIとGateway APIです。
Kubernetes Ingress API
Ingress APIは、デフォルトのサービスタイプであるNodePortとLoadBalancerの制限を克服するために作成されました。これにより、ルーティングやSSL終端などの機能が導入され、Kubernetesサービスを外部トラフィックに公開する方法が標準化されました。
Ingress APIには、IngressとIngressコントローラーの2つのコンポーネントがあります。
Ingress Kubernetesネイティブオブジェクトは、外部トラフィックがサービスにアクセスする方法に関するルールのセットを定義します。
以下の設定例は、Kubernetes Ingressオブジェクトを使用してURIパスに基づいてトラフィックをルーティングする方法を示しています:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-routes
spec:
ingressClassName: apisix
rules:
- http:
paths:
- backend:
service:
name: api-v1
port:
number: 8080
path: /v1
pathType: Exact
- backend:
service:
name: api-v2
port:
number: 8080
path: /v2
pathType: Exact
Ingressコントローラーは、これらのルールを実装し、リバースプロキシを使用してクラスターにトラフィックをルーティングします。
20以上のIngressコントローラー実装があります。APISIXには、APISIX APIゲートウェイをラップしてKubernetes Ingressとして機能するIngressコントローラーがあります。
APISIX Ingressコントローラーは、Kubernetes IngressオブジェクトをAPISIX設定に変換します。
APISIXは、この設定を実装します。
Ingress APIは特定の実装に縛られていないため、APISIXを他のIngressコントローラーと交換できます。
このベンダー中立性は、単純な設定には適しています。しかし、カナリアデプロイメントのような複雑なルーティングを行いたい場合、ベンダー固有のアノテーションに依存する必要があります。
以下の例は、Nginx Ingressを使用してカナリアデプロイメントを設定する方法を示しています。ここで使用されているカスタムアノテーションは、Nginx固有のものです:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "5"
name: api-canary
spec:
rules:
- http:
paths:
- backend:
serviceName: api-v2
servicePort: 8080
path: /
上記の設定は、トラフィックの5%をapi-v2サービスにルーティングします。
アノテーションに加えて、APISIXなどのIngressコントローラーは、Ingress APIの制限を克服するためにカスタムKubernetes CRDを持っています。
以下の例は、APISIX CRDであるApisixRouteを使用してカナリアデプロイメントを設定する方法を示しています:
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: api-canary
spec:
http:
- name: route
match:
paths:
- /*
backends:
- serviceName: api-v1
servicePort: 8080
weight: 95
- serviceName: api-v2
servicePort: 8080
weight: 5
これらのカスタムCRDにより、Ingressの設定が容易になり、下層のAPIゲートウェイの全機能を活用できますが、移植性が犠牲になります。
Kubernetes Gateway API
Gateway APIは、Ingress APIを「修正」することを目的とした新しいKubernetesオブジェクトです。
Ingressコントローラーが開発したカスタムCRDからインスピレーションを得て、HTTPヘッダーベースのマッチング、重み付きトラフィック分割、およびIngress APIではカスタムの独自アノテーションが必要なその他の機能を追加しています。
以下の例は、Kubernetes Gateway APIを使用してカナリアデプロイメントを設定する方法を示しています:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: api-canary
spec:
rules:
- backendRefs:
- name: api-v1
port: 8080
weight: 95
- name: api-v2
port: 8080
weight: 5
Gateway APIを実装するIngressコントローラーは、この設定を実装できます。
Gateway APIは、Ingress APIに対して多くの改善を行っていますが、まだアルファ版であり、Gateway APIの実装は頻繁に変更されています。
サービスメッシュ
APIゲートウェイとKubernetesゲートウェイは、アプリケーションの境界を越えて動作し、APIを抽象化しながらエッジの問題を解決します。
サービスメッシュは、異なる課題を解決します。
サービスメッシュは、サービス間の通信(東西トラフィック)に重点を置いており、サービスとクライアント間の通信(南北トラフィック)よりも重要視しています。
通常、これはAPI/サービスと共にサイドカープロキシをデプロイすることで実現されます。
ここでは、サイドカープロキシがサービス間の通信を処理し、開発者がサービスにネットワーキングロジックをコーディングする必要がありません。
多くのサービスメッシュが利用可能です。人気のあるものには以下があります:
- Istio: 最も人気のあるサービスメッシュ。多くのサービスメッシュが使用するEnvoyプロキシ上に構築されています。
- Linkerd: Linkerd専用にRustで書かれた軽量なサービスメッシュで、linkerd2-proxyを使用します。
- Consul Connect: セキュリティと可観測性を重視したサービスメッシュ。組み込みプロキシまたはEnvoyと連携できます。
Ciliumのような新しいサービスメッシュは、eBPFを介してカーネルから直接ネットワーキング機能を使用することで、サイドカーベースのサービスメッシュに代わる選択肢を提供します。
典型的なサービスメッシュでは、8つのサービスに対して8つのプロキシが必要ですが、CiliumのようなeBPFベースのサービスメッシュでは必要ありません。Cilium Service Mesh – Everything You Need to Knowから適応。
サービスメッシュには、南北トラフィックを処理する基本的なイングレス/エグレスゲートウェイもあります。イングレスゲートウェイは、外部トラフィックがサービスメッシュに入るエントリーポイントであり、エグレスゲートウェイは、メッシュ内のサービスが外部サービスにアクセスできるようにします。
Apache APISIXには、Ameshというサービスメッシュ実装もあります。IstioのコントロールプレーンとxDSプロトコルを使用して、サイドカーのデフォルトのEnvoyプロキシを置き換えます。
サービスメッシュでは、カナリアデプロイメントを設定できます。例えば、あるサービスからのリクエストを別のサービスの2つのバージョン間で分割できます。
以下の例は、Istioサービスメッシュを使用してカナリアデプロイメントを設定する方法を示しています:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: api-virtual-service
spec:
hosts:
- api
http:
- route:
- destination:
host: api
subset: v1
weight: 80
- destination:
host: api
subset: v2
weight: 20
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: api-destination-rule
spec:
host: api
subsets:
- name: v1
labels:
version: "1.0"
- name: v2
labels:
version: "2.0"
これらの設定はIstio固有です。別のサービスメッシュに切り替えるには、異なるが同様にベンダー依存の設定を作成する必要があります。
Service Mesh Interface (SMI) 仕様は、この移植性の問題を解決するために作成されました。
SMI 仕様は、サービスメッシュユーザーがサービスメッシュ実装に縛られずにアプリケーションを定義できるKubernetes CRDのセットです。
標準化の試みは、すべてのプロジェクトが参加する場合にのみ機能します。しかし、SMI仕様ではこれが起こらず、いくつかのプロジェクトのみが積極的に参加しました。
最近では、Kubernetes SIG NetworkがサービスメッシュをサポートするためにGateway APIを進化させています。
GAMMA (Gateway API for Mesh Management and Administration) イニシアチブは、Gateway APIプロジェクト内の専用グループで、「サービスメッシュ技術とユースケースに関連するGateway APIリソース、セマンティクス、およびその他のアーティファクトを調査、設計、追跡する」ことを目的としています。
Gateway APIはIngress APIの自然な次のステップですが、サービスメッシュに対してどのように機能するかはまだ待つ必要があります。Istioは、すべてのトラフィック管理のデフォルトAPIとしてGateway APIを使用する意向を発表し、プロジェクトを推進し続けています。
以下の例は、IstioでGateway APIを使用してカナリアデプロイメントを設定する方法を示しています。基本的な考え方は、parentRefsを使用して、ゲートウェイではなく他のサービスにアタッチすることです:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: api-canary
spec:
parentRefs:
- kind: Service
name: api-a
port: 8080
rules:
- backendRefs:
- name: api-b-v1
port: 8080
weight: 95
- name: api-b-v2
port: 8080
weight: 5
GAMMAプロジェクトが、特定のプロジェクトのニーズに偏り、最終的には他のプロジェクトが独自のAPIを使用するようになる可能性があるという懸念があります。これは、Kubernetes Ingress APIの後にカスタムCRDシナリオが発生したのと同様です。
しかし、Gateway APIプロジェクトは、サービスメッシュのトラフィック管理を標準化するための最良の試みです。SMIプロジェクトもGAMMAイニシアチブに参加し、サービスメッシュプロジェクトによるGateway APIの一貫した実装を提唱するのに役立ちます。
FlaggerやArgo Rolloutsなどの他のプロジェクトも、Gateway APIと統合しています。
何を使うべきか?
この質問に対する唯一の正しい答えは、「状況による」です。
APIを開発していて、認証、セキュリティ、ルーティング、またはメトリクスが必要な場合、APIゲートウェイを使用する方が、API内でこれを独自に構築するよりも良いでしょう。
Kubernetes環境で同様のことを行いたい場合、APIゲートウェイをKubernetesで動作させるよりも、Kubernetesゲートウェイを使用するべきです。幸いなことに、多くのAPIゲートウェイはKubernetesネイティブの設定でも動作します。
しかし、APIゲートウェイ + Ingressコントローラーが提供する機能がKubernetes環境では過剰である場合があり、単純なトラフィック管理に戻りたいと思うかもしれません。
一方、サービスメッシュは全く異なる問題を解決します。サービスメッシュは、南北トラフィックを処理するための独自のゲートウェイも提供します(通常は十分ですが)、より多くの機能を持つ独自のゲートウェイを使用することもできます。
Kubernetes Gateway APIを通じてAPIゲートウェイとサービスメッシュが収束することで、アプリケーション開発者が基盤となる実装を心配するのではなく、問題解決に集中しやすくなるはずです。
Apache APISIXのようなプロジェクトは、APIゲートウェイとサービスメッシュの提供を構築するために同じ技術を使用し、これらの仕様とよく統合され、ベンダー中立の選択を促進します。
また、これらのいずれも必要ない可能性もあります。マイクロサービスや分散アーキテクチャさえ必要ない場合もありますが、必要な場合、ゲートウェイとメッシュはあなたの生活を大幅に楽にすることができます。