Using Envoy Gateway for Service Access
Gateway API is the Kubernetes API for routing and load balancing. CCE provides Envoy Gateway, an Envoy-based implementation of the Gateway API. This add-on is fully compatible with the upstream Kubernetes Gateway API and supports flexible traffic routing configurations. This section describes the core capabilities and configuration methods supported by Envoy Gateway.
Precautions
- When you create a Gateway, a load balancer is automatically created based on the Envoy Gateway configuration. Automatically created load balancers are billed on a pay-per-use basis.
- After Envoy Gateway is installed, a GatewayClass named envoy-gateway is automatically created. After the add-on is uninstalled, the GatewayClass is retained. Do not manually delete it. To delete a GatewayClass after the add-on is uninstalled, manually remove its finalizers if no Gateway is associated with it. Otherwise, resources may disappear or functionality may be abnormal after the add-on is reinstalled.
- Before deleting a custom GatewayClass, ensure the Gateway associated with it is deleted.
- Uninstalling the add-on does not delete the created Gateway and its related resources (including Deployments, Services, ConfigMaps, and ServiceAccounts). Manually delete the Gateway resources managed by the add-on before uninstalling it. After the add-on is uninstalled, whether deleting a Gateway also deletes its associated resources depends on the deployment mode of the Envoy Gateway data plane. With the add-on's default configuration, deleting a Gateway will also delete its associated resources.
- In CCE standard clusters, when Envoy Gateway is bound to a dedicated load balancer, the node hosting the add-on controller pod (with the same Gateway name in the same namespace), and any other containers on that same node, cannot use the load balancer's private IP to access ingresses.
- After the add-on is configured, the associated load balancer configuration is persisted in the add-on's ConfigMap. The add-on pods use a built-in watch mechanism to monitor ConfigMap changes in real time and automatically synchronize the latest configuration. Therefore, it usually takes tens of seconds for the updated load balancing configuration to take effect.
Prerequisites
- Envoy Gateway has been installed in the current cluster and is running.
- A backend application and its Service are running in the cluster. In this example, the backend application is Nginx, the Service name is backend, and the Service port is 3000. Save the following YAML as backend.yaml and run kubectl apply -f backend.yaml:
apiVersion: apps/v1 kind: Deployment metadata: name: backend namespace: default spec: replicas: 2 selector: matchLabels: app: backend version: v1 template: metadata: labels: app: backend version: v1 spec: containers: - name: container-1 image: nginx:latest imagePullSecrets: - name: default-secret --- apiVersion: v1 kind: Service metadata: name: backend labels: app: backend version: v1 namespace: default spec: selector: app: backend version: v1 ports: - name: cce-service-0 targetPort: 80 port: 3000 protocol: TCP type: ClusterIP
Step 1: Create a Gateway
- Log in to the CCE console and click the cluster name to access the cluster console.
- In the navigation pane, choose Services and Ingresses. In the right pane, click the Gateway API tab.
- On the Gateways tab page, click Create from YAML and configure the Gateway YAML. For complete Gateway parameter definitions, see Gateway. Example:
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway # Gateway name namespace: default spec: gatewayClassName: envoy-gateway # GatewayClass name listeners: - name: http protocol: HTTP # Protocol port: 80 # Listener portIn this example, the Gateway automatically creates a load balancer based on the ELB configuration defined in the add-on, and creates an HTTP listener on port 80 for that load balancer.
- Click Submit. After the load balancer and listener are created, the Gateway status changes to Normal.

Step 2: Create an HTTPRoute
- Log in to the CCE console and click the cluster name to access the cluster console.
- In the navigation pane, choose Services and Ingresses. In the right pane, click the Gateway API tab.
- On the HTTPRoutes tab page, click Create from YAML and configure the HTTPRoute YAML. For complete HTTPRoute parameter definitions, HTTPRoute. Example:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute # The resource type is HTTPRoute. metadata: name: backend # HTTPRoute name namespace: default spec: parentRefs: - name: my-gateway # Gateway name hostnames: - "www.example.com" # Domain name rules: - backendRefs: - group: "" kind: Service name: backend # Name of the existing Service port: 3000 # Service port weight: 1In this example, HTTP traffic from the Gateway for the domain name www.example.com is routed to Service port 3000.
- Click Submit. After the HTTPRoute is created, return to the Gateways tab page and click the name of the associated Gateway. The added route is displayed.

Step 3: Test Accessibility
- View the public IP address of the load balancer associated with the Gateway.

