Autoscale workloads with Datadog

Deployment Platform
Related Documentation
TL;DR

Deploy a DataPlaneMetricsExtension to collect metrics (like latency) from a target service, expose those metrics on the /metrics endpoint, and configure the operator to reference this data for scaling decisions.

Prerequisites

If you don’t have a Konnect account, you can get started quickly with our onboarding wizard.

  1. The following Konnect items are required to complete this tutorial:
    • Personal access token (PAT): Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.
  2. Set the personal access token as an environment variable:

    export KONNECT_TOKEN='YOUR KONNECT TOKEN'
  1. Install the Gateway API CRDs before installing Kong Ingress Controller.

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml
  2. Create a Gateway and GatewayClass instance 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 -
  1. Add the Kong Helm charts:

    helm repo add kong https://charts.konghq.com
    helm repo update
  2. Install Kong Operator using Helm:

    helm upgrade --install kong-operator kong/kong-operator -n kong-system \
      --create-namespace \
      --set image.tag=2.2 \
      --set env.ENABLE_CONTROLLER_KONNECT=true
    helm upgrade --install kong-operator kong/kong-operator -n kong-system \
      --create-namespace \
      --set image.tag=2.2

    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=true

    If 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 -

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 kong

This 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=300s

To install Datadog agents in your cluster you will need:

  • An API key
  • An application key
  • The Datadog site for your region (for example datadoghq.com for the US1 region or datadoghq.eu for the EU region).

Export these to your environment:

export DD_SITE='YOUR DATADOG SITE'
export DD_API_KEY='YOUR DATADOG API KEY'
export DD_APP_KEY='YOUR DATADOG APPLICATION KEY'

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.

  1. Create a DataPlaneMetricsExtension that points to the command service:

     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 -
  2. 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 -
  3. 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",
             }
         }
     ]'

You can integrate Kong Operator with Datadog Metrics to use Kong Gateway latency metrics to autoscale workloads based on their metrics.

Install Datadog in your Kubernetes cluster

  1. Create the following configuration file:

    echo '
    datadog:
      kubelet:
        tlsVerify: false
       
    clusterAgent:
      enabled: true
      # Enable the metricsProvider to be able to scale based on metrics in Datadog
      metricsProvider:
        # Set this to true to enable Metrics Provider
        enabled: true
        # Enable usage of DatadogMetric CRD to autoscale on arbitrary Datadog queries
        useDatadogMetrics: true
       
      prometheusScrape:
        enabled: true
        serviceEndpoints: true
       
    agents:
      containers:
        agent:
          env:
          - name: DD_HOSTNAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
    ' > values.yaml
  2. Install Datadog’s helm chart:

    helm repo add datadog https://helm.datadoghq.com
    helm repo update
    helm install -n default datadog -f values.yaml --set datadog.apiKey=${DD_API_KEY} --set datadog.appKey=${DD_APP_KEY} --set datadog.site=${DD_SITE} datadog/datadog
  3. Wait for the DatadogMetric CRD to be established before continuing:

    kubectl wait --for=condition=Established crd/datadogmetrics.datadoghq.com --timeout=120s

Send traffic

To trigger autoscaling, run the following command in a new terminal window. This will cause the underlying deployment to sleep for 100ms on each request and thus increase the average response time to that value.

while curl -k "http://$(kubectl get gateway kong -o custom-columns='name:.status.addresses[0].value' --no-headers -n kong)/command/shell?cmd=sleep%200.1" ; do sleep 1; done

Keep this running while you move on to the next steps.

Annotate Kong Operator with Datadog checks config

In a new terminal window, add the following annotation on Kong Operator’s Pod to tell Datadog how to scrape Kong Operator’s metrics:

POD_NAME=$(kubectl get pods -n kong-system -l control-plane=controller-manager -o custom-columns='name:.metadata.name' --no-headers)
kubectl annotate -n kong-system pod $POD_NAME \
  'ad.datadoghq.com/manager.checks={
    "openmetrics": {
      "instances": [
        {
          "prometheus_url": "http://%%host%%:8080/metrics",
          "namespace": "autoscaling",
          "metrics": [
            "kong_upstream_latency_ms"
          ],
          "send_histograms_buckets": true,
          "send_distribution_buckets": true
        }
      ]
    }
  }'

