この記事の目的
以下の記事で Kong Gateway の公式ドキュメントを読んで動作確認を行いました.
最近人気が伸びつつある API ゲートウェイである Apache APISIX についても同様に公式ドキュメントに沿って動作確認を行ったので,こちらの記事に残します.
こちらの記事を参考にして Apaxhe APISIX の API Gateway, Dashboard, Ingress Controller 環境を構築することができます.
デモ構成
そもそも API ゲートウェイとは何ぞや
技術の進歩が速い中で正確に「これが定義である」というのは難しいですが,CNCF Landscape の API ゲートウェイの章1では
- アプリケーション間のリクエストや通信を一元管理するもの
- ユーザーがやろうとしていることができるかを示すインターフェース
- ユーザーがやったことを評価・記録するもの
のように説明されています.
以上だけだと "高級なプロキシ" のような感じもしてしまいますが,Gartner が出している Magic Quadrant for API Management (11 Oct. 2023) 2 を確認してみると "API マネジメント" の分野で必須・標準とされる機能には以下があります.
- 開発者ポータル (管理 GUI)
- ランタイム管理,監視などの運用・制御機能
- ポリシー管理などのセキュリティ機能
- API 設計・開発の補助機能
これらを持ち合わせており,かつ
- 追加機能がどれくらいあるか (どこまで無償で使えるか)
- 運用が楽な設計になっているか
- パフォーマンス性が良いか
- 強力な開発体制が整えられて更新が続けられているか
- 拡張性が良く,機能拡張方法が組織で運用可能なレベルとマッチしているか
- ローカライズされているか (日本語でのサポートなど)
などが差別化要素となっているものが API ゲートウェイ製品として現れてきているように思います.
今日では様々な API ゲートウェイ製品が見つかるので,少しずつ試して調査しながら良さげなものを見つけていくのが良いと考えています.
Kong Gateway や Apache APISIX はその中の一つという位置付けです.
Apache APISIX のサービス紹介
Apache APISIX provides rich traffic management features like Load Balancing, Dynamic Upstream, Canary Release, Circuit Breaking, Authentication, Observability, etc.3
Apache APISIX は様々な機能を複数のサービスに分けて提供していますので,順にご紹介します.
Service | Summary |
---|---|
API Gateway | A dynamic, real-time, high-performance API gateway. |
Dashboard | Designed to make it as easy as possible for users to operate Apache APISIX through a frontend interface. |
Ingress Controller | APISIX Ingress Controller for Kubernetes. |
API Gateway
APISIX API Gateway provides rich traffic management features such as load balancing, dynamic upstream, canary release, circuit breaking, authentication, observability, and more.
Apache APISIX API Gateway はクラウドネイティブを強く意識した OSS の API ゲートウェイ製品を提供します.
マルチプロトコルやセキュリティ機能など豊富な機能が提供されており,全て無償で利用することができます.
これらの機能はプラグインとして提供されており,以下の Plugin Hub から利用方法を参照することができます.
公式のアーキテクチャ紹介によると,APISIX は Nginx 及び OpenResty の lua-nginx-module の上に構築されています.
これは Kong Gateway と同じであり,Nginx/Lua の中身の C と Go によるパフォーマンスの比較を行うよりも,Just-In-Time (JIT) を信用して Lua で発展したルーティング機能の柔軟性を活用するように舵を切った結果とのことです.
特に高パフォーマンスが求められる Core 部分では C での書き直しも行っているようです.
一方で利用しているデータベースには明確に差があり,Kong Gateway は PostgreSQL を利用していたのに対して APISIX では etcd を利用しています.
これは他のデータベースと比較して etcd がスケールを行いやすく,単一障害点の排除や同時実行制御に強みを持たせるためであると説明されています.4
また,Kong Gateway と同様に Admin API を提供しており,管理者による設定とゲートウェイのアクセスに利用するポートが分けられています.
Dashboard
APISIX における管理 GUI (開発者ポータル) を担うサービスです.
各種ルーティングの設定やプラグインの有効化などは,Admin API を利用するか,Dashboard を利用して行うことになります.
現在では APISIX が提供する全ての機能が Dashboard から管理できるようにはなっておらず,順に追加している途中であるとのことです.
なお,利用を開始するには API Gateway とは別にデプロイしてあげる必要があります.
言語は英語とトルコ語,中国語をサポートしています.
特に GUI が気になる場合は Online Playground から気軽に雰囲気を確かめることができます(ユーザー名とパスワードは admin
/admin
です).
触ってみた感想としては,
- 使いやすさは Kong Gateway (Free) と同程度
- ボタンの位置など探すのにすごく苦労するわけではないが,多少は慣れが必要
- 設定値を json として出力・確認するのが容易
- 良くも悪くも Kong Gateway の GUI よりもタイムアウトまでの時間が短く,再ログインを求められる頻度が高い.
- Grafana ダッシュボードとの連携を行うことができるのは良さそう
といったところでした.
Ingress Controller
Ingress Controller は APISIX スタックの中でコントロールプレーンにあり,Kubernetes カスタムリソース定義 (CRD) に基づいた独自の実装を可能にします.
これによってルーティング設定などを実装することができます.
CRD については以下で詳細な説明がされています.
本記事ではあまり触れませんが,Kubernetes The Hard Way をもじった APISIX Ingress Controller the Hard Way があるので別の機会に読み進めて試してみたいと思います.
動作確認環境
動作確認を行った環境情報を以下に示します.
Name | Version |
---|---|
Windows 11 | 22H2 |
Ubuntu (WSL2) | 20.04.6 LTS |
Docker | 20.10.17 |
Docker Compose | v2.10.2 |
Kubernetes | v1.27.3 |
kubectl client | v1.25.0 |
kubectl kustomize | v4.5.7 |
KinD | v0.20.0 |
helm | v3.13.3 |
Go | v1.21.3 |
APISIX API Gateway | 3.8.0-debian |
APISIX Dashboard | 3.0.0-alpine |
APISIX Ingress Controller | 1.7.1 |
bitnami/etcd | 3.5.7-debian-11-r14 |
Prometheus | v2.48.1 |
Kong Gateway との比較
個人的に Kong Gateway と Apache APISIX と比較した結果を先に記述しておきます.
Kong Gateway の方が優れていると思われる点
- 先発として知名度や人気が高い.
- デジタル庁からも推奨 API ゲートウェイとされている.5
- Apache APISIX のように Kubernetes の習熟までは必要なく,Docker のみ使えれば構築に支障はない.
- カスタムプラグイン作成も比較的容易.
- 有償プランによるオフィシャルなサポート(Konnect) もあるので,いざとなったら課金で様々な問題を解決できる可能性がある.
Apache APISIX の方が優れていると思われる点
- クラウドネイティブ性が非常に高く,(その気になれば) 保守性の高いサービスを構築できる.
- 独自の Ingress Controler などの Kubernetes 環境に即した構築手法も提供している.
- Kong Gateway のよりもパフォーマンス・性能が良い (らしい).6
- etcd を利用することでアーキテクチャの肥大化を防ぎ,同時実行制御に関して処理性能が特に高い.
- Java など Kong Gateway にはなかった他言語でのプラグイン開発がサポートされている.
- すさまじい速度で Contributor を増やしている.
- 一般提供のプラグインの種類も豊富 (Keycloak 認可プラグインや Elasticsearch ロガープラグインなどもサポート)
- 完全無償 (Apache)
API Gateway の起動
APISIX を起動する方法として,公式から
が提供されています.
ただし Docker イメージは Apache Software Foundation (ASF) として公式にリリースしているわけではなく,各人が Dockerfile
からビルドして利用することが推奨されています.
APISIX が売りとしている "Fully-Dynamic" (設定や動作の変更時に再起動が不要である) を保証する上でも Kubernetes がマッチしているように感じます.
上記より Kubernetes 環境があれば Helm Charts を使うのが良いと思います.
今回はローカルで KinD のシングルノード構成で一連の環境を立ち上げていきます.
(Minikube では etcd の起動に失敗することまで確認しましたが,原因調査はしていません)
# helm レポジトリ追加,更新,デプロイ
helm repo add apisix https://charts.apiseven.com && \
helm repo update && \
helm upgrade --install apisix apisix/apisix --create-namespace --namespace apisix \
--set dashboard.enabled=true --set ingress-controller.enabled=true \
--set ingress-controller.config.apisix.serviceNamespace=apisix \
--set prometheus.enabled=true --set prometheus.serviceMonitor.enabled=true \
--set prometheus.serviceMonitor.namespace=apisix \
--set prometheus.serviceMonitor.selector.release=apisix
> Release "apisix" does not exist. Installing it now.
> NAME: apisix
> LAST DEPLOYED: Thu Jan 25 12:42:29 2024
> NAMESPACE: apisix
> STATUS: deployed
> REVISION: 1
> NOTES:
> 1. Get the application URL by running these commands:
> export NODE_PORT=$(kubectl get --namespace apisix -o jsonpath="{.spec.ports[0].nodePort}" services apisix-gateway)
> export NODE_IP=$(kubectl get nodes --namespace apisix -o jsonpath="{.items[0].status.addresses[0].address}")
> echo http://$NODE_IP:$NODE_PORT
# 確認
kubectl -n apisix get pods
> NAME READY STATUS RESTARTS AGE
> apisix-78975cc787-z8bsg 1/1 Running 0 2m35s
> apisix-dashboard-b58db9d6-bxzqb 1/1 Running 4 (77s ago) 2m35s
> apisix-etcd-0 1/1 Running 0 2m35s
> apisix-etcd-1 1/1 Running 0 2m35s
> apisix-etcd-2 1/1 Running 0 2m35s
> apisix-ingress-controller-7589b94554-dgbd6 1/1 Running 0 2m35s
kubectl -n apisix get services
> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
> apisix-admin ClusterIP 10.96.192.241 <none> 9180/TCP 3m15s
> apisix-dashboard ClusterIP 10.96.8.1 <none> 80/TCP 3m15s
> apisix-etcd ClusterIP 10.96.43.152 <none> 2379/TCP,2380/TCP 3m15s
> apisix-etcd-headless ClusterIP None <none> 2379/TCP,2380/TCP 3m15s
> apisix-gateway NodePort 10.96.213.35 <none> 80:31167/TCP 3m15s
> apisix-ingress-controller ClusterIP 10.96.166.85 <none> 80/TCP 3m15s
> apisix-ingress-controller-apisix-gateway NodePort 10.96.166.137 <none> 80:32409/TCP,443:32403/TCP 3m15s
# ポートフォワード http://localhost:8080 で API Gateway にアクセスできるようになる
kubectl -n apisix port-forward svc/apisix-gateway 8080:80
# ポートフォワード http://localhost:9080 で APISIX Dashboard にアクセスできるようになる
kubectl -n apisix port-forward svc/apisix-dashboard 9080:80
# ポートフォワード http://localhost:9180 で APISIX Admin API にアクセスできるようになる
kubectl -n apisix port-forward svc/apisix-admin 9180:9180
APISIX Admin API のデフォルト API Key は edd1c9f034335f136f87ad84b625c8f1
です (詳しくは設定ファイル config.yaml
の設定値を定義している values.yaml
をご覧ください).
APISIX Dashboard のデフォルトのログインユーザ/パスワードは admin
/admin
です (詳しくは設定ファイル config.yaml
の設定値を定義している values.yaml
をご覧ください).
APISIX API Gateway にも利用ユーザを定義する Consumer があります.
Consumer を作成してプラグインを設定していくことで,API を利用するユーザごとに挙動を変えることができます.
なお,APISIX でも Consumer は横断的に作成されます.
/consumers エンドポイントに POST をすることで Consumer を登録できます.
curl -i "http://localhost:9180/apisix/admin/consumers?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"username": "foo"
}'
http://localhost:9080/consumer/list
任意のリクエストをプロキシ
Kong Gateway と同様で Route と Upstream の概念を使ってルーティング&プロキシを行います.
ただし,Kong Gateway では Upstream API と Route API を順番に叩いて URI と宛先 API を設定していたのに対し,APISIX では Route API ですべて同時に設定することができます.
外部の API にルーティングを行う際は API Gateway から疎通可能であることを十分に確認してください.
ここでは同じ namespace に立てられた API サーバーに対するルーティングを試します.
まず適当なレスポンスを返すサーバーを API Gateway と同じ namespace apisix
にたてます.
Golang で Hello, APISIX!
と返す API サーバーを作成してコンテナ化し,kubectl apply
していきます.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, APISIX!")
})
http.ListenAndServe(":10080", nil)
}
FROM golang:1.21.3 as builder
WORKDIR /app
COPY main.go .
RUN go mod init helloapp
RUN CGO_ENABLED=0 GOOS=linux go build -o helloapp
FROM alpine:3.19.0
WORKDIR /app
COPY --from=builder /app/helloapp /app/
EXPOSE 10080
CMD ["/app/helloapp"]
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloapp
labels:
app: helloapp
spec:
replicas: 1
selector:
matchLabels:
app: helloapp
template:
metadata:
labels:
app: helloapp
spec:
containers:
- name: helloapp
image: caunus/helloapp:latest
ports:
- containerPort: 10080
apiVersion: v1
kind: Service
metadata:
name: helloapp
spec:
selector:
app: helloapp
ports:
- protocol: TCP
port: 80
targetPort: 10080
type: LoadBalancer
# コンテナを作成して DockerHub にあげておく
docker build -t caunus/helloapp:latest .
docker push caunus/helloapp:latest
# apisix namespace に kubectl apply
kubectl -n apisix apply -f deployment.yaml
> deployment.apps/helloapp created
kubectl -n apisix apply -f service.yaml
> service/helloapp created
# 確認
kubectl -n apisix get pods -o wide
> NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
> ...
> helloapp-98d8d47f-m6gss 1/1 Running 0 19s 10.244.0.14 kind-control-plane <none> <none>
kubectl -n apisix get services
> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
> ...
> helloapp LoadBalancer 10.96.35.128 <pending> 80:31910/TCP 2m6s
以上で同じ namespace apisix
にデプロイされている Pod からは http://helloapp で helloapp Pod からの応答を取得することができます.
気になる方は helloapp Pod に入って curl を取得し叩いてみることで確認できます.
kubectl exec -n apisix -it helloapp-98d8d47f-m6gss -- /bin/sh
> apk add curl
> curl http://helloapp
>> Hello, APISIX!
下準備ができたのでルーティング設定をしてから API Gateway にアクセスしてみます.
# Route を作成
curl -i "http://localhost:9180/apisix/admin/routes?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id": "example_route",
"uri": "/mock",
"upstream": {
"type": "roundrobin",
"nodes": {
"helloapp:80": 1
}
}
}'
# API Gateway に問い合わせ
curl -X GET http://localhost:8080/mock
> Hello, APISIX!
無事ルーティングできていることが確認できました.
Dashboard を確認すると,先ほど作成した Route が登録されていることがわかります.
ただし Upstream としては登録されないことが管理面で少し気になりました.
http://localhost:9080/routes/list
http://localhost:9080/upstream/list
そこで Dashboard で先ほど作成した Route は削除しておき,改めて Upstream と Route を分けて設定してみます.
# Upstream を作成
curl -i "http://localhost:9180/apisix/admin/upstreams?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id": "example_upstream",
"type": "roundrobin",
"nodes": [
{
"host": "helloapp",
"port": 80,
"weight": 1
}
]
}'
# Route を作成
curl -i "http://localhost:9180/apisix/admin/routes?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id": "example_route",
"uri": "/mock",
"upstream_id": "example_upstream"
}'
# API Gateway に問い合わせ
curl -X GET http://localhost:8080/mock
> Hello, APISIX!
上記で Upstream と Route を分けて管理をできることがわかりました.
http://localhost:9080/routes/list
http://localhost:9080/upstream/list
ロードバランシング
Kong Gateway と同様に Upstream に宛先となる API を登録することで簡単にロードバランシングができます.
任意のリクエストをプロキシ と同様に,Golang で Bonjour, APISIX!
と返す API サーバーを作成してコンテナ化し,kubectl apply
していきます.
ラウンドロビンで Hello, APISIX!
と Bonjour, APISIX!
を得ることにします.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Bonjour, APISIX!")
})
http.ListenAndServe(":11080", nil)
}
FROM golang:1.21.3 as builder
WORKDIR /app
COPY main.go .
RUN go mod init bonjourapp
RUN CGO_ENABLED=0 GOOS=linux go build -o bonjourapp
FROM alpine:3.19.0
WORKDIR /app
COPY --from=builder /app/bonjourapp /app/
EXPOSE 11080
CMD ["/app/bonjourapp"]
apiVersion: apps/v1
kind: Deployment
metadata:
name: bonjourapp
labels:
app: bonjourapp
spec:
replicas: 1
selector:
matchLabels:
app: bonjourapp
template:
metadata:
labels:
app: bonjourapp
spec:
containers:
- name: bonjourapp
image: caunus/bonjourapp:latest
ports:
- containerPort: 11080
apiVersion: v1
kind: Service
metadata:
name: bonjourapp
spec:
selector:
app: bonjourapp
ports:
- protocol: TCP
port: 80
targetPort: 11080
type: LoadBalancer
# コンテナを作成して DockerHub にあげておく
docker build -t caunus/bonjourapp:latest .
docker push caunus/bonjourapp:latest
# apisix namespace に kubectl apply
kubectl -n apisix apply -f deployment.yaml
> deployment.apps/bonjourapp created
kubectl -n apisix apply -f service.yaml
> service/bonjourapp created
# 確認
kubectl -n apisix get pods -o wide
> NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
> ...
> bonjourapp-bd6845f99-w68v9 1/1 Running 0 19s 10.244.0.15 kind-control-plane <none> <none>
> helloapp-98d8d47f-m6gss 1/1 Running 0 6m26s 10.244.0.14 kind-control-plane <none> <none>
kubectl -n apisix get services
> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
> ...
> bonjourapp LoadBalancer 10.96.128.240 <pending> 80:32252/TCP 84s
> helloapp LoadBalancer 10.96.35.128 <pending> 80:31910/TCP 7m27s
下準備ができたのでルーティング設定をしてから API Gateway にアクセスしてみます.
# Upstream を更新
curl -i "http://localhost:9180/apisix/admin/upstreams?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"id": "example_upstream",
"type": "roundrobin",
"nodes": [
{
"host": "helloapp",
"port": 80,
"weight": 1
},
{
"host": "bonjourapp",
"port": 80,
"weight": 1
}
]
}'
# API Gateway に問い合わせ
curl -X GET http://localhost:8080/mock
> Hello, APISIX!
curl -X GET http://localhost:8080/mock
> Bonjour, APISIX!
curl -X GET http://localhost:8080/mock
> Bonjour, APISIX!
curl -X GET http://localhost:8080/mock
> Hello, APISIX!
以上でラウンドロビンでロードバランシングができていることが確認できました.
リクエストの流量制御
Kong Gateway と同様に limit-count プラグインや limit-req プラグインなどを利用してリクエストの流量制御を行うことができます.
プラグインはグローバルで有効化することも Route 単位で有効化することもできます.
プラグインを無効化するには "_meta": {"disable": true}
で再登録します.よって一度設定した情報は残ることになります.
# 特定の Route で limit-count プラグインを有効化
curl -i "http://127.0.0.1:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 10,
"rejected_code": 503
}
}
}'
# 3 回連続でリクエストを送ると 503 が返る
curl -X GET http://localhost:8080/mock
> Bonjour, APISIX!
curl -X GET http://localhost:8080/mock
> Bonjour, APISIX!
curl -X GET http://localhost:8080/mock
> <html>
> <head><title>503 Service Temporarily Unavailable</title></head>
> <body>
> <center><h1>503 Service Temporarily Unavailable</h1></center>
> <hr><center>openresty</center>
> <p><em>Powered by <a href="https://apisix.apache.org/">APISIX</a>.</em></p></body>
> </html>
# プラグインの無効化
curl -i "http://127.0.0.1:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"limit-count": {
"_meta": {
"disable": true
}
}
}
}'
レスポンスのキャッシュ
Kong Gateway と同様に proxy-cache プラグイン を有効化することでレスポンスをキャッシュして,繰り返しのリクエストへの応答の高速化を図ることができます.
キャッシュ方法は disk と memory から選ぶことができます.
Kong Gateway では memory が基本だったと思うので差分と呼べるかもしれません.
プラグインはグローバルで有効化することも Route 単位で有効化することもできます.
プラグインを無効化するには "_meta": {"disable": true}
で再登録します.よって一度設定した情報は残ることになります.
# 特定の Route で disk-based な proxy-cache プラグインを有効化
curl -i "http://localhost:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"proxy-cache": {
"cache_key": ["$uri", "-cache-id"],
"cache_bypass": ["$arg_bypass"],
"cache_method": ["GET"],
"cache_http_status": [200],
"hide_cache_headers": true,
"no_cache": ["$arg_test"]
}
}
}'
# プラグインの無効化
curl -i "http://localhost:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"proxy-cache": {
"_meta": {
"disable": true
}
}
}
}'
API キー認証
Kong Gateway と同様に key-auth プラグイン を有効化することで API キー認証を実装することができます.
いま起動時に作成した Consumer foo に key-auth プラグインを有効化する例を考えてみます.
ここで,Consumer API は PATCH をサポートしておらず追加・削除と参照しかできないため,改めて作成しなおす必要があります.
Kong Gateway では既存の Consumer にそのまま設定を追加できたので差分となります.
Consumer の設定が終わったら Route などでも key-auth プラグインを有効化することで認証が行われるようになります.
# 一旦 foo を削除
curl -i "http://localhost:9180/apisix/admin/consumers/foo?api_key=edd1c9f034335f136f87ad84b625c8f1" -X DELETE
# foo を再作成
curl -i "http://localhost:9180/apisix/admin/consumers?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
"username": "foo",
"plugins": {
"key-auth": {
"key": "password"
}
}
}'
# Route で有効化
curl -i "http://localhost:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"key-auth": {}
}
}'
# リクエストを試す
curl -X GET http://localhost:8080/mock
> {"message":"Missing API key found in request"}
curl -X GET http://localhost:8080/mock -H 'apikey:password'
> Hello, APISIX!
# プラグインの無効化
curl -i "http://localhost:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"key-auth": {
"_meta": {
"disable": true
}
}
}
}'
Prometheus で監視
Kong Gateway 同様に Prometheus と連携して監視を行うことができます.
本記事では KinD 環境に Prometheus を起動して動作確認を行います.
ここで,API Gateway と Prometheus が接続できるように設定する必要があります.
一番簡単に接続できるようにする方法は apisix-gateway
Pod にサイドカーとして Prometheus をたちあげることだと思いますが,Prometheus は API Gateway と合わせてスケーリングされても困るので今回は採用しません.
次点で APISIX と同じ namespace に Prometheus を起動することが考えられますが,一つの Prometheus で複数のサービスを管理したい立場の人 (特に金銭観点が多い気がしますが) も一定層いることを踏まえ,別の namespace で立ち上げる場合を考えたいと思います.
まずは Prometheus がスクレイピングを行うために API Gateway にポート開けを行います.
API Gateway 側ではデフォルトで 9091
のポートを利用します (詳しくは設定ファイル config.yaml
の設定値を定義している values.yaml
をご覧ください).
apiVersion: v1
kind: Service
metadata:
name: apisix-monitor
spec:
selector:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
ports:
- name: apisix-monitor
port: 9091
protocol: TCP
targetPort: 9091
type: LoadBalancer
# Service 登録
kubectl -n apisix apply -f service.yaml
> service/apisix-monitor created
# 確認
kubectl -n apisix get services
> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
> ...
> apisix-monitor LoadBalancer 10.96.68.125 <pending> 9091:32224/TCP 13s
> ...
こちらで 9091
ポートが利用できるようになったので,ポートフォワードして Prometheus 用の metrics が取得できることを確認します.
# ポートフォワード http://localhost:9091 で API Gateway の Prometheus 用 metrics を取得できるようになる
kubectl -n apisix port-forward svc/apisix-monitor 9091:9091
# metrics の取得確認
curl http://localhost:9091/apisix/prometheus/metrics
上記が確認できたら Prometheus を準備していきます.
ホストから localhost:9091
で接続できるようにしたので Prometheus Pod からホストに接続できるように名前解決をできるようにする必要がありますが,ここでは host.docker.internal
を利用します.
apiVersion: v1
data:
prometheus.yml: |
scrape_configs:
- job_name: 'apisix'
scrape_interval: 15s
metrics_path: "/apisix/prometheus/metrics"
static_configs:
- targets: ['host.docker.internal:9091']
kind: ConfigMap
metadata:
name: prom-config
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
labels:
app: prometheus
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
containers:
- name: prometheus
image: prom/prometheus:v2.48.1
ports:
- containerPort: 9090
volumeMounts:
- name: prometheus-config-volume
mountPath: /etc/prometheus/
securityContext:
privileged: true
volumes:
- name: prometheus-config-volume
configMap:
name: prom-config
apiVersion: v1
kind: Service
metadata:
name: prometheus
spec:
selector:
app: prometheus
ports:
- protocol: TCP
port: 80
targetPort: 9090
type: LoadBalancer
# Prometheus 起動
kubectl apply -f configmap.yaml
> configmap/prom-config created
kubectl apply -f deployment.yaml
> deployment.apps/prometheus created
kubectl apply -f service.yaml
> service/prometheus created
# 確認
kubectl get configmaps
> NAME DATA AGE
> ...
> prom-config 1 51s
kubectl get deployments
> NAME READY UP-TO-DATE AVAILABLE AGE
> prometheus 1/1 1 1 68s
kubectl get services
> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
> ...
> prometheus LoadBalancer 10.96.92.134 <pending> 80:30559/TCP 83s
# ポートフォワード http://localhost:9090 で Prometheus にアクセスできるようになる
kubectl port-forward svc/prometheus 9090:80
上記で Prometheus 起動が確認できたら Route に対してプラグインを有効化します.
# 特定の Route で Prometheus プラグインを有効化
curl -i "http://localhost:9180/apisix/admin/routes/example_route?api_key=edd1c9f034335f136f87ad84b625c8f1" -X PATCH -d '
{
"plugins": {
"prometheus":{}
}
}'
apisix_http_status
の結果で /mock
へのリクエストが 2 種類現れていますが,kubectl -n apisix get services
の結果と照らし合わせればこれらが helloapp と bonjourapp それぞれの Service の IP であることがわかり,現在の接続状況などの監視ができることがわかりました.
カスタムプラグインでさらに拡張
Kong Gateway 同様にAPISIX でも Lua での外部プラグイン開発をサポートしています.7
Lua で開発を行う場合は公式ドキュメントを参考にするとよいです.独自のコードは API Gateway がロードするように設定ファイルに記載を行います.
ここで,外部ライブラリを使う場合は Nginx の設定を書き換えて依存関係を登録したりと本体に手を加える必要がある可能性があります.
APISIX では Lua 以外の言語での拡張に関して,サイドカーとして起動するプラグイン用の Runner も準備しており RPC 呼び出しを活用してカスタムプラグインを実行します.
Service | Summary |
---|---|
Java Plugin Runner | Runs Apache APISIX plugins written in Java. Implemented as a sidecar that accompanies Apache APISIX. |
Go Plugin Runner | Runs Apache APISIX plugins written in Go. Implemented as a sidecar that accompanies Apache APISIX. |
Python Plugin Runner | Runs Apache APISIX plugins written in Python. Implemented as a sidecar that accompanies Apache APISIX. |
Javascript Plugin Runner | Node.js / Deno Plugin Runner for APISIX (Alpha) |
また proxy-wasm
SDK を利用した WebAssembly プラグインを差し込むこともできます.8
こちらはまた別の記事で動作検証をしてみたいと思いますが,Kong Gateway よりかは複雑であることが伺えます.
まとめ
Apache APISIX は日本語での紹介やサポートはほとんどなく,また Kubernetes への習熟が必須な API Gateway でしたが,その一方で多くの追加機能を提供していることがわかりました.
また強力な OSS の開発体制も整えられてきているように思います.
試用している中ではパフォーマンスの面で気になることは特にありませんでしたが,この記事を読んで興味が湧いた方は試してみていただいて,ご自身が求めるスペックが発揮できるかをご確認いただければと思います.
後片付け (オマケ)
お試し環境を削除する手順も念のため載せておきます.
# 後片付け
helm uninstall -n apisix apisix
kubectl delete namespace apisix