How to Scale Your Pods Based on HTTP Traffic

Carlo Columna
18 min readAug 12, 2023

Kia ora everyone! How’s it going?

Welcome to the third and last part of a blog series discussing autoscaling capabilities in Kubernetes using KEDA or Kubernetes Event-driven Autoscaling. If you haven’t, I highly recommend checking out the first two parts of the series below.

In this part three of this blog series we will be scaling a workload running in an Amazon EKS cluster based on HTTP traffic.

The structure of this blog would be as follows:

  1. Background
  2. KEDA HTTP Add-On
  3. Creating and installing demo application
  4. Setup HTTP Scaling
  5. Test Scaling — explore three scaling scenarios

Background

As a start, let’s ask the question why do we even need this scaling capability?

In the first part of this blog series, How to Level Up Your Kubernetes Scaling, we’ve discussed in detail the limitations of a Horizontal Pod Autoscaler. Below are two of these limitations:

It cannot scale to zero. HPA by default uses metrics namely CPU and memory utilisation to calculate the desired number of replicas. Because these metrics cannot be zero, the desired number of replicas cannot be zero as well. This is not ideal for intermittent and resource-intensive workloads when you are trying to optimise your cost.

It’s limited to scaling based on metrics. You are unable to scale based on events or HTTP traffic.

As mentioned above, CPU and memory can never be zero. For our workload to scale to zero, we need to use a metric different from CPU and memory. Furthermore, when scaling HTTP servers, CPU and memory utilisation do not always correspond to the number of HTTP requests. As such, there is a need to be able to directly scale based on the actual HTTP requests. This is where the KEDA HTTP Add-on comes in!

KEDA HTTP Add-On

From the website, KEDA HTTP Add-on allows Kubernetes users to automatically scale their HTTP servers up and down (including to/from zero) based on incoming HTTP traffic. Just a bit of caution that the HTTP Add-on currently is in beta and as such it’s not yet recommended for production usage. This should not stop us, however, from using it for non-mission critical workloads.

Why an Add-On?

As the name suggests, it is an add-on for KEDA which means you have to install it separately on top of KEDA. As many as KEDA scalers are, it does not include an HTTP-based scaler out of the box. The reasons why are explained quite well here.

How does it work?

Note this section is heavily copied from the KEDA AddOn docs because it’s already quite well explained here.

KEDA-HTTP Architecture Overview
Architecture Overview

Above is the architecture overview of how KEDA-HTTP works in conjunction with KEDA. This is explained in more detail below.

High-Level Components

There are three major components of KEDA-HTTP plus KEDA itself.

  • Operator — This component listens for events related to HTTPScaledObjects and creates, updates or removes internal machinery as appropriate.
  • Interceptor — This component accepts and routes external HTTP traffic to the appropriate internal application, as appropriate.
  • Scaler — This component tracks the size of the pending HTTP request queue for a given app and reports it to KEDA. It acts as an external scaler.
  • KEDA — KEDA will receive metric from the external scaler and will scale up or down our HTTP application.

Setup HTTP scaling

Scaling is easily configured through a Custom Resource (CRD) called HTTPScaledObject.http.keda.sh or HTTPScaledObject for short. As mentioned above, the KEDA-HTTP operator will keep an eye on these CRDs and will take corresponding actions. When one is created, the operator does the following:

  • Update an internal routing table that maps incoming HTTP hostnames to internal applications.
  • Furnish this routing table information to interceptors so that they can properly route requests.
  • Create a ScaledObject for the Deployment specified in the HTTPScaledObject resource.

When the HTTPScaledObject is deleted, the operator reverses all of the aforementioned actions.

This CRD object instructs interceptors to forward requests for our applications host to the app’s backing Service. This is where you can also specify the number of pending (or in-progress) requests that our application needs to have before the HTTP Add-on will scale it.

TheHTTPScaledObject full specifications can be found here.

Autoscaling

After an HTTPScaledObject is created and the operator creates the appropriate resources, we must send HTTP requests through the interceptor so that our HTTP application is scaled. We must send the request to the interceptors Service called keda-add-ons-http-interceptor-proxy which is created when we install the KEDA-HTTP Add-on.