After applying the above you should see avg:autoscaling.kong_upstream_latency_ms{service:command} metrics in your Datadog Metrics explorer.

Expose Datadog metrics to Kubernetes

To use an external metric in HorizontalPodAutoscaler, we need to configure the Datadog agent to expose it.

There are several ways to achieve this but we’ll use a Kubernetes native way and use the DatadogMetric CRD:

echo '
apiVersion: datadoghq.com/v1alpha1
kind: DatadogMetric
metadata:
  name: command-kong-upstream-latency-ms-avg
  namespace: kong
spec:
  query: autoscaling.kong_upstream_latency_ms{service:command} ' | kubectl apply -f -

Note: The Datadog Cluster Agent only starts refreshing a DatadogMetric’s status once it’s referenced by a HorizontalPodAutoscaler. Its ACTIVE/VALID/VALUE fields will stay empty until you create the HPA in the next section.

Use DatadogMetric in HorizontalPodAutoscaler

The command-kong-upstream-latency-ms-avg DatadogMetric from the kong namespace can be used by the Kubernetes HorizontalPodAutoscaler to autoscale our workload, specifically the command Deployment. The HorizontalPodAutoscaler must be created in the same namespace as the command Deployment it targets, which is kong.

  1. Run the following command to scale the underlying command Deployment between 1 and 10 replicas, trying to keep the average latency across last 30s 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: External
        external:
          metric:
            name: datadogmetric@kong:command-kong-upstream-latency-ms-avg
          target:
            type: Value
            value: 40 ' | kubectl apply -f -
  2. Once the HPA is created, wait for DatadogMetric to become active and valid:

    kubectl wait --for=jsonpath='{.status.conditions[?(@.type=="Active")].status}'=True -n kong datadogmetric/command-kong-upstream-latency-ms-avg --timeout=120s
    kubectl wait --for=jsonpath='{.status.conditions[?(@.type=="Valid")].status}'=True -n kong datadogmetric/command-kong-upstream-latency-ms-avg --timeout=120s
    kubectl get -n kong datadogmetric command-kong-upstream-latency-ms-avg

    You should get the following result:

    NAME                                   ACTIVE   VALID   VALUE               REFERENCES          UPDATE TIME
    command-kong-upstream-latency-ms-avg   True     True    104.46194839477539  hpa:kong/command   38s

Validate

  1. Run the following command to get the command-kong-upstream-latency-ms-avg metric via the Kubernetes External Metrics API:

    kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/kong/datadogmetric@kong:command-kong-upstream-latency-ms-avg" | jq

    You should get the following result:

    {
      "kind": "ExternalMetricValueList",
      "apiVersion": "external.metrics.k8s.io/v1beta1",
      "metadata": {},
      "items": [
        {
          "metricName": "datadogmetric@kong:command-kong-upstream-latency-ms-avg",
          "metricLabels": null,
          "timestamp": "2024-03-08T18:03:02Z",
          "value": "104233138021n"
        }
      ]
    }

    Note: 104233138021n is a Kubernetes way of expressing numbers as integers. Since value here represents latency in milliseconds, it is approximately equivalent to 104.23ms.

  2. Check for SuccessfulRescale events:

    kubectl get events -n kong --field-selector involvedObject.name=command,involvedObject.kind=HorizontalPodAutoscaler,reason=SuccessfulRescale --sort-by='.lastTimestamp'

    The result should look like this:

    LAST SEEN   TYPE     REASON              OBJECT                            MESSAGE
    38s         Normal   SuccessfulRescale   horizontalpodautoscaler/command   New size: 5; reason: external metric datadogmetric@kong:command-kong-upstream-latency-ms-avg(nil) above target
    23s         Normal   SuccessfulRescale   horizontalpodautoscaler/command   New size: 10; reason: external metric datadogmetric@kong:command-kong-upstream-latency-ms-avg(nil) above target

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!