本記事は「Kong Advent Calendar 2024」の21日目のエントリとして、KonnectのDataPlaneをPrometheus/Grafanaで監視する方法について解説する。
基本的には以下のための手順を整理したメモとなる。
- KonnectのDataPlaneのメトリクス取得
- DataPlaneがProxyする通信のメトリクス取得
メトリクス取得にはPrometheusを利用し、可視化はGrafanaを利用する。
今回はKonnect向けに書いているが設定はKong Gatewayにも流用可能なので、Kong Gatewayでも同じようなことをしたい人には参考になると思う。
前提
以下の前提で構築および検証を実施する。
- DataPlaneとPrometheusの展開先にEKSを利用
- cert-managerは導入済み
- Prometheus/Grafanaの構築にはPrometheus Operatorを利用
- Prometheus/Grafanaの公開に使うIngress ControllerはContourを使用
- KonnectのControlPlaneは作成済み
Ingress Controllerは当初Kong Ingress Controller(KIC)を利用しようと考えていたが、Konnectでの利用はUIがRead-Onlyになるなど少し制約が面倒だったので今回はContourにした。(参考:Kong Ingress Controller for Kubernetes Association)
構築
Ingress Controller(Contour)の構築
この辺の手順に従ってインストールする。
Helmのリポジトリを追加する。
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
インストールする。環境にもよるが大体1分くらいで完了する。
helm upgrade -i contour bitnami/contour -n projectcontour --create-namespace --wait
設定値を変更したい人はこちらからvalues.yamlの値が参照できる。
インストールすると以下のIngressClassが確認できる。
$ kubectl get ingressclass contour
NAME CONTROLLER PARAMETERS AGE
contour projectcontour.io/projectcontour/contour-contour <none> 5m56s
今後はこれを使ってIngressを作成する。
Prometheus/Grafanaの構築
PrometheusとGrafanaはPrometheus Operatorを使って構築する。
構築方法はHelmのリポジトリに記載があるのでこれを参考にインストールする。
リポジトリを追加する。
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
values.yaml
を作成する前に、Ingressで利用するドメインを環境変数に設定する。
DOMAIN=eks.hogehoge.info
values.yaml
を作成する。
cat <<EOF > ./prometheus-stack-values.yaml
alertmanager:
ingress:
enabled: true
ingressClassName: contour
annotations:
cert-manager.io/issuer: prometheus-stack-kube-prom-self-signed-issuer
hosts:
- alertmanager.$DOMAIN
tls:
- secretName: alertmanager-general-tls
hosts:
- alertmanager.$DOMAIN
grafana:
adminPassword: admin
ingress:
enabled: true
ingressClassName: contour
annotations:
cert-manager.io/issuer: prometheus-stack-kube-prom-self-signed-issuer
hosts:
- grafana.$DOMAIN
tls:
- secretName: grafana-general-tls
hosts:
- grafana.$DOMAIN
persistence:
enabled: true
type: statefulset
accessModes:
- ReadWriteOnce
size: 20Gi
finalizers:
- kubernetes.io/pvc-protection
prometheusOperator:
admissionWebhooks:
certManager:
enabled: true
prometheus:
prometheusSpec:
storageSpec:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
ingress:
enabled: true
ingressClassName: contour
annotations:
cert-manager.io/issuer: prometheus-stack-kube-prom-self-signed-issuer
hosts:
- prometheus.$DOMAIN
tls:
- secretName: prometheus-general-tls
hosts:
- prometheus.$DOMAIN
EOF
何となく分かると思うので詳細な説明は割愛するが、基本的にはcert-manager向けの設定とドメインの設定、ストレージ容量の指定をしているくらいである。
cert-managerのためのIssuer
やCertificate
などは自動生成されるので用意する必要はない。
インストールする。
helm upgrade -i -f prometheus-stack-values.yaml prometheus-stack prometheus-community/kube-prometheus-stack -n prometheus-stack --create-namespace --wait
指定したホスト名がIngressのADDRESS
に表示されるアドレスを向くようDNSサーバ側で名前解決の設定を入れる。
設定後、PrometheusとGrafanaにアクセスするとそれぞれ画面が確認できる。
Grafanaの初期ログインユーザ名とパスワードは<helm release名>-grafana
に格納されている。
今回はvalues.yaml
でパスワードにadmin
を設定しており、初期ユーザはadmin
になるので、両方admin
を指定すればログイン出来る。
DataPlaneの構築
Konnectと繋ぐためのDataPlaneをデプロイする。
ブラウザからKonnectにログインし、Data Plane Nodes
->New Data Plane Node
を選択し、作成画面のPlatform
でKubernetes
を選択する。
選択すると以下のように進行手順が表示されるので、これに従ってDataPlaneをデプロイする。
リポジトリを追加する。
kubectl create namespace kong
helm repo add kong https://charts.konghq.com
helm repo update
証明書を生成し、tls.crt
とtls.key
という名前で保存する。
保存後にSecretを作成し、DataPlaneが証明書を参照できるようにする。
kubectl create secret tls kong-cluster-cert -n kong --cert=./tls.crt --key=./tls.key
Secretの作成が終わったら、表示されているDataPlaneのvalues.yaml
を一旦ファイルに保存する。
DataPlaneのIngress設定
ここから一工夫加える。
せっかくIngressがあるので、ProxyをIngressで公開するよう設定を追加する。
通信はIngressでTLS終端してKong GatewayにはHTTPを渡すようにする(ContourだとContourのCRDであるkind: HTTPProxy
を使わないとTLSのパススルーが出来ないっぽい)。
IngressでTLS終端するために自己署名証明書発行のためのIssuer
とCertificate
を作成しapplyする。
cat <<EOF > ./proxy-cert.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: kong-konnect-dp-issuer-root
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: kong-konnect-dp-ca
spec:
commonName: kong-konnect-dp-ca
secretName: kong-konnect-dp-ca
isCA: true
issuerRef:
group: cert-manager.io
kind: Issuer
name: kong-konnect-dp-issuer-root
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: kong-konnect-dp-issuer
spec:
ca:
secretName: kong-konnect-dp-ca
EOF
kubectl apply -f ./proxy-cert.yaml
このIssuerを使って自己署名証明書を作成し、Ingressリソースも作成するためにvalues.yaml
に対してproxy
ブロックを追記する。
cat <<EOF >> ./values.yaml
proxy:
enabled: true
type: ClusterIP
http:
enabled: true
ingress:
enabled: true
ingressClassName: contour
hostname: "proxy.$DOMAIN"
tls:
- hosts:
- proxy.$DOMAIN
secretName: kong-konnect-dp-general-tls
annotations:
cert-manager.io/issuer: kong-konnect-dp-issuer
tls:
enabled: false
EOF
TLSはIngressでは使うのでproxy.ingress.tls
は設定するが、IngressでTLSを終端させた後はHTTPでProxyにアクセスするため、proxy.http.enabled
はtrue
で、proxy.tls.enabled
はfalse
となる
DataPlaneの監視設定
もう少しvalues.yaml
に追加設定する。
次はDataPlaneを監視するためにServiceMonitor
の設定を入れる。
ServiceMonitor
はPrometheus Operatorが提供するカスタムリソースであり、このリソース内で指定した条件に合致するkind: Service
で提供されるリソースを自動的にスクレイピングしてくれるものである。
ServiceMonitor
は幸いなことにvalues.yaml
で値を指定すれば自動生成されるので、その設定も追加する。
cat <<EOF >> ./values.yaml
serviceMonitor:
enabled: true
namespace: prometheus-stack
labels:
release: prometheus-stack
EOF
namespace
にPrometheusがいるNamespaceを指定し、Prometheus側に検出してもらうためにラベルを設定している。
なぜこのラベルなのかは「Prometheus OperatorのServiceMonitor / PodMonitor検出ルール」という内容で以前触れているのでそちらを参照して欲しい。
DataPlaneのデプロイ
このvalues.yaml
を使ってDataPlaneをデプロイする。
helm upgrade -i kong-konnect-dp kong/kong -n kong -f ./values.yaml
デプロイが完了すると以下のようにDataPlaneが見つかった旨が表示される。
作成したIngress経由でProxyにアクセスできることを確認する。
$ curl https://proxy.$DOMAIN -k
{
"message":"no Route matched with those values",
"request_id":"8767816cf10a442aa25ba93f36a83904"
}
Prometheus側を見ると、TargetにDataPlaneがいることが分かる。
PrometheusのExpression BrowserからKongに関連するメトリクスが取れていることも分かる。
なお、何度か試していた時に、たまにTargetにDataPlaneが出てこないことがあった。
確認するとServiceMonitor
に指定したラベルが反映されていなかった(原因は不明)。
その場合はkubectl edit servicemonitor -n prometheus-stack kong-konnect-dp-kong
みたいな感じでServiceMonitor
を修正し、metadata.labels
にrelease: prometheus-stack
を追加してあげるとよい。
Grafanaのダッシュボードの作成
メトリクスが取れていることが確認できたので、ダッシュボードを作成する。
Kong GatewayのダッシュボードはGrafanaLabsで公開されているので、新規に作成せずにここで公開されているものを使ってダッシュボードを作成する。
(図:Grafana Labsで"kong"でダッシュボードを検索した結果)
Grafanaにログインし、左サイドバーのDashboards
からNew
->New dashboard
をクリックする。
次にImport dashboard
->Discard
をクリックし、以下の新規にダッシュボードをインポートする設定に移る。
Kong Officialのダッシュボードはこちらにあり、このIDは7424なので、このIDを入力してLoad
をクリックし、データソースにPrometheusを選択してImport
をクリックする。
Importが完了するとダッシュボードが表示される。
ただし、今は通信を行っておらず、かつPrometheus Pluginも入れていないので見れるメトリクスは限定的であり、ほとんどがNo dataと表示される。
なお、Proxy Podの負荷状態に関するパネルはKongのダッシュボードには用意されていない。
これに関してはPrometheus OperatorでデプロイしたGrafanaに標準でついているダッシュボード(kubernetes-mixin)を使うとCPU・メモリ利用率、帯域使用量などが確認できるので、それで代用するとよい。
DataPlaneがProxyする通信のメトリクス取得
適当に通信を行って、Proxyした通信のメトリクスが見れるかを確認する。
ServiceとRouteをAPIで作成するために、最初にKonnectのトークン、ControlPlaneのID、KonnectのAPIエンドポイントをそれぞれ環境変数に設定する。
KONNECT_TOKEN=kpat_ER1WQxxxx
CP_ID=788397a0-b6f4-4dc8-a2f8-63cc6f0c62bb
KONNECT_API=https://us.api.konghq.com/v2
curlでAPIを発行してService、Routeを作成する。なお叩いているAPIの使用はこの辺を参考にした。
最初にServiceを作成する。
curl -s -X POST \
"${KONNECT_API}/control-planes/${CP_ID}/core-entities/services" \
-H "Authorization: Bearer $KONNECT_TOKEN" \
-d name=httpbin-service \
-d url=https://httpbin.konghq.com
作成時に表示されるServiceのIDを環境変数に設定する。
SERVICE_ID=306ed63f-2022-447b-90be-2425cdafa661
Routeを作成する。
curl -s -X POST \
"${KONNECT_API}/control-planes/${CP_ID}/core-entities/routes" \
-H "Authorization: Bearer ${KONNECT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "httpbin-route",
"paths": ["/httpbin"],
"service": {
"id": "'"${SERVICE_ID}"'"
}
}'
ServiceとRouteの作成が済んだらPrometheus Pluginを設定する。
ここではServiceに対して適用する。
curl -s -X POST \
"${KONNECT_API}/control-planes/${CP_ID}/core-entities/services/${SERVICE_ID}/plugins" \
-H "Authorization: Bearer $KONNECT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prometheus",
"config": {
"status_code_metrics": true,
"latency_metrics": true,
"bandwidth_metrics": true,
"upstream_health_metrics": true
}
}'
動作確認する。
以下のような感じで一定時間Proxyに対してアクセスする。
watch curl -s -k https://proxy.$DOMAIN/httpbin/user-agent
少し時間が経ったらPrometheusがスクレイピングしてメトリクスが見れるはずだ。
Prometheus側でメトリクスが取れることを確認する。
ここでは一例として、リクエスト数を確認してみる。
exported_service="httpbin-service"
に対してのアクセスがcode="200"
を返した回数が15回であることが確認できた。
Grafanaのダッシュボードの方も確認する。
今度はNo dataとならずRPSやレイテンシがグラフィカルに表示されることが確認できた。
まとめ
KonnectのDataPlaneの監視方法については公式ドキュメントには特に記載がなかったが、Helmのvalues.yaml
を読み解くことでServiceMonitor
を使って簡単にPrometheusの監視下に置くことが確認できた。
また公式のダッシュボードにはDataPlaneのパネルはないものの、Prometheus Operator標準のパネルで監視できることも確認できた。
今回アラートは特に設定しなかったが、必要なメトリクスが取れていることも分かったので、DataPlaneの障害時には通知を飛ばすのは難しくなさそうだ。
また、DataPlaneがProxyする通信のメトリクスも可視化できたので、こちらもアラート対象にする見込みを得ることが出来た。