The interceptor keeps track of the number of pending HTTP requests — HTTP requests that it has forwarded but the app hasn’t returned. The scaler periodically makes HTTP requests to the interceptor via an internal RPC endpoint — on a separate port from the public server — to get the size of the pending queue. Based on this queue size, it reports scaling metrics as appropriate to KEDA. As the queue size increases, the scaler instructs KEDA to scale up as appropriate. Similarly, as the queue size decreases, the scaler instructs KEDA to scale down.

The HTTP Add-on works with the Kubernetes Horizontal Pod Autoscaler (HPA) — via KEDA itself — to execute scale-up and scale-down operations (except for scaling between zero and non-zero replicas). The add-on furnishes KEDA with two metrics — the current number of pending requests for a host, and the desired number (called targetPendingRequests in the HTTPScaledObject). KEDA then sends these metrics to the HPA, which uses them as the currentMetricValue and desiredMetricValue, respectively, in the HPA Algorithm.

The net effect is that the add-on scales up when your app grows to more pending requests than the targetPendingRequests value and scales down when it has fewer than that value.

Why does this project route HTTP requests?

To autoscale HTTP servers, the KEDA-HTTP Add-on needs access to metrics that it can report to KEDA so that KEDA itself can scale the target HTTP server. This is done through the use of an interceptor and external scaler which proxy incoming HTTP requests to provide autoscaling metrics. However, the KEDA-HTTP is minimally involved with routing and they are working on ways to get out of the “critical path” of an HTTP request as much as possible.

All right, that’s it for the KEDA-HTTP concepts, let’s see it in action!

Demo

For the demo, we’ll be scaling an HTTP application through the three scenarios below:

  • Scenario 1: Using a ClusterIP Service only
  • Scenario 2: Using an Ingress and NGINX Ingress Controller — We’ll expose our HTTP application outside of the Kubernetes cluster so we can scale based on external traffic.
  • Scenario 3: Using an Ingress, NGINX Ingress Controller and an ExternalName Service— Same as the previous one but with the Ingress resource and demo application on the same Namespace.

Prerequisites

Before we can proceed, let’s lay out the prerequisites:

  • Kubernetes cluster, we’ll be using an Amazon EKS cluster for the demo
  • KEDA installed in the Kubernetes cluster, see part 1 of this blog series on how to install
  • KEDA-HTTP Add-on and NGINX Ingress Controller installed in the Kubernetes cluster, see how to install both on the next steps below
  • Terminal with kubectl installed

Install KEDA-HTTP Add-On

Before installing it’s important to note that there are two modes of installation for both KEDA and KEDA-HTTP Add-on — cluster-global and namespaced mode.

  • cluster-global — ScaledObjects and HTTPScaledObjects (respectively) can be installed in any Namespace, and one installation will detect and process it.
  • namespaced — You must install your ScaledObjects and HTTPScaledObjects in a specific Namespace.

Both should be installed with the same mode, e.g. if you install one as cluster-global, the other must also be cluster-global.

We have installed KEDA from part 1 of this blog series using cluster-global mode so we’ll do the same for the Add-on. This allows the flexibility of creating ScaledObjects and HTTPScaledObjects in any Namespace albeit giving cluster privileges to KEDA and the Add-on.

To install we can use the Helm chart which is inside the KEDA’s default helm repository at kedacore/charts.

To keep all KEDA components in one place, let’s install the Add-on to the keda Namespace by running:

helm install http-add-on kedacore/keda-add-ons-http --namespace keda

Note that this installed the Add-on in cluster-global mode. Add --set operator.watchNamespace=<target namespace> to install the Add-on in namepaced mode. If we want to do this, we must also install KEDA in namespaced mode and use the same target Namespace.

Installing the Add-on won’t affect any running workloads in the cluster. We’ll need to install an HTTPScaledObject for each Deployment we want to scale.

After running the helm install command above, we should see the Add-on components prefixed with keda-add-ons-* running as Deployments.

