All Products
Search
Document Center

Container Compute Service:Expose services through an ALB by using the Gateway API

Last Updated:Aug 08, 2025

The Gateway API is an official Kubernetes project that provides next-generation APIs for Kubernetes routing and load balancing. This topic describes how to use an Application Load Balancer (ALB) with the Gateway API to configure traffic rules and expose services outside a cluster.

Background information

The Gateway API is a collection of Kubernetes resources used to model service network traffic. Its goal is to provide an expressive, extensible, and role-oriented service network model.

ALB Ingress Controller versions 2.17.0 and later support the Gateway API. You must install the ALB Ingress Controller to expose services through an ALB using the Gateway API.

Prerequisites

  • An ACS cluster of version 1.31 or later is created.

  • The ALB Ingress Controller, version 2.17 or later, is installed in the cluster.

  • The Gateway API, version 1.3.0 or later, is installed in the cluster.

  • Two virtual switches that support ALB are created in the cluster's VPC.

Verify the environment

If your cluster meets the prerequisites, a GatewayClass resource named alb is automatically created. You can use one of the following methods to verify the resource.

Console

  1. Log on to the ACS console. In the left-side navigation pane, click Clusters.

  2. On the Clusters page, find the cluster that you want to manage and click its ID. In the left-side navigation pane of the cluster details page, choose Workloads > Custom Resources.

  3. Click gateway.networking.k8s.io and view the GatewayClass resource under v1.

    image

kubectl

kubectl get gatewayclass

Expected output:

NAME   CONTROLLER                         ACCEPTED   AGE
alb    gateways.alibabacloud.com/alb/v1   True       1m

Deploy a sample application

  1. Create an httpbin.yaml file.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: go-httpbin
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: go-httpbin
      template:
        metadata:
          labels:
            app: go-httpbin
            version: v1
        spec:
          containers:
            - image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
              args:
                - "--port=8090"
                - "--version=v1"
              imagePullPolicy: Always
              name: go-httpbin
              ports:
                - containerPort: 8090
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: go-httpbin
      namespace: default
    spec:
      type: ClusterIP 
      ports:
        - port: 80
          targetPort: 8090
          protocol: TCP
      selector:
        app: go-httpbin
  2. Deploy the application.

    kubectl apply -f httpbin.yaml

Deploy the Gateway and route

  1. Create a gateway.yaml file.

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: alb
      namespace: default
    spec:
      gatewayClassName: alb
      listeners:
        - name: http
          protocol: HTTP
          port: 80
          hostname: "*.ingress.top"
          allowedRoutes:
            namespaces:
              from: Same
    ---
    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: demo-route
    spec:
      parentRefs: # Reference the Gateway resource
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: alb
      hostnames:
        - demo.ingress.top # Set the host to demo.domain.ingress.top
      rules:
        - matches: # The matching rule is path prefix matching
            - path:
                type: PathPrefix
                value: /
          backendRefs: # The backend is a Service named go-httpbin on port 80
            - kind: Service
              name: go-httpbin
              port: 80
  2. Deploy the Gateway and routing rules.

    kubectl apply -f gateway.yaml
  3. After about 2 minutes, check the creation status of the Gateway.

    kubectl get gateway alb

    Expected output:

    NAME   CLASS   ADDRESS                                                  PROGRAMMED   AGE
    alb    alb     alb-0mwhq4ck6xxxxxxxxx.cn-hangzhou.alb.aliyuncsslb.com   True         2m12s

    The output indicates that the Gateway is created.

  4. Check the creation status of the route.

    kubectl describe httproute demo-route|grep Status -A 20

    Expected output:

    Status:
      Parents:
        Conditions:
          Last Transition Time:  2025-05-23T08:21:25Z
          Message:               Route is accepted.
          Observed Generation:   1
          Reason:                Accepted
          Status:                True
          Type:                  Accepted
          Last Transition Time:  2025-05-23T08:21:25Z
          Message:               Route is resolved.
          Observed Generation:   1
          Reason:                ResolvedRefs
          Status:                True
          Type:                  ResolvedRefs
        Controller Name:         gateways.alibabacloud.com/alb/v1
        Parent Ref:
          Group:  gateway.networking.k8s.io
          Kind:   Gateway
          Name:   alb
  5. Test access to the application.

    1. Obtain the Gateway address.

      export ALB_DOMAIN=$(kubectl get gateway alb -n default -o jsonpath='{.status.addresses[?(@.type=="Hostname")].value}')
    2. Access the application.

      curl -H "Host: demo.ingress.top" http://${ALB_DOMAIN}/version

      Expected output:

      version: v1
      hostname: go-httpbin-547xxxxxf6-xxxxx