You can also run the following command to obtain the public IP address, replacing my-gateway with the Gateway name:
kubectl get gateway/my-gateway -o jsonpath='{.status.addresses[0].value}' - Run the following command to test access, replacing xx.xx.xx.xx with the public IP address of the load balancer:
curl -I -H "Host: www.example.com" http://xx.xx.xx.xxInformation similar to the following is displayed:
HTTP/1.1 200 OK server: nginx/1.23.2 date: Thu, 28 May 2026 01:47:02 GMT content-type: text/html content-length: 615 last-modified: Wed, 19 Oct 2022 07:56:21 GMT etag: "634fada5-267" accept-ranges: bytes
More Scenarios
Adding HTTPS Access to a Gateway
- Use a certificate to create a kubernetes.io/tls secret. For details, see Creating a Secret.
In this example, a self-signed certificate is used, and the created secret is named example-cert.
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization" openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt
Use the generated certificate to create the secret.
kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt
- Add HTTPS access to the Gateway and configure the certificate. Example:
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway # Gateway name namespace: default spec: gatewayClassName: envoy-gateway # GatewayClass name listeners: - name: http protocol: HTTP # Protocol port: 80 # Listener port - name: https protocol: HTTPS # Protocol port: 443 # Listener port tls: certificateRefs: # TLS certificate - group: "" kind: Secret name: example-cert # Secret name mode: Terminate - After the load balancer and listener are automatically created, the Gateway transitions to the Normal state. Click the Gateway name to view the added HTTPS listener.

