helm upgrade --install kong-operator kong/kong-operator -n kong-system \
--create-namespace \
--set image.tag=2.3
kubectl -n kong-system wait --for=condition=Available=true --timeout=300s deployment/kong-operator-kong-operator-controller-managerAutoscale workloads with Prometheus
Deploy a DataPlaneMetricsExtension to expose latency metrics from a Service,
then configure the Kong Operator to associate those metrics with the Data Plane.
This enables external tools like Prometheus and KEDA to trigger scaling decisions.
Prerequisites
Kong Operator running
If you want cert-manager to issue and rotate the admission and conversion webhook certificates, install cert-manager to your cluster and enable cert-manager integration by passing the following argument while installing, in the next step:
--set global.webhooks.options.certManager.enabled=trueIf you do not enable this, the chart will generate and inject self-signed certificates automatically. We recommend enabling cert-manager to manage the lifecycle of these certificates.
Kong Operator needs a certificate authority to sign the certificate for mTLS communication between the control plane and the data plane.
This is handled automatically by the Helm chart. If you need to provide a custom CA certificate, refer to the certificateAuthority section
in the values.yaml of the Helm chart to learn how to create and reference your own CA certificate.
Apply a KongLicense. This assumes that your license is available in ./license.json
echo "
apiVersion: configuration.konghq.com/v1alpha1
kind: KongLicense
metadata:
name: kong-license
rawLicenseString: '$(cat ./license.json)'
" | kubectl apply -f -Enable the Gateway API
The Kong Operator Helm chart installs the Gateway API CRDs when you install it, so you do not need to install them separately.
-
Create a
GatewayandGatewayClassinstance to use.echo " apiVersion: v1 kind: Namespace metadata: name: kong --- apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: kong annotations: konghq.com/gatewayclass-unmanaged: 'true' spec: controllerName: konghq.com/gateway-operator --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: kong spec: gatewayClassName: kong listeners: - name: proxy port: 80 protocol: HTTP allowedRoutes: namespaces: from: All " | kubectl apply -n kong -f -
Required Kubernetes resources
This how-to requires some Kubernetes services to be available in your cluster. These services will be used by the resources created in this how-to.
kubectl apply -f https://developer.konghq.com/manifests/kic/command-service.yaml -n kongThis how-to also requires 1 pre-configured route:
Wait until the pods for the services are ready:
kubectl wait --for=condition=Ready pod --all -n kong --timeout=300sAutoscaling Workloads
This tutorial shows how to autoscale workloads based on Service latency. The command service created in the prerequisites allows us to inject an artificial delay in to responses to trigger autoscaling.
Create a DataPlaneMetricsExtension
The DataPlaneMetricsExtension allows Kong Operator to monitor Service latency and expose it on the /metrics endpoint.
-
Create a
DataPlaneMetricsExtensionthat points to thecommandservice:echo ' kind: DataPlaneMetricsExtension apiVersion: gateway-operator.konghq.com/v1alpha1 metadata: name: kong namespace: kong spec: serviceSelector: matchNames: - name: command config: latency: true ' | kubectl apply -f - -
Create a GatewayConfiguration that uses it:
echo ' kind: GatewayConfiguration apiVersion: gateway-operator.konghq.com/v2beta1 metadata: name: kong namespace: kong spec: extensions: - kind: DataPlaneMetricsExtension group: gateway-operator.konghq.com name: kong ' | kubectl apply -f - -
Patch the GatewayClass to use the config:
kubectl patch -n kong --type=json gatewayclass kong -p='[ { "op":"add", "path":"/spec/parametersRef", "value":{ "group": "gateway-operator.konghq.com", "kind": "GatewayConfiguration", "name": "kong", "namespace": "kong", } } ]'
Install Prometheus
Note: You can reuse your current Prometheus setup and skip this step but please be aware that it needs to be able to scrape Kong Operator’s metrics (e.g. through
ServiceMonitor) and note down the namespace in which it’s deployed.
-
Add the
prometheus-communityhelm charts:helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update -
Install Prometheus via
kube-prometheus-stackhelm chart:helm upgrade --install --create-namespace -n prometheus prometheus prometheus-community/kube-prometheus-stack
Create a ServiceMonitor to scrape Kong Operator
To make Prometheus scrape Kong Operator’s /metrics endpoint, we’ll need to create a ServiceMonitor:
echo '
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
release: prometheus
name: gateway-operator
namespace: kong-system
spec:
endpoints:
- port: http
scheme: http
path: /metrics
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
selector:
matchLabels:
control-plane: controller-manager ' | kubectl apply -f -After applying the above manifest you can check one of the metrics exposed by Kong Operator to verify that the scrape config has been applied.
To access the Prometheus UI, create a port-forward and visit http://localhost:9090:
kubectl port-forward service/prometheus-kube-prometheus-prometheus 9090:9090 -n prometheusThis can be verified by going to your Prometheus UI and querying:
up{service=~"kong-operator-kong-operator-metrics"}Prometheus metrics can take up to 2 minutes to appear.
Install prometheus-adapter
The prometheus-adapter package makes Prometheus metrics usable in Kubernetes.
To deploy prometheus-adapter, you’ll need to decide what time series to expose so that Kubernetes can consume it.
Note: Kong Operator enriches specific metrics for use with
prometheus-adapter. See the overview for a complete list.
Create a values.yaml file to deploy the prometheus-adapter helm chart.
This configuration calculates a kong_upstream_latency_ms_60s_average metric, which exposes a 60s moving average of upstream response latency:
echo $'
prometheus:
# Update this value if Prometheus is installed in a different namespace
url: http://prometheus-kube-prometheus-prometheus.prometheus.svc
rules:
default: false
custom:
- seriesQuery: \'{__name__=~"^kong_upstream_latency_ms_(sum|count)",kubernetes_namespace!="",kubernetes_name!="",kubernetes_kind!=""}\'
resources:
overrides:
exported_namespace:
resource: "namespace"
exported_service:
resource: "service"
name:
as: "kong_upstream_latency_ms_60s_average"
metricsQuery: |
sum by (exported_service) (rate(kong_upstream_latency_ms_sum{<<.LabelMatchers>>}[60s:10s]))
/
sum by (exported_service) (rate(kong_upstream_latency_ms_count{<<.LabelMatchers>>}[60s:10s]))
' > values.yamlInstall prometheus-adapter using Helm:
helm upgrade --install --create-namespace -n prometheus --values values.yaml prometheus-adapter prometheus-community/prometheus-adapterSend traffic
-
Wait for the
Gatewayand thecommandHTTPRouteto be programmed:kubectl wait --for=condition=Programmed gateway/kong -n kong --timeout=5m kubectl wait --for=jsonpath='{.status.parents[0].conditions[?(@.type=="Programmed")].status}'=True httproute/command -n kong --timeout=5m -
Get the
Gateway’s external IP address:export PROXY_IP=$(kubectl get gateway kong -n kong -o jsonpath='{.status.addresses[0].value}') -
To trigger autoscaling, start sending traffic in the background. Each request makes the underlying deployment sleep for 100ms, which raises the average response time to that value. Leave it running while you work through the rest of this guide: the 60-second average that the autoscaler reads only stays above its target while requests are flowing, and the metric can take a few minutes to be populated. The loop sends a request every second for about 30 minutes, which is long enough for the metric to appear and the autoscaler to react:
for _ in {1..1800}; do curl -k --no-progress-meter --fail-with-body "http://$PROXY_IP/command/shell?cmd=sleep%200.1" sleep 1 done > /dev/null 2>&1 &
Verify metrics are exposed in Kubernetes
When all is configured, you should be able to see the metric you’ve configured in prometheus-adapter exposed via the Kubernetes Custom Metrics API. Wait until the metric is populated, then query it:
timeout 900 bash -c 'until kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kong/services/command/kong_upstream_latency_ms_60s_average" | grep -q kong_upstream_latency_ms_60s_average; do sleep 10; done'
kubectl get --raw '/apis/custom.metrics.k8s.io/v1beta1/namespaces/kong/services/command/kong_upstream_latency_ms_60s_average' | jqNote: The
prometheus-adaptermay take a few minutes to populate the custom metrics. It only discoverskong_upstream_latency_ms_60s_averageafter the data plane has picked up the metrics extension and started reporting latency, so keep the traffic loop running while you wait.
This should result in:
{
"kind": "MetricValueList",
"apiVersion": "custom.metrics.k8s.io/v1beta1",
"metadata": {},
"items": [
{
"describedObject": {
"kind": "Service",
"namespace": "kong",
"name": "command",
"apiVersion": "/v1"
},
"metricName": "kong_upstream_latency_ms_60s_average",
"timestamp": "2024-03-06T13:11:12Z",
"value": "102312m",
"selector": null
}
]
}Note:
102312mis a Kubernetes way of expressing numbers as integers.valuerepresents the latency in microseconds, and is approximately equivalent to 102 milliseconds (ms).
Use exposed metric in HorizontalPodAutoscaler
When the metric configured in prometheus-adapter is available through Kubernetes’s Custom Metrics API,
we can use it in HorizontalPodAutoscaler to autoscale our workload, specifically the command Deployment.
This can be done by using the following manifest, which will scale the underlying command Deployment between 1 and 10 replicas, trying to keep the average latency across last 60s at 40ms.
echo '
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: command
namespace: kong
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: command
minReplicas: 1
maxReplicas: 10
behavior:
scaleDown:
stabilizationWindowSeconds: 1
policies:
- type: Percent
value: 100
periodSeconds: 10
scaleUp:
stabilizationWindowSeconds: 1
policies:
- type: Percent
value: 100
periodSeconds: 2
- type: Pods
value: 4
periodSeconds: 2
selectPolicy: Max
metrics:
- type: Object
object:
metric:
name: "kong_upstream_latency_ms_60s_average"
describedObject:
apiVersion: v1
kind: Service
name: command
target:
type: Value
value: "40" ' | kubectl apply -f -Observe Kubernetes SuccessfulRescale events
You can watch SuccessfulRescale events using the following kubectl command:
timeout 60 kubectl get events -n kong --field-selector involvedObject.name=command,involvedObject.kind=HorizontalPodAutoscaler -w | grep -m1 SuccessfulRescaleIf everything went well we should see the SuccessfulRescale events:
12m Normal SuccessfulRescale horizontalpodautoscaler/command New size: 2; reason: Service metric kong_upstream_latency_ms_60s_average above target
12m Normal SuccessfulRescale horizontalpodautoscaler/command New size: 4; reason: Service metric kong_upstream_latency_ms_60s_average above target
12m Normal SuccessfulRescale horizontalpodautoscaler/command New size: 8; reason: Service metric kong_upstream_latency_ms_60s_average above target
12m Normal SuccessfulRescale horizontalpodautoscaler/command New size: 10; reason: Service metric kong_upstream_latency_ms_60s_average above targetThen when latency drops (when the traffic loop finishes, or when you stop it) you should observe the SuccessfulRescale events scaling your workloads down:
4s Normal SuccessfulRescale horizontalpodautoscaler/command New size: 1; reason: All metrics below targetCleanup
Delete the resources created in this guide
Uninstall the metrics stack this guide installs, delete the resources it created, then remove the operator. Deleting the kong-system namespace removes the operator:
helm uninstall prometheus-adapter -n prometheus
helm uninstall prometheus -n prometheus
kubectl delete --ignore-not-found namespace prometheus
kubectl delete -n kong --ignore-not-found \
horizontalpodautoscaler/command \
servicemonitor/gateway-operator \
httproute/command \
gateway/kong \
gatewayconfiguration/kong
kubectl delete --ignore-not-found gatewayclass/kong
kubectl delete --ignore-not-found namespace kong
helm uninstall kong-operator -n kong-system
kubectl delete --ignore-not-found namespace kong-system