Scenarios

Scenario 1: Use a filter to modify request headers

You can use the filter feature in HTTPRoute to perform additional processing during the request or response phase. The following example shows how to use a filter to add a request header to requests that are sent to the backend.

  1. Create an httproute-filter.yaml file.

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: demo-filter
    spec:
      parentRefs: # Reference the Gateway resource
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: alb
      hostnames:
        - filter.ingress.top # Set the host to filter.ingress.top
      rules:
        - matches: # The matching rule is path prefix matching
            - path:
                type: PathPrefix
                value: /
          filters:
            - type: RequestHeaderModifier # Add the request header my-header: foo
              requestHeaderModifier:
                add:
                  - name: my-header
                    value: foo
          backendRefs: # The backend is a Service named go-httpbin on port 80
            - kind: Service
              name: go-httpbin
              port: 80

    This file creates an HTTPRoute resource named demo-filter. After deployment, when you access the go-httpbin application using the filter.ingress.top domain name, the my-header: foo request header is automatically added to the request.

  2. Deploy the routing rule.

    kubectl apply -f httproute-filter.yaml
  3. Access the application.

    curl -H "Host: filter.ingress.top" http://${ALB_DOMAIN}/header

    Expected output:

    headers: {
        "Accept": [
          "*/*"
        ],
        "Connection": [
          "close"
        ],
        "Host": [
          "filter.ingress.top"
        ],
        "My-Header": [
          "foo"
        ],
        "Path": [
          "/header"
        ],
        "Protocol": [
          "HTTP/1.1"
        ],
        "Remoteip": [
          "118.xx.xx.91"
        ],
        "URL": [
          "/header"
        ],
        "User-Agent": [
          "curl/8.9.1"
        ]
      }
     query param: 
    , hostname: go-httpbin-547xxxxxf6-xxxxx

Scenario 2: Split traffic based on weights

You can set weights for multiple backend services to split requests based on traffic.

  1. Create an nginx.yaml file.

    Expand to view the YAML content

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: old-nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: old-nginx
      template:
        metadata:
          labels:
            run: old-nginx
        spec:
          containers:
          - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/old-nginx
            imagePullPolicy: Always
            name: old-nginx
            ports:
            - containerPort: 80
              protocol: TCP
          restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: old-nginx
    spec:
      type: ClusterIP 
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: old-nginx
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: new-nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: new-nginx
      template:
        metadata:
          labels:
            run: new-nginx
        spec:
          containers:
          - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/new-nginx
            imagePullPolicy: Always
            name: new-nginx
            ports:
            - containerPort: 80
              protocol: TCP
          restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: new-nginx
    spec:
      type: ClusterIP 
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: new-nginx

    The preceding file deploys two NGINX applications. The old-nginx service returns the "old" string, and the new-nginx service returns the "new" string. The deployed resources are placed in the default namespace.

  2. Create an httproute-weight.yaml file.

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: demo-weight
    spec:
      parentRefs: # Reference the Gateway resource
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: alb
      hostnames:
        - weight.ingress.top # Set the host to weight.ingress.top
      rules:
        - matches: # The matching rule is path prefix matching
            - path:
                type: PathPrefix
                value: /
          backendRefs:
            # Set the backends and their corresponding weights. The weights are not percentages and do not need to sum to 100.
            - kind: Service
              name: old-nginx
              port: 80
              weight: 100 # Set the weight of old-nginx to 100
            - kind: Service
              name: new-nginx
              port: 80
              weight: 100 # Set the weight of new-nginx to 100

    In this routing rule, the old-nginx and new-nginx services are assigned the same weight. Therefore, traffic is distributed to the new-nginx and old-nginx services at a 1:1 ratio.

  3. Deploy the application and routing rule.

    kubectl apply -f nginx.yaml
    kubectl apply -f httproute-weight.yaml
  4. Access the application 10 times.

    for i in {1..10}; do curl -H "Host: weight.ingress.top" http://${ALB_DOMAIN}/; done

    Expected output:

    old
    new
    new
    old
    new
    old
    old
    new
    new
    old

    The output shows that traffic is distributed to the new-nginx and old-nginx services at a 1:1 ratio.