- Run the following command to test access, replacing xx.xx.xx.xx with the public IP address of the load balancer:
curl -I --cacert example.com.crt --resolve www.example.com:443:xx.xx.xx.xx https://www.example.comInformation similar to the following is displayed:
HTTP/2 200 server: nginx/1.23.2 date: Thu, 28 May 2026 02:32:57 GMT content-type: text/html content-length: 615 last-modified: Wed, 19 Oct 2022 07:56:21 GMT etag: "634fada5-267" accept-ranges: bytes
Using Path Prefix Matching in an HTTPRoute
- Update the sample application to add the /test access path.
Path matching requires that the corresponding path exists in the backend application. Otherwise, a 404 error is returned.
For example, the default Nginx access path is /usr/share/nginx/html. When using /test for prefix matching, ensure /usr/share/nginx/html/test exists in your Nginx application. Otherwise, a 404 error is returned.
The following example uses a startup command to write content to /usr/share/nginx/html/test. The response body is "This is a test."apiVersion: apps/v1 kind: Deployment metadata: name: backend namespace: default spec: replicas: 2 selector: matchLabels: app: backend version: v1 template: metadata: labels: app: backend version: v1 spec: containers: - name: container-1 image: nginx:latest command: ["/bin/sh", "-c"] args: - echo "This is a test." > /usr/share/nginx/html/test && nginx -g "daemon off;" # Add the test access path. imagePullSecrets: - name: default-secret - Update the HTTPRoute resource.
The following example configures the HTTPRoute to match the /test prefix:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute # The resource type is HTTPRoute. metadata: name: backend # HTTPRoute name namespace: default spec: parentRefs: - name: my-gateway # Gateway name hostnames: - "www.example.com" # Domain name rules: - backendRefs: - group: "" kind: Service name: backend # Name of the existing Service port: 3000 # Service port weight: 1 matches: - path: type: PathPrefix # Prefix match value: /test # Path prefix - Run the following command to test access, replacing xx.xx.xx.xx with the public IP address of the load balancer:
curl -i -H "Host: www.example.com" http://xx.xx.xx.xx/testInformation similar to the following is displayed:
HTTP/1.1 200 OK server: nginx/1.23.2 date: Thu, 28 May 2026 03:22:10 GMT content-type: application/octet-stream content-length: 16 last-modified: Thu, 28 May 2026 03:15:51 GMT etag: "6a17b367-10" accept-ranges: bytes This is a test.
Configuring Proportional Request Distribution in an HTTPRoute
In this example, an HTTPRoute is created with routing rules for backend1 and backend2, and weights are assigned to each backend.
All request traffic is distributed according to the ratio of each backend's weight to the total weight of all backends.
- Create two sample applications, backend1 and backend2. Example:
apiVersion: apps/v1 kind: Deployment metadata: name: backend1 namespace: default spec: replicas: 2 selector: matchLabels: app: backend1 version: v1 template: metadata: labels: app: backend1 version: v1 spec: containers: - name: container-1 image: nginx:latest command: ["/bin/sh", "-c"] args: - echo "This is backend1." > /usr/share/nginx/html/index.html && nginx -g "daemon off;" # By default, "This is backend1" is returned for requests to this backend. imagePullSecrets: - name: default-secret --- apiVersion: v1 kind: Service metadata: name: backend1 labels: app: backend1 version: v1 namespace: default spec: selector: app: backend1 version: v1 ports: - name: cce-service-0 targetPort: 80 port: 3000 protocol: TCP type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: backend2 namespace: default spec: replicas: 2 selector: matchLabels: app: backend2 version: v1 template: metadata: labels: app: backend2 version: v1 spec: containers: - name: container-1 image: nginx:latest command: ["/bin/sh", "-c"] args: - echo "This is backend2." > /usr/share/nginx/html/index.html && nginx -g "daemon off;" # By default, "This is backend2" is returned for requests to this backend. imagePullSecrets: - name: default-secret --- apiVersion: v1 kind: Service metadata: name: backend2 labels: app: backend2 version: v1 namespace: default spec: selector: app: backend2 version: v1 ports: - name: cce-service-0 targetPort: 80 port: 3000 protocol: TCP type: ClusterIP - Update the HTTPRoute to add routes for backend1 and backend2, and set their weights to 2 and 8, respectively.
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute # The resource type is HTTPRoute. metadata: name: backend # HTTPRoute name namespace: default spec: parentRefs: - name: my-gateway # Gateway name hostnames: - "www.example.com" # Domain name rules: - backendRefs: - group: "" kind: Service name: backend1 # Name of the existing Service port: 3000 # Service port weight: 2 # Set the weight to 2. - group: "" kind: Service name: backend2 # Name of the existing Service port: 3000 # Service port weight: 8 # Set the weight to 8. - Initiate 20 consecutive requests to test traffic distribution, replacing xx.xx.xx.xx with the public IP address of the load balancer.
for i in $(seq 1 20); do curl -sS -H "Host: www.example.com" http://xx.xx.xx.xx/; doneThe expected output shows that backend1 receives approximately 20% of traffic and backend2 receives approximately 80%.
This is backend2. This is backend2. This is backend2. This is backend1. This is backend1. This is backend2. This is backend2. This is backend2. This is backend2. This is backend2. This is backend2. This is backend2. This is backend1. This is backend2. This is backend2. This is backend2. This is backend2. This is backend1. This is backend2. This is backend2.
Forwarding Requests by Header in an HTTPRoute
Envoy Gateway supports request forwarding based on headers. In this example, the following rules are configured for demonstration:
- When the request header is x-env: test, the request is forwarded to backend1.
- When the request header is x-env: prod, the request is forwarded to backend2.
- All other requests are forwarded to the default backend.
- Create two sample applications, backend1 and backend2. Example:
apiVersion: apps/v1 kind: Deployment metadata: name: backend1 namespace: default spec: replicas: 2 selector: matchLabels: app: backend1 version: v1 template: metadata: labels: app: backend1 version: v1 spec: containers: - name: container-1 image: nginx:latest command: ["/bin/sh", "-c"] args: - echo "This is backend1." > /usr/share/nginx/html/index.html && nginx -g "daemon off;" # By default, "This is backend1" is returned for requests to this backend. imagePullSecrets: - name: default-secret --- apiVersion: v1 kind: Service metadata: name: backend1 labels: app: backend1 version: v1 namespace: default spec: selector: app: backend1 version: v1 ports: - name: cce-service-0 targetPort: 80 port: 3000 protocol: TCP type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: backend2 namespace: default spec: replicas: 2 selector: matchLabels: app: backend2 version: v1 template: metadata: labels: app: backend2 version: v1 spec: containers: - name: container-1 image: nginx:latest command: ["/bin/sh", "-c"] args: - echo "This is backend2." > /usr/share/nginx/html/index.html && nginx -g "daemon off;" # By default, "This is backend2" is returned for requests to this backend. imagePullSecrets: - name: default-secret --- apiVersion: v1 kind: Service metadata: name: backend2 labels: app: backend2 version: v1 namespace: default spec: selector: app: backend2 version: v1 ports: - name: cce-service-0 targetPort: 80 port: 3000 protocol: TCP type: ClusterIP - Update the HTTPRoute to forward requests based on headers.
Example:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend namespace: default spec: parentRefs: - name: my-gateway hostnames: - "www.example.com" rules: # Rule 1: Header x-env = test -> backend1 in the test environment - matches: - headers: - name: x-env value: test # Exact match value type: Exact # Match type. Options: Exact (default), Prefix, and RegularExpression path: type: PathPrefix value: / backendRefs: - group: "" kind: Service name: backend1 port: 3000 # Rule 2: Header x-env = prod -> backend2 in the production environment - matches: - headers: - name: x-env value: prod # Exact match value type: Exact # Match type. Options: Exact (default), Prefix, and RegularExpression path: type: PathPrefix value: / backendRefs: - group: "" kind: Service name: backend2 port: 3000 # Rule 3: Default route (when no header is matched) - matches: - path: type: PathPrefix value: / backendRefs: - group: "" kind: Service name: backend port: 3000 - Test access using the request header x-env: test.
curl -i -H "Host: www.example.com" -H "x-env: test" http://xx.xx.xx.xx/Expected output:
HTTP/1.1 200 OK server: nginx/1.23.2 date: Sat, 30 May 2026 10:09:03 GMT content-type: text/html content-length: 18 last-modified: Thu, 28 May 2026 06:49:53 GMT etag: "6a17e591-12" accept-ranges: bytes This is backend1.
The output shows that backend1 was accessed, as expected.
- Test access using the request header x-env: prod.
curl -i -H "Host: www.example.com" -H "x-env: prod" http://xx.xx.xx.xxExpected output:
HTTP/1.1 200 OK server: nginx/1.23.2 date: Sat, 30 May 2026 10:09:01 GMT content-type: text/html content-length: 18 last-modified: Thu, 28 May 2026 07:07:17 GMT etag: "6a17e9a5-12" accept-ranges: bytes This is backend2.
The output shows that backend2 was accessed, as expected.
Specifying a Single Gateway Listener for an HTTPRoute
In an HTTPRoute, you can use the sectionName or port field to bind the forwarding rule to a specific listener in the parent Gateway.
- Update the HTTPRoute resource.
In the following example, the HTTPRoute binds only to the Gateway listener named http on port 80.
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: my-route namespace: default spec: parentRefs: - name: my-gateway sectionName: http # Bind only the listener named http. port: 80 # Bind only the listener on port 80. hostnames: - "www.example.com" # Domain name rules: - backendRefs: - group: "" kind: Service name: backend # Name of the existing Service port: 3000 # Service port weight: 1- sectionName and port are optional. If they are left blank, the HTTPRoute binds to all listeners in the Gateway by default.
- sectionName="http" binds the HTTPRoute to the listener named http in the Gateway.
- port="80" binds the HTTPRoute to the listener on port 80 in the Gateway.
- sectionName="http" and port="80" together bind the HTTPRoute to the listener named http on port 80 in the Gateway.
- After the HTTPRoute is created, return to the Gateways tab page and click the associated Gateway name. The route is attached only to listener port 80.

