How to Scale Your Pods Based on HTTP Traffic
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:
- Background
- KEDA HTTP Add-On
- Creating and installing demo application
- Setup HTTP Scaling
- 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.
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
HTTPScaledObject
s 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 theDeployment
specified in theHTTPScaledObject
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 ExternalNameService
— Same as the previous one but with theIngress
resource and demo application on the sameNamespace
.
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 —
ScaledObject
s andHTTPScaledObject
s (respectively) can be installed in anyNamespace
, and one installation will detect and process it. - namespaced — You must install your
ScaledObject
s andHTTPScaledObject
s in a specificNamespace
.
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 ScaledObject
s and HTTPScaledObject
s 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.
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 sameNamespace
where we installed the HTTP Add-on components, in our case the kedaNamespace
. This is not ideal because we would want to put all of the resources of our demo application on the sameNamespace
, 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.
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.
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!