$ kubectl get deployments -n keda
NAME READY UP-TO-DATE AVAILABLE AGE
keda-add-ons-http-controller-manager 1/1 1 1 5s
keda-add-ons-http-external-scaler 1/1 1 1 6s
keda-add-ons-http-interceptor 3/3 3 3 6s
keda-operator 1/1 1 1 26d
keda-operator-metrics-apiserver 1/1 1 1 26d
$ helm list -n keda
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
http-add-on keda 1 2023-06-27 19:42:00.912006094 +0000 UTC deployed keda-add-ons-http-0.4.1 0.4.0
keda keda 3 2023-06-27 19:41:24.550943176 +0000 UTC deployed keda-2.9.4 2.9.3

You can customise the Add-on Helm installation by updating the configuration parameters as listed here.

Right, with KEDA and the HTTP Add-on both installed we are now ready to create our demo application.

Install demo application

For our demo application, we’ll continue the tradition from the first two blog series by spinning up an NGINX application. First, let’s create a Namespace using kubectl like so,

$ kubectl create namespace demo-ns
namespace/demo-ns created

We then create a Deployment like so,

# Generate manifest
$ kubectl create deploy demo -n demo-ns --dry-run=client --image nginx -oyaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: demo
name: demo
namespace: demo-ns
spec:
replicas: 1
selector:
matchLabels:
app: demo
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: demo
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}

# Create deployment
$ kubectl create deploy demo -n demo-ns --image nginx
deployment.apps/demo created

# Check the pod is running
$ kubectl get pods -n demo-ns -w
NAME READY STATUS RESTARTS AGE
demo-68b4b4d5bf-f84jv 0/1 ContainerCreating 0 5s
demo-68b4b4d5bf-f84jv 1/1 Running 0 9s

Let’s expose the deployment we created by creating a Service of type ClusterIP like so,

# Create Service
$ kubectl expose deployment demo -n demo-ns --port=80 --target-port=80
service/demo exposed

# Double-check Service and Endpoint
$ k get svc,ep -n demo-ns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/demo ClusterIP 172.20.121.195 <none> 80/TCP 15s

NAME ENDPOINTS AGE
endpoints/demo 10.136.179.129:80 15s

Let’s try connecting to our NGINX application by running port-forward like so,

$ k port-forward svc/demo 8080:80 -n demo-ns
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

And then in a separate terminal let’s run a curl command,

$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Sweet!
We are ready to set-up the HTTP scaling for our demo application.

Set-up HTTP scaling

To set-up scaling we need to create a HTTPScaledObject for our demo application. Copying this example from the documentation and updating it to our needs we have,

kind: HTTPScaledObject
apiVersion: http.keda.sh/v1alpha1
metadata:
name: demo
namespace: demo-ns
spec:
host: myhost.com
scaleTargetRef:
deployment: demo
service: demo
port: 80
replicas:
min: 0 # We want to scale to zero
max: 10

Let’s save the manifest above to a file and then let’s apply it like so,

# Apply manifest
$ k apply -f demo-http-scaled-object.yaml
httpscaledobject.http.keda.sh/demo created

# Double-check
$ k get HTTPScaledObject -n demo-ns
NAME SCALETARGETDEPLOYMENTNAME SCALETARGETSERVICENAME SCALETARGETPORT MINREPLICAS MAXREPLICAS AGE ACTIVE
demo {"deployment":"demo","port":80,"service":"demo"} 0 10 6s

# Check created HPA
$ k get hpa -n demo-ns
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
keda-hpa-demo-app Deployment/demo 0/100 (avg) 1 10 5 58s

# Check the pods
$ kubectl get pods
No resources found in demo-ns namespace.

After applying the manifest, the HTTP Add-on operator detected it and created the necessary infrastructure. You can see it by checking the operator logs like so,