Customizing an EnvoyProxy to Configure an Existing Load Balancer for a Gateway
- Create a custom EnvoyProxy.
- Associate with the custom EnvoyProxy.
- Method 1: Associate a GatewayClass with the EnvoyProxy.
- Create a GatewayClass.
apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: my-gateway-class spec: controllerName: gateway.envoyproxy.io/gatewayclass-controller parametersRef: group: gateway.envoyproxy.io kind: EnvoyProxy name: dev-proxy-config # Name of the created custom EnvoyProxy namespace: default # EnvoyProxy namespace - Create a Gateway.
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway # Gateway name namespace: default spec: gatewayClassName: my-gateway-class # Name of the created GatewayClass listeners: - name: http protocol: HTTP # Protocol port: 80 # Listener port - name: http-2 protocol: HTTP # Protocol port: 81 # Listener port
- Create a GatewayClass.
- Method 2: Associate a Gateway with the EnvoyProxy.
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway namespace: default spec: gatewayClassName: envoy-gateway # Name of the GatewayClass created by the add-on infrastructure: parametersRef: group: gateway.envoyproxy.io kind: EnvoyProxy name: dev-proxy-config # Name of the created custom EnvoyProxy listeners: - name: http protocol: HTTP port: 82
- Method 1: Associate a GatewayClass with the EnvoyProxy.
- Log in to the CCE console. On the Gateways tab page, verify that the load balancer associated with the new Gateway is the existing one.
If an existing load balancer is used, different Gateways cannot share the same port. Otherwise, the Gateway status will become abnormal.
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot