diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/_index.md b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/_index.md new file mode 100644 index 0000000000..901aa77c37 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/_index.md @@ -0,0 +1,59 @@ +--- +title: Autoscaling HTTP applications on Kubernetes + +draft: true +cascade: + draft: true + +minutes_to_complete: 45 + +who_is_this_for: > + Developers and SREs running HTTP-based workloads on Kubernetes who want to enable intelligent, event-driven autoscaling. + +learning_objectives: + - Install Kedify (KEDA build, HTTP Scaler, and Kedify Agent) via Helm + - Verify that the components are running in your cluster + - Deploy a sample HTTP application and test autoscaling behavior + +prerequisites: + - A running Kubernetes cluster (local or cloud) + - kubectl and helm installed locally + - Access to the Kedify Service dashboard (https://dashboard.kedify.io/) to obtain Organization ID and API Key — log in or create an account if you don’t have one + +author: Zbynek Roubalik + +### Tags +skilllevels: Introductory +subjects: Containers and Virtualization +cloud_service_providers: Any +armips: + - Neoverse +operatingsystems: + - Linux +tools_software_languages: + - Kubernetes + - Helm + - KEDA + - Kedify + +further_reading: + - resource: + title: Kedify HTTP Scaler + link: https://kedify.io/scalers/http + type: documentation + - resource: + title: Kedify documentation + link: https://docs.kedify.io + type: documentation + - resource: + title: KEDA project + link: https://keda.sh/ + type: documentation + + +### FIXED, DO NOT MODIFY +# ============================================================================= +weight: 1 # _index.md always has weight of 1 to order correctly +layout: "learningpathall" # All files under learning paths have this same wrapper +learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content. +--- diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/_next-steps.md b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/_next-steps.md new file mode 100644 index 0000000000..52222c2fa7 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/_next-steps.md @@ -0,0 +1,8 @@ +--- +# ============================================================================= +# FIXED, DO NOT MODIFY THIS FILE +# ============================================================================= +weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation. +title: "Next Steps" # Always the same, html page title. +layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing. +--- diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/http-scaling.md b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/http-scaling.md new file mode 100644 index 0000000000..1bb91db087 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/http-scaling.md @@ -0,0 +1,281 @@ +--- +title: "HTTP Scaling for Ingress-Based Applications" +weight: 4 +layout: "learningpathall" +--- + +Use this section to get a quick, hands-on feel for Kedify HTTP autoscaling. We’ll deploy a small web service, expose it through a standard Kubernetes Ingress, and rely on Kedify’s autowiring to route traffic via its proxy so requests are measured and drive scaling. + +Scale a real HTTP app exposed through Kubernetes Ingress using Kedify’s [kedify-http](https://docs.kedify.io/scalers/http-scaler/) scaler. You will deploy a simple app, enable autoscaling with a [ScaledObject](https://keda.sh/docs/latest/concepts/scaling-deployments/), generate load, and observe the system scale out and back in (including scale-to-zero when idle). + +## How it works + +With ingress autowiring enabled, Kedify automatically routes traffic through its proxy before it reaches your Service/Deployment: + +``` +Ingress → kedify-proxy → Service → Deployment +``` + +The [Kedify Proxy](https://docs.kedify.io/scalers/http-scaler/#kedify-proxy) gathers request metrics used by the scaler to make decisions. + +## What you’ll deploy + +- Deployment & Service: an HTTP server with a small response delay to simulate work +- Ingress: public entry using host `application.keda` +- ScaledObject: Kedify HTTP scaler with `trafficAutowire: ingress` + +## Step 0 — Set up Ingress IP environment variable + +Before testing the application, ensure you have the `INGRESS_IP` environment variable set with your ingress controller's external IP or hostname. + +If you followed the [Install Ingress Controller](../install-ingress/) guide, you should already have this set. If not, or if you're using an existing ingress controller, run this command: + +```bash +export INGRESS_IP=$(kubectl get service ingress-nginx-controller --namespace=ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}') +echo "Ingress IP/Hostname: $INGRESS_IP" +``` +You should now have the correct IP address or hostname stored in the `$INGRESS_IP` environment variable. If the command doesn't print any value, please repeat it after some time. + +{{% notice Note %}} +If your ingress controller service has a different name or namespace, adjust the command accordingly. For example, some installations use `nginx-ingress-controller` or place it in a different namespace. +{{% /notice %}} + +## Step 1 — Create the application and Ingress + +Let's start with deploying an application that responds to an incoming HTTP server and is exposed via Ingress. You can check the source code of the application on [GitHub](https://github.com/kedify/examples/tree/main/samples/http-server). + +#### Deploy the application + +Run the following command to deploy our application: + +```bash +cat <<'EOF' | kubectl apply -f - +apiVersion: apps/v1 +kind: Deployment +metadata: + name: application +spec: + replicas: 1 + selector: + matchLabels: + app: application + template: + metadata: + labels: + app: application + spec: + nodeSelector: + kubernetes.io/arch: arm64 + tolerations: + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoSchedule" + containers: + - name: application + image: ghcr.io/kedify/sample-http-server:latest + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + - name: RESPONSE_DELAY + value: "0.3" +--- +apiVersion: v1 +kind: Service +metadata: + name: application-service +spec: + ports: + - name: http + protocol: TCP + port: 8080 + targetPort: http + selector: + app: application + type: ClusterIP +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: application-ingress +spec: + ingressClassName: nginx + rules: + - host: application.keda + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: application-service + port: + number: 8080 +EOF +``` + +Notes: +- `RESPONSE_DELAY` adds ~300ms latency per request, making scaling effects easier to see. +- The Ingress uses host `application.keda`. To access this app we will use your ingress controller’s IP with a `Host:` header (shown below). + +#### Verify the application is running correctly + +Let's check that we have 1 replica of the application deployed and ready: + +```bash +kubectl get deployment application +``` + +In the output we should see 1 replica ready: +``` +NAME READY UP-TO-DATE AVAILABLE AGE +application 1/1 1 1 3m44s +``` + +#### Test the application +Hit the app to confirm the app is ready and routing works: + +```bash +curl -I -H "Host: application.keda" http://$INGRESS_IP +``` + +You should see similar output: +``` +HTTP/1.1 200 OK +Date: Thu, 11 Sep 2025 14:11:24 GMT +Content-Type: text/html +Content-Length: 301 +Connection: keep-alive +``` + +## Step 2 — Enable autoscaling with Kedify + +The application is currectly running, Now we will enable autoscaling on this app, we will scale from 0 to 10 replicas. No request shall be lost at any moment. To do that, please run the following command to deploy our `ScaledObject`: + +```bash +cat <<'EOF' | kubectl apply -f - +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: application +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: application + cooldownPeriod: 5 + minReplicaCount: 0 + maxReplicaCount: 10 + fallback: + failureThreshold: 2 + replicas: 1 + advanced: + restoreToOriginalReplicaCount: true + horizontalPodAutoscalerConfig: + behavior: + scaleDown: + stabilizationWindowSeconds: 5 + triggers: + - type: kedify-http + metadata: + hosts: application.keda + pathPrefixes: / + service: application-service + port: "8080" + scalingMetric: requestRate + targetValue: "10" + granularity: 1s + window: 10s + trafficAutowire: ingress +EOF +``` + +What the key fields do: +- `type: kedify-http` — Use Kedify’s HTTP scaler. +- `hosts`, `pathPrefixes` — Which requests to observe for scaling. +- `service`, `port` — The Service and port receiving traffic. +- `scalingMetric: requestRate` and `targetValue: 10` — Target 1000 req/s (per granularity/window) before scaling out. +- `minReplicaCount: 0` — Allows scale-to-zero when idle. +- `trafficAutowire: ingress` — Lets Kedify auto-wire your Ingress to the kedify-proxy. + +After applying, the ScaledObject will appear in the Kedify dashboard (https://dashboard.kedify.io/). + +![Kedify Dashboard With ScaledObject](images/scaledobject.png) + +## Step 3 — Send traffic and observe scaling + +Becuase we are not sending any traffic to our application, after some time, it should be scaled to zero. + +#### Verify scale to zero + +Run this command and wait until there is 0 replicas: + +```bash +watch kubectl get deployment application -n default +``` + +You should see similar output: +```bash +Every 2,0s: kubectl get deployment application -n default + +NAME READY UP-TO-DATE AVAILABLE AGE +application 0/0 0 0 110s +``` + +#### Verify the app can scale from zero + +Now, hit the app again, it should be scaled to 1 replica and return back correct response: +```bash +curl -I -H "Host: application.keda" http://$INGRESS_IP +``` + +You should see a 200 OK response. Next, generate sustained load. You can use `hey` (or a similar tool): + +#### Test higher load + +```bash +hey -n 40000 -c 200 -host "application.keda" http://$INGRESS_IP +``` + +While the load runs, watch replicas change: + +```bash +watch kubectl get deployment application -n default +``` + +For example something like this: + +``` +Every 2,0s: kubectl get deployment application -n default + +NAME READY UP-TO-DATE AVAILABLE AGE +application 5/5 5 5 23m +``` + +Expected behavior: +- On bursty load, Kedify scales the Deployment up toward `maxReplicaCount`. +- When traffic subsides, replicas scale down. After the cooldown, they can return to zero. + +You can also observe traffic and scaling in the Kedify dashboard: + +![Kedify Dashboard ScaledObject Detail](images/load.png) + +## Clean up + +```bash +kubectl delete scaledobject application +kubectl delete ingress application-ingress +kubectl delete service application-service +kubectl delete deployment application +``` + +## Next steps + +Explore the official Kedify [How-to guides](https://docs.kedify.io/how-to/) for more configurations such as Gateway API, Istio VirtualService, or OpenShift Routes. + +### See also + +- Kedify documentation: https://docs.kedify.io diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/images/load.png b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/images/load.png new file mode 100644 index 0000000000..c51d0b92dd Binary files /dev/null and b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/images/load.png differ diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/images/scaledobject.png b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/images/scaledobject.png new file mode 100644 index 0000000000..ab63711abe Binary files /dev/null and b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/images/scaledobject.png differ diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/install-ingress.md b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/install-ingress.md new file mode 100644 index 0000000000..2782610599 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/install-ingress.md @@ -0,0 +1,93 @@ +--- +title: "Install Ingress Controller" +weight: 3 +layout: "learningpathall" +--- + +Before deploying HTTP applications with Kedify autoscaling, you need an Ingress Controller to handle incoming traffic. Most major cloud providers (AWS EKS, Google GKE, Azure AKS) do not include an Ingress Controller by default in their managed Kubernetes offerings. + +{{% notice Note %}} +If your cluster already has an Ingress Controller installed and configured, you can skip this step and proceed directly to the [HTTP Scaling guide](../http-scaling/). +{{% /notice %}} + +## Install NGINX Ingress Controller via Helm + +Add the NGINX Ingress Controller Helm repository: + +```bash +helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx +helm repo update +``` + +Install the NGINX Ingress Controller: + +```bash +helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \ + --namespace ingress-nginx \ + --create-namespace \ + \ + --set "controller.nodeSelector.kubernetes\.io/arch=arm64" \ + --set "controller.tolerations[0].key=kubernetes.io/arch" \ + --set "controller.tolerations[0].operator=Equal" \ + --set "controller.tolerations[0].value=arm64" \ + --set "controller.tolerations[0].effect=NoSchedule" \ + \ + --set "controller.admissionWebhooks.patch.nodeSelector.kubernetes\.io/arch=arm64" \ + --set "controller.admissionWebhooks.patch.tolerations[0].key=kubernetes.io/arch" \ + --set "controller.admissionWebhooks.patch.tolerations[0].operator=Equal" \ + --set "controller.admissionWebhooks.patch.tolerations[0].value=arm64" \ + --set "controller.admissionWebhooks.patch.tolerations[0].effect=NoSchedule" +``` + +Wait for the LoadBalancer to be ready: + +```bash +kubectl wait --namespace ingress-nginx \ + --for=condition=ready pod \ + --selector=app.kubernetes.io/component=controller \ + --timeout=300s +``` + +## Get the External Endpoint + +Get the external IP address or hostname for your ingress controller and save it as an environment variable: + +```bash +export INGRESS_IP=$(kubectl get service ingress-nginx-controller --namespace=ingress-nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}') +echo "Ingress IP/Hostname: $INGRESS_IP" +``` + +This will save the external IP or hostname in the `INGRESS_IP` environment variable and display it. If the command doesn't print any value, please repeat it after some time. Please note the value: +- **AWS EKS**: You'll see an AWS LoadBalancer hostname (e.g., `a1234567890abcdef-123456789.us-west-2.elb.amazonaws.com`) +- **Google GKE**: You'll see an IP address (e.g., `34.102.136.180`) +- **Azure AKS**: You'll see an IP address (e.g., `20.62.196.123`) + +## Configure Access + +For this tutorial, you have two options: + +### Option 1: DNS Setup (Recommended for production) +Point `application.keda` to your ingress controller's external IP/hostname using your DNS provider. + +### Option 2: Host Header (Quick setup) +Use the external IP/hostname directly with a `Host:` header in your requests. When testing, you'll use: + +```bash +curl -H "Host: application.keda" http://$INGRESS_IP +``` + +The `$INGRESS_IP` environment variable contains the actual external IP or hostname from your ingress controller service. + +## Verification + +Test that the ingress controller is working by checking its readiness: + +```bash +kubectl get pods --namespace ingress-nginx +``` + +You should see the `ingress-nginx-controller` pod in `Running` status. + +## Next Steps + +Now that you have an Ingress Controller installed and configured, proceed to the [HTTP Scaling guide](../http-scaling/) to deploy an application and configure Kedify autoscaling. diff --git a/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/install-kedify-helm.md b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/install-kedify-helm.md new file mode 100644 index 0000000000..1a79f07306 --- /dev/null +++ b/content/learning-paths/servers-and-cloud-computing/kedify-http-autoscaling/install-kedify-helm.md @@ -0,0 +1,120 @@ +--- +title: "Install Kedify via Helm" +weight: 2 +layout: "learningpathall" +--- + +This page installs Kedify on your cluster using Helm. You’ll add the Kedify chart repo, install KEDA (Kedify build), the HTTP Scaler, and the Kedify Agent, then verify everything is running. + +For more details and all installation methods, see Kedify installation docs: https://docs.kedify.io/installation/helm#installation-on-arm + +## Prerequisites + +- A running Kubernetes cluster (kind, minikube, EKS, GKE, AKS, etc.) +- kubectl and helm installed and configured to talk to your cluster +- Kedify Service account (https://dashboard.kedify.io/) to obtain Organization ID and API Key — log in or create an account if you don’t have one + +## Prepare installation + +1) Get your Organization ID: In the Kedify dashboard (https://dashboard.kedify.io/) go to Organization -> Details and copy the ID. + +2) Get your API key: +- If you already have a Kedify Agent deployed, you can retrieve it from the existing Secret: + +```bash +kubectl get secret -n keda kedify-agent -o=jsonpath='{.data.apikey}' | base64 --decode +``` + +- Otherwise, in the Kedify dashboard (https://dashboard.kedify.io/) go to Organization -> API Keys, click Create Agent Key, and copy the key. + +Note: The API Key is shared across all your Agent installations. If you regenerate it, update existing Agent installs and keep it secret. + +## Helm repository + +Add the Kedify Helm repository and update your local index: + +```bash +helm repo add kedifykeda https://kedify.github.io/charts +helm repo update +``` + +## Helm installation + +Most providers like AWS EKS and Azure AKS automatically place pods on ARM nodes when you specify `nodeSelector` for `kubernetes.io/arch=arm64`. However, Google Kubernetes Engine (GKE) applies an explicit taint on ARM nodes, requiring matching `tolerations`. + +To ensure a portable deployment strategy across all cloud providers, we recommend configuring both `nodeSelector` and `tolerations` in your Helm values or CLI flags. + +Install each component into the keda namespace. Replace placeholders where noted. + +1) Install Kedify build of KEDA: + +```bash +helm upgrade --install keda kedifykeda/keda \ + --namespace keda \ + --create-namespace \ + --devel \ + --set "nodeSelector.kubernetes\.io/arch=arm64" \ + --set "tolerations[0].key=kubernetes.io/arch" \ + --set "tolerations[0].operator=Equal" \ + --set "tolerations[0].value=arm64" \ + --set "tolerations[0].effect=NoSchedule" +``` + +2) Install Kedify HTTP Scaler: + +```bash +helm upgrade --install keda-add-ons-http kedifykeda/keda-add-ons-http \ + --namespace keda \ + --devel \ + --set "interceptor.nodeSelector.kubernetes\.io/arch=arm64" \ + --set "interceptor.tolerations[0].key=kubernetes.io/arch" \ + --set "interceptor.tolerations[0].operator=Equal" \ + --set "interceptor.tolerations[0].value=arm64" \ + --set "interceptor.tolerations[0].effect=NoSchedule" \ + --set "scaler.nodeSelector.kubernetes\.io/arch=arm64" \ + --set "scaler.tolerations[0].key=kubernetes.io/arch" \ + --set "scaler.tolerations[0].operator=Equal" \ + --set "scaler.tolerations[0].value=arm64" \ + --set "scaler.tolerations[0].effect=NoSchedule" +``` + +3) Install Kedify Agent (edit clusterName, orgId, apiKey): + +```bash +helm upgrade --install kedify-agent kedifykeda/kedify-agent \ + --namespace keda \ + --set "agent.nodeSelector.kubernetes\.io/arch=arm64" \ + --set "agent.tolerations[0].key=kubernetes.io/arch" \ + --set "agent.tolerations[0].operator=Equal" \ + --set "agent.tolerations[0].value=arm64" \ + --set "agent.tolerations[0].effect=NoSchedule" \ + --set "agent.kedifyProxy.globalValues.nodeSelector.kubernetes\.io/arch=arm64" \ + --set "agent.kedifyProxy.globalValues.tolerations[0].key=kubernetes.io/arch" \ + --set "agent.kedifyProxy.globalValues.tolerations[0].operator=Equal" \ + --set "agent.kedifyProxy.globalValues.tolerations[0].value=arm64" \ + --set "agent.kedifyProxy.globalValues.tolerations[0].effect=NoSchedule" \ + \ + --set clusterName="my-arm-cluster" \ + --set agent.orgId="$YOUR_ORG_ID" \ + --set agent.apiKey="$YOUR_API_KEY" +``` + +## Verify installation + +```bash +kubectl get pods -n keda +``` + +Expected example (names may differ): + +```text +NAME READY STATUS RESTARTS AGE +keda-add-ons-http-external-scaler-xxxxx 1/1 Running 0 1m +keda-add-ons-http-interceptor-xxxxx 1/1 Running 0 1m +keda-admission-webhooks-xxxxx 1/1 Running 0 1m +keda-operator-xxxxx 1/1 Running 0 1m +keda-operator-metrics-apiserver-xxxxx 1/1 Running 0 1m +kedify-agent-xxxxx 1/1 Running 0 1m +``` + +Proceed to the next section to deploy a sample HTTP app and test autoscaling.