$ kubectl logs -nkeda keda-add-ons-http-controller-manager-5c8b9696d5-x22lm -c keda-add-ons-http-operator
2023-07-24T03:39:42Z INFO controllers.HTTPScaledObject Reconciliation start {"HTTPScaledObject.Namespace": "demo-ns", "HTTPScaledObject.Name": "demo"}
2023-07-24T03:39:42Z INFO controllers.HTTPScaledObject Adding Finalizer for the ScaledObject {"HTTPScaledObject.Namespace": "demo-ns", "HTTPScaledObject.Name": "demo"}
2023-07-24T03:39:42Z INFO controllers.HTTPScaledObject Reconciling HTTPScaledObject {"HTTPScaledObject.Namespace": "demo-ns", "HTTPScaledObject.Name": "demo", "Namespace": "demo-ns", "DeploymentName": "demo"}
2023-07-24T03:39:42Z INFO controllers.HTTPScaledObject Creating scaled objects {"HTTPScaledObject.Namespace": "demo-ns", "HTTPScaledObject.Name": "demo", "reconciler.appObjects": "addObjects", "HTTPScaledObject.name": "demo", "HTTPScaledObject.namespace": "demo-ns", "external scaler host name": "keda-add-ons-http-external-scaler.keda:9090"}
2023-07-24T03:39:42Z INFO controllers.HTTPScaledObject Creating App ScaledObject {"HTTPScaledObject.Namespace": "demo-ns", "HTTPScaledObject.Name": "demo", "reconciler.appObjects": "addObjects", "HTTPScaledObject.name": "demo", "HTTPScaledObject.namespace": "demo-ns", "ScaledObject": {"Object":{"apiVersion":"keda.sh/v1alpha1","kind":"ScaledObject","metadata":{"labels":{"app":"kedahttp-demo-app","name":"demo-app"},"name":"demo-app","namespace":"demo-ns"},"spec":{"advanced":{"restoreToOriginalReplicaCount":true},"maxReplicaCount":10,"minReplicaCount":5,"pollingInterval":1,"scaleTargetRef":{"kind":"Deployment","name":"demo"},"triggers":[{"metadata":{"host":"myhost.com","scalerAddress":"keda-add-ons-http-external-scaler.keda:9090"},"type":"external-push"}]}}}}
...

An HPA was also created and if you noticed, there is no longer a running pod because KEDA has deactivated the deployment because there are no incoming HTTP requests.

Cool! Our demo NGINX application is ready for scaling, let’s trigger scaling by connecting to it!

Test scaling

So far, we’ve created and deployed our NGINX application and set-up autoscaling by creating a HTTPScaledObject for it. Let’s go back to the three scenarios we mentioned earlier.

Scenario 1: Using a ClusterIP Service only

When we installed the HTTP Add-on, a Service called keda-add-ons-http-interceptor-proxy was created. To test scaling we need to route traffic to this Service. This Service has Endpoints pointing towards the interceptors

...  
ports:
- name: http
port: 8080
protocol: TCP
targetPort: inter-proxy
selector:
control-plane: interceptor
...

which then forwards the traffic to the right application. But how does it know which application to send the traffic to?

If you remember, our HTTPScaledObject has this spec below.

...
spec:
host: myhost.com
scaleTargetRef:
deployment: demo
service: demo
port: 80
...

From this spec, it knows that traffic with the host myhost.com needs to route to the Endpoints under the demo Service.

So far our setup looks like the diagram below.

Scaling using Service only

Right let’s trigger scaling by first creating a connection locally through kubectl port-forward :

$ kubectl port-forward svc/keda-add-ons-http-interceptor-proxy 8080:8080 -nkeda
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Handling connection for 8080

On a separate terminal let’s create a watch for our NGINX pods by running kubectl get pods -w.

On another terminal run let’s run a curl command specifying the host header.

$ curl localhost:8080 -H 'Host: myhost.com'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

The NGINX app has scaled and responded as seen above, albeit with a slight delay. If we look back at our watch we should see the pod starting up, then running then eventually terminating.

$ kubectl get pods -n demo-ns -w
NAME READY STATUS RESTARTS AGE
demo-68b4b4d5bf-p6z7v 0/1 Pending 0 0s
demo-68b4b4d5bf-p6z7v 0/1 Pending 0 0s
demo-68b4b4d5bf-p6z7v 0/1 ContainerCreating 0 0s
demo-68b4b4d5bf-p6z7v 1/1 Running 0 3s
demo-68b4b4d5bf-p6z7v 1/1 Terminating 0 6m3s
demo-68b4b4d5bf-p6z7v 0/1 Terminating 0 6m3s
demo-68b4b4d5bf-p6z7v 0/1 Terminating 0 6m4s
demo-68b4b4d5bf-p6z7v 0/1 Terminating 0 6m4s

