Docs
Ingress ControllerManage traffic and APIsTraffic ManagementProxy Requests to Weighted Backends

Proxy Requests to Weighted Backends

Configure weighted routing to distribute traffic across multiple upstream services using APISIX or API7 Ingress Controller.

Applies to:API7 Ingress Controller (drives API7 Gateway)APISIX Ingress Controller (drives Apache APISIX)

Goal

Distribute HTTP requests between two upstream services according to assigned weights using a Gateway API HTTPRoute or an APISIX CRD route.

Before you begin

  • Complete Set Up Ingress Controller and Gateway.
  • You have kubectl configured against the cluster used in the setup guide.
  • Choose a free local port for the gateway port-forward. The examples use 9080.

Set the variables this guide uses:

export UPSTREAM1_NAME="echo-1"
export UPSTREAM2_NAME="echo-2"
export UPSTREAM_PORT="80"
export UPSTREAM1_WEIGHT="1"
export UPSTREAM2_WEIGHT="4"
export REQUEST_COUNT="50"
export GATEWAY_SERVICE_NAME="apisix-gateway"   # your gateway's Service name in namespace aic
export GATEWAY_HTTP_PORT="80"
export FORWARD_PORT="9080"

Steps

Step 1: Deploy the example upstream services

Create a manifest for two http-echo services in the aic namespace:

lb-two-http-echo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-1
  namespace: aic
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo-1
  template:
    metadata:
      labels:
        app: echo-1
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo:0.2.3
        args:
          - "-text=Hello from pod $(POD_NAME) in upstream 1"
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
        ports:
          - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: echo-1
  namespace: aic
spec:
  selector:
    app: echo-1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5678
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-2
  namespace: aic
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo-2
  template:
    metadata:
      labels:
        app: echo-2
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo:0.2.3
        args:
          - "-text=Hello from pod $(POD_NAME) in upstream 2"
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
        ports:
          - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: echo-2
  namespace: aic
spec:
  selector:
    app: echo-2
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5678
  type: ClusterIP

Apply the manifest and wait for the Pods to become ready:

kubectl apply -f lb-two-http-echo.yaml
kubectl wait --for=condition=ready pod -l app=echo-1 -n aic --timeout=120s
kubectl wait --for=condition=ready pod -l app=echo-2 -n aic --timeout=120s

Step 2: Create the weighted route

Create a manifest for a route that load balances requests between the two services with the configured weights:

lb-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: lb-route
spec:
  parentRefs:
  - name: apisix
  rules:
  - matches:
    - path:
        type: Exact
        value: /
    backendRefs:
    - name: echo-1
      port: 80
      weight: 1
    - name: echo-2
      port: 80
      weight: 4

Apply the manifest:

kubectl apply -f lb-route.yaml

Validate

Forward the gateway HTTP port to your local machine:

kubectl port-forward -n aic "svc/${GATEWAY_SERVICE_NAME}" "${FORWARD_PORT}:${GATEWAY_HTTP_PORT}" &

Send REQUEST_COUNT consecutive requests and count how many are handled by each upstream:

resp=$(seq ${REQUEST_COUNT} | xargs -I{} curl "http://127.0.0.1:${FORWARD_PORT}/" -sL) && \
  count_echo1=$(echo "$resp" | grep "upstream 1" | wc -l) && \
  count_echo2=$(echo "$resp" | grep "upstream 2" | wc -l) && \
  echo "echo-1: $count_echo1, echo-2: $count_echo2"

Expected: a response similar to:

echo-1: 9, echo-2: 41

The distribution of requests across services should be close to the configured 1:${UPSTREAM2_WEIGHT} ratio. The slight deviation is due to the gateway operating with multiple workers.

Roll back / Clean up

Delete the manifests created in this guide:

kubectl delete -f lb-route.yaml
kubectl delete -f lb-two-http-echo.yaml

Stop the local port-forward process if it is still running:

kill %1 2>/dev/null || true

Troubleshoot

SymptomCauseFix
Both counts are zero.The route is not accepted, the upstream Pods are not ready, or the port-forward targets the wrong Service.Verify the HTTPRoute/ApisixRoute status, check that echo-1 and echo-2 are ready, and confirm GATEWAY_SERVICE_NAME and FORWARD_PORT.
The ratio is very different from the configured weights.The gateway has not finished loading the new route, or the test ran too few requests.Wait a few seconds and increase REQUEST_COUNT to at least 50.
curl returns 503 Service Unavailable.Both upstreams are unhealthy or the Services have no endpoints.Check the Pods with kubectl get pods -l app=echo-1 and kubectl get pods -l app=echo-2 -n aic.