LoginSignup
5
3

この記事の目的

以下の記事で Kong Gateway の公式ドキュメントを読んで動作確認を行いました.

最近人気が伸びつつある API ゲートウェイである Apache APISIX についても同様に公式ドキュメントに沿って動作確認を行ったので,こちらの記事に残します.

こちらの記事を参考にして Apaxhe APISIX の API Gateway, Dashboard, Ingress Controller 環境を構築することができます.

デモ構成

kind-architecture.PNG

そもそも API ゲートウェイとは何ぞや

image.png

技術の進歩が速い中で正確に「これが定義である」というのは難しいですが,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 のサービス紹介

image.png

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 及び OpenRestylua-nginx-module の上に構築されています.

image.png

これは 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 です).

image.png

触ってみた感想としては,

  • 使いやすさは Kong Gateway (Free) と同程度
    • ボタンの位置など探すのにすごく苦労するわけではないが,多少は慣れが必要
    • 設定値を json として出力・確認するのが容易
  • 良くも悪くも Kong Gateway の GUI よりもタイムアウトまでの時間が短く,再ログインを求められる頻度が高い.
  • Grafana ダッシュボードとの連携を行うことができるのは良さそう

といったところでした.

Ingress Controller

image.png

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 をご覧ください).

http://localhost:9080/
image.png

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
image.png

任意のリクエストをプロキシ

proxy.PNG

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 していきます.

main.go
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)
}
Dockerfile
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"]
deployment.yaml
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
service.yaml
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
image.png

http://localhost:9080/upstream/list
image.png

そこで 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
image.png

http://localhost:9080/upstream/list
image.png

ロードバランシング

lb.PNG

Kong Gateway と同様に Upstream に宛先となる API を登録することで簡単にロードバランシングができます.

任意のリクエストをプロキシ と同様に,Golang で Bonjour, APISIX! と返す API サーバーを作成してコンテナ化し,kubectl apply していきます.
ラウンドロビンで Hello, APISIX!Bonjour, APISIX! を得ることにします.

main.go
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)
}
Dockerfile
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"]
deployment.yaml
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
service.yaml
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
        }
     }
  }
}'

image.png

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 をご覧ください).

service.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 を利用します.

configmap.yaml
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
deployment.yml
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
service.yml
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":{}
    }
}'

http://localhost:9090/targets
image.png

http://localhost:9090/graph
image.png

apisix_http_status の結果で /mock へのリクエストが 2 種類現れていますが,kubectl -n apisix get services の結果と照らし合わせればこれらが helloapp と bonjourapp それぞれの Service の IP であることがわかり,現在の接続状況などの監視ができることがわかりました.

カスタムプラグインでさらに拡張

image.png

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
  1. https://cncf.landscape2.io/guide#orchestration-management--api-gateway

  2. https://www.gartner.com/doc/reprints?id=1-2F7MCTJF&ct=231004&st=sb

  3. https://apisix.apache.org/

  4. https://apisix.apache.org/docs/apisix/FAQ/#why-does-apache-apisix-use-etcd-for-the-configuration-center

  5. https://www.publickey1.jp/blog/22/apikong_gatewaypr.html

  6. https://api7.ai/apisix-vs-kong

  7. https://apisix.apache.org/docs/apisix/external-plugin/

  8. https://apisix.apache.org/docs/apisix/wasm/

5
3
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
5
3