Skip to content

add net-gateway-api ingress support#2251

Open
kahirokunn wants to merge 1 commit intoknative:mainfrom
kahirokunn:add-gateway-api-ingress-support
Open

add net-gateway-api ingress support#2251
kahirokunn wants to merge 1 commit intoknative:mainfrom
kahirokunn:add-gateway-api-ingress-support

Conversation

@kahirokunn
Copy link
Member

@kahirokunn kahirokunn commented Mar 8, 2026

/lint

Fixes #1285

Proposed Changes

  • Add Gateway API (net-gateway-api) as a new ingress provider option.

Usage

apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
  name: knative-serving
  namespace: knative-serving
spec:
  ingress:
    gateway-api:
      enabled: true

The config-gateway ConfigMap can be customized via spec.config["config-gateway"] to configure external/local gateways for your environment.

End-to-End Walkthrough: Envoy Gateway Integration

Below is a complete guide to running Knative Services using this PR's net-gateway-api support with Envoy Gateway as the Gateway API implementation.

Prerequisites

go install sigs.k8s.io/cloud-provider-kind@latest

1. Create a kind Cluster

kind create cluster

2. Install Envoy Gateway

Install Envoy Gateway via Helm. We use GatewayNamespace mode so that Envoy is deployed in a separate namespace for each Gateway.

cat <<'EOF' > /tmp/values-eg.yaml
config:
  envoyGateway:
    provider:
      type: Kubernetes
      kubernetes:
        deploy:
          type: GatewayNamespace
EOF

export ENVOY_GATEWAY_VERSION=v1.7.0
helm install eg oci://docker.io/envoyproxy/gateway-helm \
  --version $ENVOY_GATEWAY_VERSION \
  -n envoy-gateway-system --create-namespace \
  -f /tmp/values-eg.yaml

After installing Envoy Gateway, start cloud-provider-kind in a separate terminal:

sudo cloud-provider-kind

3. Create Gateway API Resources

Create GatewayClass and Gateway resources for both external traffic and internal (cluster-local) traffic.

External

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: eg-external
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: knative-external-config
  namespace: envoy-gateway-system
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyService:
        name: knative-external
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg-external
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: knative-external-config
    namespace: envoy-gateway-system
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg-external
  namespace: eg-external
spec:
  gatewayClassName: eg-external
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
  - name: tls
    port: 443
    protocol: TLS
    tls:
      mode: Passthrough
    allowedRoutes:
      namespaces:
        from: All
EOF

Internal

The internal Gateway uses the ClusterIP service type, so it is not accessible from outside the cluster.

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: eg-internal
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: knative-internal-config
  namespace: envoy-gateway-system
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyService:
        type: ClusterIP
        name: knative-internal
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg-internal
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: knative-internal-config
    namespace: envoy-gateway-system
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg-internal
  namespace: eg-internal
spec:
  gatewayClassName: eg-internal
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
EOF

4. Build and Install the Knative Operator

Build and deploy the Operator locally, including the changes from this PR.

cd /path/to/knative/operator

export KO_DOCKER_REPO=kind.local
ko apply -f config/

5. Apply the KnativeServing CR

This is where the Operator really shines. A single CR lets you declaratively manage the Knative Serving installation, enable Gateway API, and configure config-gateway, config-network, and config-domain all in one place.

kubectl create ns knative-serving

cat <<'EOF' | kubectl apply -f -
apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
  name: knative-serving
  namespace: knative-serving
spec:
  ingress:
    gateway-api:
      enabled: true
  config:
    config-gateway:
      external-gateways: |
        - class: eg-external
          gateway: eg-external/eg-external
          service: eg-external/knative-external
          supported-features:
          - HTTPRouteRequestTimeout
      local-gateways: |
        - class: eg-internal
          gateway: eg-internal/eg-internal
          service: eg-internal/knative-internal
          supported-features:
          - HTTPRouteRequestTimeout
    network:
      ingress.class: gateway-api.ingress.networking.knative.dev
    domain:
      example.com: ""
EOF

6. Deploy a Sample Application

cat <<'EOF' | kubectl apply -f -
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: Go Sample v1
EOF

7. Verify It Works

Get the LoadBalancer IP of the external Gateway and send a request:

