HTTP Scaling with Istio VirtualServices
This guide demonstrates how to scale applications within an Istio service mesh using VirtualService
resources to manage HTTP traffic. You’ll deploy a sample application, configure the necessary Istio resources (Gateway
, VirtualService
), deploy a KEDA HTTPScaledObject
, and observe how Kedify automatically manages traffic routing for efficient load-based scaling including scale-to-zero when there’s no demand.
Architecture Overview
For applications managed by Istio and exposed via VirtualService
, Kedify integrates with the service mesh using its autowiring feature. When using the kedify-http
scaler, the traffic flow is adjusted to include Kedify’s proxy:
Istio Gateway -> VirtualService -> kedify-proxy -> Service -> Deployment
The kedify-proxy
intercepts traffic routed by the VirtualService
, collects metrics based on hosts defined in the HTTPScaledObject
, and enables scaling decisions. When traffic increases, Kedify scales your application up; when traffic decreases, it scales down—even to zero if configured. Kedify automatically modifies the VirtualService
destination host to point to the kedify-proxy
service.
Prerequisites
- A running Kubernetes cluster with Istio installed.
- The
kubectl
command line utility installed and accessible. - Install hey to send load to a web application.
Step 1: Prepare Istio Sidecar Injection
Enable Istio sidecar injection for the namespaces where your application will run:
kubectl create ns kedakubectl patch namespace keda -p '{"metadata": {"labels": {"istio-injection": "enabled"}}}'kubectl patch namespace default -p '{"metadata": {"labels": {"istio-injection": "enabled"}}}'
Step 2: Install KEDA
Install KEDA and its HTTP add-on in the keda
namespace:
helm repo add kedacore https://kedacore.github.io/chartshelm install keda kedacore/keda --namespace kedahelm install http-add-on kedacore/keda-add-ons-http --namespace keda
Verify that KEDA and its components are running:
kubectl get pods -n keda
You should see output similar to:
NAME READY STATUS RESTARTS AGEkeda-add-ons-http-controller-manager-79db447c7d-7r9xb 3/3 Running 0 39skeda-add-ons-http-external-scaler-dfb9f7bcc-dxqft 2/2 Running 0 39skeda-add-ons-http-external-scaler-dfb9f7bcc-fh76m 2/2 Running 0 39skeda-add-ons-http-external-scaler-dfb9f7bcc-phcw9 2/2 Running 0 39skeda-add-ons-http-interceptor-6dd68bbc87-5jz6v 2/2 Running 0 38skeda-add-ons-http-interceptor-6dd68bbc87-5ng2w 2/2 Running 0 39skeda-add-ons-http-interceptor-6dd68bbc87-pnp47 2/2 Running 0 38skeda-admission-webhooks-554fc8d77f-n7mml 2/2 Running 0 39skeda-operator-dd878ddf6-7ww29 2/2 Running 0 39skeda-operator-metrics-apiserver-86cc9c6fff-t4prd 2/2 Running 0 39s
Step 3: Deploy Sample Application
For this example, we’ll use podinfo as our sample application:
helm upgrade --install --wait podinfo --namespace default oci://ghcr.io/stefanprodan/charts/podinfo
Create the Istio Gateway and initial VirtualService:
apiVersion: networking.istio.io/v1beta1kind: Gatewaymetadata: name: app namespace: defaultspec: selector: istio: ingressgateway servers: - hosts: - 'www.podinfo.com' port: name: http number: 80 protocol: HTTP---apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata: name: podinfo namespace: defaultspec: hosts: - 'www.podinfo.com' gateways: - app http: - match: - uri: prefix: / route: - destination: host: podinfo port: number: 9898
Gateway
: Defines the entry point for traffic into the Istio service mesh.VirtualService
: Configures Istio’s routing. It attaches to the specified gateway, matches requests for the hostwww.podinfo.com
, and routes traffic to thepodinfo
service. Kedify will automatically update thedestination.host
field to point to thekedify-proxy
when autowiring is active.
Apply the configuration:
kubectl apply -f istio.yaml
Step 4: Configure Autoscaling
Create an HTTPScaledObject to define the scaling behavior:
kind: HTTPScaledObjectapiVersion: http.keda.sh/v1alpha1metadata: name: podinfo namespace: defaultspec: hosts: - www.podinfo.com scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: podinfo service: podinfo port: 9898 replicas: min: 0 max: 10 scalingMetric: requestRate: targetValue: 1 scaledownPeriod: 5
hosts
(www.podinfo.com): The hostname defined in theVirtualService
to monitor for traffic.scaleTargetRef.service
(podinfo): The Kubernetes Service associated with the application deployment.scaleTargetRef.port
(9898): The port on the service to monitor.scalingMetric.requestRate.targetValue
(1): Target request rate. KEDA scales out when the rate per replica exceeds this value.
Apply the HTTPScaledObject:
kubectl apply -f httpscaledobject.yaml
You should see the HTTPScaledObject
appear in the Kedify Dashboard.
Step 5: Configure Traffic Routing
Update the VirtualService to route traffic through Kedify’s proxy:
apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata: name: podinfo namespace: defaultspec: hosts: - 'www.podinfo.com' gateways: - app http: - match: - uri: prefix: / route: - destination: host: keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local port: number: 8080
Apply the updated VirtualService:
kubectl apply -f virtualservice_through_keda.yaml
Step 6: Test Autoscaling
First, let’s verify that the application is accessible through the Gateway:
GATEWAY_IP=$(kubectl get svc -nistio-system istio-ingressgateway -o json | jq --raw-output '.status.loadBalancer.ingress[0].ip')curl -H "host: www.podinfo.com" "http://$GATEWAY_IP"
If everything is correctly configured, you should receive a successful HTTP response:
{ "hostname": "podinfo-5965fc9856-4tfpg", "version": "6.6.3", "revision": "b0c487c6b217bed8e6a53fca25f6ee1a7dd573e3", "color": "#34577c", "logo": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif", "message": "greetings from podinfo v6.6.3", "goos": "linux", "goarch": "amd64", "runtime": "go1.22.3", "num_goroutine": "8", "num_cpu": "16"}
Now, let’s simulate higher load using hey
:
hey -n 10000 -c 150 -host "www.podinfo.com" "http://$GATEWAY_IP"
After sending the load, you’ll see a response time histogram in the terminal:
Response time histogram: 0.301 [1] | 0.310 [2746] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.319 [3499] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.327 [2694] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.336 [683] |■■■■■■■■ 0.345 [99] |■ 0.354 [20] | 0.362 [1] | 0.371 [23] | 0.380 [37] | 0.389 [80] |■
In the Kedify Dashboard, you can also observe the traffic load and resulting scaling.
Network Policies
If you’re using NetworkPolicies in your cluster, you’ll need to configure them to allow traffic between Kedify’s proxy and your application. Here are example policies:
For Kedify interceptor egress:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-interceptor namespace: kedaspec: podSelector: matchLabels: app.kubernetes.io/component: interceptor app.kubernetes.io/instance: http-add-on app.kubernetes.io/part-of: keda-add-ons-http egress: - to: - namespaceSelector: matchLabels: istio-injection: enabled podSelector: matchLabels: app.kubernetes.io/name: podinfo ports: - port: 9898 policyTypes: - Egress
For application ingress:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-from-keda namespace: defaultspec: podSelector: matchLabels: app.kubernetes.io/name: podinfo ingress: - from: - namespaceSelector: matchLabels: istio-injection: enabled ports: - protocol: TCP port: 9898 policyTypes: - Ingress
Next Steps
Explore the complete HTTP Scaler documentation for more advanced configurations and details about its architecture and features, including autowiring for various ingress types.