Related operations

Configure a certificate for the application

You can configure a TLS certificate for the application on the Gateway resource.

  1. Create a self-signed certificate for the ingress.tap domain name.

    openssl req -subj '/CN=ingress.top' -new -newkey rsa:2048 -sha256 \
      -days 365 -nodes -x509 -keyout server.key -out server.crt \
      -addext "subjectAltName = DNS:ingress.top" \
      -addext "keyUsage = digitalSignature" \
      -addext "extendedKeyUsage = serverAuth" 2> /dev/null;
      openssl x509 -in server.crt -subject -noout
  2. Create a TLS Secret.

    kubectl create secret tls ingress.top --key server.key --cert server.crt
  3. Create a gateway-tls.yaml file to update the Gateway.

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: alb
      namespace: default
    spec:
      gatewayClassName: alb
      listeners:
        - name: http
          protocol: HTTP
          port: 80
          hostname: "*.ingress.top"
          allowedRoutes:
            namespaces:
              from: Same
        - name: https
          protocol: HTTPS
          port: 443
          hostname: "*.ingress.top"
          allowedRoutes:
            namespaces:
              from: Same
          tls: # Configure TLS
            mode: Terminate
            certificateRefs: # Reference the created secret
              - kind: Secret
                name: ingress.top
  4. Update the Gateway.

    gateway.gateway.networking.k8s.io/alb configured
  5. After the Programmed status of the Gateway changes to True, verify the certificate configuration.

    openssl s_client -servername ingress.top -connect ${ALB_DOMAIN}:443

    Expected output:

    CONNECTED(00000003)
    depth=0 CN = ingress.top
    verify error:num=18:self-signed certificate
    verify return:1
    depth=0 CN = ingress.top
    verify return:1
    ---
    Certificate chain
     0 s:CN = ingress.top
       i:CN = ingress.top
       a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
       v:NotBefore: Jun 24 10:49:39 2025 GMT; NotAfter: Jun 24 10:49:39 2026 GMT
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    ...
    ...
    ...
    -----END CERTIFICATE-----
    subject=CN = ingress.top
    issuer=CN = ingress.top
    ---
    No client certificate CA names sent
    Peer signing digest: SHA256
    Peer signature type: RSA-PSS
    Server Temp Key: X25519, 253 bits
    ---
    SSL handshake has read 1506 bytes and written 410 bytes
    Verification error: self-signed certificate
    ---
    New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
    Server public key is 2048 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    No ALPN negotiated
    SSL-Session:
        Protocol  : TLSv1.2
        Cipher    : ECDHE-RSA-AES128-GCM-SHA256
        Session-ID: xxxxxxxxxxxxxxxxxxxxxxxxx
        Session-ID-ctx: 
        Master-Key: xxxxxxxxxxxxxxxxxxxxxxxxxxx
        PSK identity: None
        PSK identity hint: None
        SRP username: None
        TLS session ticket lifetime hint: 300 (seconds)
        TLS session ticket:
        ...
        ...
        ...
    
        Start Time: 1750820008
        Timeout   : 7200 (sec)
        Verify return code: 18 (self-signed certificate)
        Extended master secret: yes
    ---

    The output indicates that the certificate is configured and active.

    Note

    You can run curl -H "Host: demo.ingress.top" -k https://${ALB_DOMAIN}/version to access the application. The expected output is the same as the output in the Test access to the application step.