export LB_IP=$(kubectl -n eg-external get svc knative-external \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

echo "$LB_IP helloworld-go.default.example.com" | sudo tee -a /etc/hosts

curl http://helloworld-go.default.example.com
Hello Go Sample v1!

Release Note

Add support for Gateway API (net-gateway-api) as an ingress provider. Users can enable it by setting `spec.ingress.gateway-api.enabled: true` in the KnativeServing CR.

Manual testing

It is functioning normally when verified locally.

CleanShot 2026-03-08 at 22 40 53@2x

@knative-prow knative-prow bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Mar 8, 2026
@knative-prow knative-prow bot requested review from aliok and matzew March 8, 2026 13:38
@knative-prow
Copy link

knative-prow bot commented Mar 8, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: kahirokunn
Once this PR has been reviewed and has the lgtm label, please assign matzew for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

@knative-prow knative-prow bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kahirokunn: 0 warnings.

Details

In response to this:

/lint

Fixes #1285

Proposed Changes

  • Add Gateway API (net-gateway-api) as a new ingress provider option.

Usage

apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
 name: knative-serving
 namespace: knative-serving
spec:
 ingress:
   gateway-api:
     enabled: true

The config-gateway ConfigMap can be customized via spec.config["config-gateway"] to configure external/local gateways for your environment.

End-to-End Walkthrough: Envoy Gateway Integration

Below is a complete guide to running Knative Services using this PR's net-gateway-api support with Envoy Gateway as the Gateway API implementation.

Prerequisites

go install sigs.k8s.io/cloud-provider-kind@latest

1. Create a kind Cluster

kind create cluster

2. Install Envoy Gateway

Install Envoy Gateway via Helm. We use GatewayNamespace mode so that Envoy is deployed in a separate namespace for each Gateway.

cat <<'EOF' > /tmp/values-eg.yaml
config:
 envoyGateway:
   provider:
     type: Kubernetes
     kubernetes:
       deploy:
         type: GatewayNamespace
EOF

export ENVOY_GATEWAY_VERSION=v1.7.0
helm install eg oci://docker.io/envoyproxy/gateway-helm \
 --version $ENVOY_GATEWAY_VERSION \
 -n envoy-gateway-system --create-namespace \
 -f /tmp/values-eg.yaml

After installing Envoy Gateway, start cloud-provider-kind in a separate terminal:

sudo cloud-provider-kind

3. Create Gateway API Resources

Create GatewayClass and Gateway resources for both external traffic and internal (cluster-local) traffic.

External

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
 name: eg-external
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
 name: knative-external-config
 namespace: envoy-gateway-system
spec:
 provider:
   type: Kubernetes
   kubernetes:
     envoyService:
       name: knative-external
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
 name: eg-external
spec:
 controllerName: gateway.envoyproxy.io/gatewayclass-controller
 parametersRef:
   group: gateway.envoyproxy.io
   kind: EnvoyProxy
   name: knative-external-config
   namespace: envoy-gateway-system
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
 name: eg-external
 namespace: eg-external
spec:
 gatewayClassName: eg-external
 listeners:
 - name: http
   port: 80
   protocol: HTTP
   allowedRoutes:
     namespaces:
       from: All
 - name: tls
   port: 443
   protocol: TLS
   tls:
     mode: Passthrough
   allowedRoutes:
     namespaces:
       from: All
EOF

Internal

The internal Gateway uses the ClusterIP service type, so it is not accessible from outside the cluster.

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
 name: eg-internal
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
 name: knative-internal-config
 namespace: envoy-gateway-system
spec:
 provider:
   type: Kubernetes
   kubernetes:
     envoyService:
       type: ClusterIP
       name: knative-internal
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
 name: eg-internal
spec:
 controllerName: gateway.envoyproxy.io/gatewayclass-controller
 parametersRef:
   group: gateway.envoyproxy.io
   kind: EnvoyProxy
   name: knative-internal-config
   namespace: envoy-gateway-system
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
 name: eg-internal
 namespace: eg-internal
spec:
 gatewayClassName: eg-internal
 listeners:
 - name: http
   port: 80
   protocol: HTTP
   allowedRoutes:
     namespaces:
       from: All
EOF

4. Build and Install the Knative Operator

Build and deploy the Operator locally, including the changes from this PR.

cd /path/to/knative/operator

export KO_DOCKER_REPO=kind.local
ko apply -f config/

5. Apply the KnativeServing CR

This is where the Operator really shines. A single CR lets you declaratively manage the Knative Serving installation, enable Gateway API, and configure config-gateway, config-network, and config-domain all in one place.

apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
 name: knative-serving
 namespace: knative-serving
spec:
 ingress:
   gateway-api:
     enabled: true
 config:
   config-gateway:
     external-gateways: |
       - class: eg-external
         gateway: eg-external/eg-external
         service: eg-external/knative-external
         supported-features:
         - HTTPRouteRequestTimeout
     local-gateways: |
       - class: eg-internal
         gateway: eg-internal/eg-internal
         service: eg-internal/knative-internal
         supported-features:
         - HTTPRouteRequestTimeout
   network:
     ingress.class: gateway-api.ingress.networking.knative.dev
   domain:
     example.com: ""

6. Deploy a Sample Application

cat <<'EOF' | kubectl apply -f -
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
 name: helloworld-go
spec:
 template:
   spec:
     containers:
     - image: gcr.io/knative-samples/helloworld-go
       env:
       - name: TARGET
         value: Go Sample v1
EOF

7. Verify It Works

Get the LoadBalancer IP of the external Gateway and send a request:

export LB_IP=$(kubectl -n eg-external get svc knative-external \
 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

echo "$LB_IP helloworld-go.default.example.com" | sudo tee -a /etc/hosts

curl http://helloworld-go.default.example.com
Hello Go Sample v1!

Release Note

Add support for Gateway API (net-gateway-api) as an ingress provider. Users can enable it by setting `spec.ingress.gateway-api.enabled: true` in the KnativeServing CR.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@codecov
Copy link

codecov bot commented Mar 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.58%. Comparing base (274b7dc) to head (18f5aaa).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2251      +/-   ##
==========================================
+ Coverage   63.45%   63.58%   +0.13%     
==========================================
  Files          49       50       +1     
  Lines        1899     1906       +7     
==========================================
+ Hits         1205     1212       +7     
  Misses        600      600              
  Partials       94       94              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@kahirokunn kahirokunn force-pushed the add-gateway-api-ingress-support branch 2 times, most recently from c25d418 to ec92622 Compare March 8, 2026 14:05
@kahirokunn
Copy link
Member Author

kahirokunn commented Mar 8, 2026

I also prepared a walkthrough for a Shared Gateway pattern (single Gateway for both external and cluster-local traffic) as a simpler alternative. If it's helpful, feel free to reference it.

1. Create a kind Cluster

kind create cluster

2. Install Envoy Gateway

Install Envoy Gateway via Helm. We use GatewayNamespace mode so that Envoy is deployed in the Gateway's namespace, separate from the control plane.

cat <<'EOF' > /tmp/values-eg.yaml
config:
  envoyGateway:
    provider:
      type: Kubernetes
      kubernetes:
        deploy:
          type: GatewayNamespace
EOF

export ENVOY_GATEWAY_VERSION=v1.7.0
helm upgrade --install eg oci://docker.io/envoyproxy/gateway-helm \
  --version $ENVOY_GATEWAY_VERSION \
  -n envoy-gateway-system --create-namespace \
  -f /tmp/values-eg.yaml

After installing Envoy Gateway, start cloud-provider-kind in a separate terminal:

sudo cloud-provider-kind

3. Create Gateway API Resources

Create a single set of GatewayClass and Gateway resources that handle both external and cluster-local traffic.

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: eg
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: envoy-gateway-config
  namespace: envoy-gateway-system
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyService:
        name: eg
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: envoy-gateway-config
    namespace: envoy-gateway-system
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg
  namespace: eg
spec:
  gatewayClassName: envoy-gateway
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
  - name: tls
    port: 443
    protocol: TLS
    tls:
      mode: Passthrough
    allowedRoutes:
      namespaces:
        from: All
EOF

Note: External and cluster-local traffic share the same Gateway. Isolation is handled at the HTTPRoute level — cluster-local services use internal domain names (e.g., *.svc.cluster.local) that are not resolvable from outside the cluster.

4. Build and Install the Knative Operator

Build and deploy the Operator locally, including the changes from this PR.

cd /path/to/knative/operator

export KO_DOCKER_REPO=kind.local
ko apply -f config/

5. Apply the KnativeServing CR

A single CR lets you declaratively manage the Knative Serving installation, enable Gateway API, and configure config-gateway, config-network, and config-domain all in one place.

kubectl create ns knative-serving

cat <<'EOF' | kubectl apply -f -
apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
  name: knative-serving
  namespace: knative-serving
spec:
  ingress:
    gateway-api:
      enabled: true
  config:
    config-gateway:
      external-gateways: |
        - class: envoy-gateway
          gateway: eg/eg
          service: eg/eg
          supported-features:
          - HTTPRouteRequestTimeout
      local-gateways: |
        - class: envoy-gateway
          gateway: eg/eg
          service: eg/eg
          supported-features:
          - HTTPRouteRequestTimeout
    network:
      ingress.class: gateway-api.ingress.networking.knative.dev
    domain:
      example.com: ""
EOF

6. Deploy a Sample Application

cat <<'EOF' | kubectl apply -f -
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    spec:
      containers:
      - image: gcr.io/knative-samples/helloworld-go
        env:
        - name: TARGET
          value: Go Sample v1
EOF

7. Verify It Works

Get the LoadBalancer IP of the Gateway and send a request:

export LB_IP=$(kubectl -n eg get svc eg \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

echo "$LB_IP helloworld-go.default.example.com" | sudo tee -a /etc/hosts

curl http://helloworld-go.default.example.com
Hello Go Sample v1!

You can also verify from inside the cluster using a curl container:

kubectl run curl --rm -it --image=curlimages/curl --restart=Never -- \
  curl -H "Host: helloworld-go.default.example.com" http://eg.eg.svc.cluster.local
Hello Go Sample v1!

Signed-off-by: kahirokunn <okinakahiro@gmail.com>
@dprotaso
Copy link
Member

/assign @dprotaso @houshengbo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support net-gateway-api

3 participants