So what just happened?

As mentioned earlier, when we routed traffic to the HTTP Add-on interceptor Service, the interceptor keeps track of the number of pending HTTP requests. The external scaler periodically checks the size of this pending queue and reports scaling metrics as appropriate to KEDA. As the queue size increases or decreases, the scaler instructs KEDA to scale up or down respectively. In our testing above, a single request is pending — enough for KEDA to scale the deployment to a single replica.

While we are sending request to our application through curl earlier, we can also check the status of the interceptor’s pending HTTP request queue. To do that, let’s start a proxy like so,

$ kubectl proxy -p 8002
Starting to serve on 127.0.0.1:8002

On a separate terminal, let’s get the status of the queue like so

$ curl -L localhost:8002/api/v1/namespaces/keda/services/keda-add-ons-http-interceptor-admin:9090/proxy/queue
{"myhost.com":1}

We can see that there is one pending request bound to myhost.com.

Scenario 2: Scale using an Ingress and Ingress Controller

The interceptor Service keda-add-ons-http-interceptor-proxy is of type ClusterIP, so it’s not accessible outside of our Kubernetes cluster. While we can access it using the kubectl port-forward command as seen in the first scenario, this is not recommended in production settings. To solve this, we can use an ingress controller to route to the interceptor service.

One of the widely used ingress controller is NGINX Ingress controller or simply nginx-ingress. We can install it using helm like so,

$  helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Release "ingress-nginx" does not exist. Installing it now.
NAME: ingress-nginx
LAST DEPLOYED: Thu Aug 3 08:48:00 2023
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller'
...

$ kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-7687f9d45-dbbbl 1/1 Running 0 89s

Now that we have nginx-ingress installed, let’s create an Ingress manifest for our demo application like so,

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
namespace: keda # <-- namespace where the Add-On is installed
spec:
ingressClassName: nginx
rules:
- host: myhost.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: keda-add-ons-http-interceptor-proxy # <-- interceptor service
port:
number: 8080

Note the following important details:

  • This Ingress resource must be created on the same Namespace where we installed the HTTP Add-on components, in our case the keda Namespace. This is not ideal because we would want to put all of the resources of our demo application on the same Namespace, the demo-ns. On the next scenario we’ll solve this limitation.
  • The backend service points to the Add-ons interceptors Service

Let’s save the above manifest to a file called ingress.yaml and apply it using kubectl like so kubectl apply -f ingress.yaml

$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/demo created

$ kubectl get ingress -n keda
NAME CLASS HOSTS ADDRESS PORTS AGE
demo nginx myhost.com internal-ab469z87hd65sf308b561ej76533e2cdummy-12345678.us-west-2.elb.amazonaws.com 80 35s

The ADDRESS we get from above is the IP address that our demo application will be running at on the public internet. Because we are using an ingress controller, this is the IP of the ingress controller’s Service . To be more specific, this is the address of the load balancer sitting in front of our nginx-ingress controller because we are using AWS.

Note: If you haven’t yet, it is recommended to manage your DNS records and set-up TLS certificates. External-DNS and Cert-Manager can be used for these respectively.

Our current setup now looks like the diagram below.

Scaling using ingress

Right, now let’s try scaling our application by sending HTTP request to it simply by using curl specifying the Host header. This is needed to tell the interceptor how to route the request. If we have a DNS name setup for the IP, we don’t need this header.

$ curl -H "Host: myhost.com" internal-ab469z87hd65sf308b561ej76533e2cdummy-12345678.us-west-2.elb.amazonaws.com

Because we have a DNS name set-up for the IP using External-DNS, we don’t need to set the header. Let’s send a request like so,

$ curl myhost.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Awesome! We got a response from our demo application!

A watch on our demo namespace shows the pod starting up in response to the scaling

$ kubectl get pods -n demo-ns -w
NAME READY STATUS RESTARTS AGE
demo-7fd9757bb7-s4rtl 0/1 ContainerCreating 0 1s
demo-7fd9757bb7-s4rtl 1/1 Running 0 8s

So to recap, we sent a request to our Ingress host which forwarded the request to the interceptors Service which then forwarded the traffic to our demo applications Service. Behind the scenes, the request was routed to the right destination through IP tables managed by kube-proxy but this is out of scope for this blog.

Scenario 3: Scale using an Ingress, NGINX Ingress Controller and ExternalName Service

In the previous scenario, we had to create our demo application’s Ingress on the same Namespace where we installed the HTTP Add-on components, which in our case is the keda Namespace . What if we want to create our Ingress resource inside the demo-ns together with the rest of our demo application’s resources? The problem here, is that Kubernetes networking does not allow for an Ingress resource to point to another Service on another Namespace . This means we cannot set the service backend of our Ingress resource in demo-ns to point to the interceptor’s Service in keda Namespace. We can, however point a Service to another Service on a different Namespace which is what we are going to do.

First, let’s create a Service of type ExternalName . An ExternalName Service is a special type of Service which instead of the typical selectors maps a Service to a DNS name.

apiVersion: v1
kind: Service
metadata:
name: demo-externalname
namespace: demo-ns
spec:
type: ExternalName
externalName: keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local # <-- interceptor service

The Service above maps to the interceptors Service DNS name. Let’s save the above manifest to a file called demo-externalname.yaml and apply it using kubectl like so kubectl apply -f demo-externalname.yaml

$ kubectl apply -f demo-externalname.yaml
service/demo-externalname created

$ kubectl get service -n demo-ns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo ClusterIP 172.20.121.195 <none> 80/TCP 164m
demo-externalname ExternalName <none> keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local <none> 25s

Notice that we now have two Services. Next, let’s delete our current Ingress in the keda Namespace .

$ kubectl delete ingress -n keda
ingress.networking.k8s.io "demo" deleted

Next let’s update our Ingress manifest like so,

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
namespace: demo-ns # <-- change namespace to demo-ns
spec:
ingressClassName: nginx
rules:
- host: myhost.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-externalname # <-- external-name service in demo-ns
port:
number: 8080 # <-- port of the interceptor service

Noticed that we are creating our Ingress in our demo-ns and we are updating the service backend to our ExternalName Service . The port remains the same. Our HTTPScaledObject also remains the same. Let’s create our new Ingress like so,

$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/demo created

With the changes above our setup now looks like below.

Scaling using ingress and service externalname

Ol’ right, time to test our changes! Let’s send a request to our demo application!

$ curl myhost.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Fantastic! Our demo application has responded!

Let’s check the pods that got created in response to the scaling triggered by our request,

$ kubectl get pods -n demo-ns -w
NAME READY STATUS RESTARTS AGE
demo-7fd9757bb7-zf6kx 0/1 Pending 0 0s
demo-7fd9757bb7-zf6kx 0/1 Pending 0 0s
demo-7fd9757bb7-zf6kx 0/1 ContainerCreating 0 0s
demo-7fd9757bb7-zf6kx 1/1 Running 0 2s
demo-7fd9757bb7-zf6kx 1/1 Terminating 0 5m39s
demo-7fd9757bb7-zf6kx 0/1 Terminating 0 5m39s
demo-7fd9757bb7-zf6kx 0/1 Terminating 0 5m39s
demo-7fd9757bb7-zf6kx 0/1 Terminating 0 5m39s

Sweet as!

To recap, we created a new Service of type ExternalName and pointed that to the interceptors Service. We then recreated our Ingress to our demo-ns and updated it to point to our ExternalName Service.

Coolbeans! That’s it for this blog! I hope this has been useful and that you learned something! Cheers!

Have a question or want to reach out for a yarn?

If you have some questions, feedback or just want to reach out for a good ol’ yarn, please connect and flick me a message at https://www.linkedin.com/in/carlo-columna/.

Like what you’ve read?

If you liked what you read, or if you found it useful, please follow me below for more articles and to get notified when I published new ones. Cheers!

References:

--

--

Carlo Columna

I'm a chemical engineer turned beer brewer turned tech enthusiasts. I write to empower others leverage new technologies in solving real world problems.