TCPRoute

Standard Channel since v1.6.0
The TCPRoute resource is GA and has been part of the Standard Channel since v1.6.0. For more information on release channels, refer to our versioning guide.

TCPRoute is a Gateway API type for routing TCP traffic from a Gateway listener to a backend, i.e. Service. When combined with a Gateway listener, it forwards connections arriving on the listener’s port to the backends specified in the route.

TCPRoute is intentionally minimal. TCP carries no application-layer metadata that the Gateway can match on, so traffic is classified only by the listener’s protocol:port. As a result, TCPRoute has no hostnames, matches, or filters, and a rule consists only of the backends to forward traffic to.

Background

While many routing cases can be handled at L7 with HTTPRoute or GRPCRoute, and TLS traffic can be routed by Server Name Indication (SNI) with TLSRoute, a large class of workloads speak plain TCP that fits none of those models. Common examples include:

  • Databases (e.g. PostgreSQL, MySQL, Redis).
  • Message brokers (e.g. Kafka, RabbitMQ, NATS).
  • Mail protocols such as SMTP and IMAP.
  • Legacy or proprietary TCP-based services.

Without TCPRoute, these workloads must rely on implementation-specific extensions or fall back to traditional Kubernetes Service resources. TCPRoute lets you manage them with the Gateway API and consolidate load balancing under a single Gateway rather than one load balancer per Service.

Spec

The specification of a TCPRoute consists of:

  • ParentRefs - Define which Gateways this Route wants to be attached to.
  • Rules - Define a rule to perform actions against matching TCP connections. For TCPRoute this is limited to which backendRefs should be used. A TCPRoute may contain a single rule with up to 16 backendRefs.

Attaching to Gateways

Each Route includes a way to reference the parent resources it wants to attach to. In most cases, that’s going to be Gateways, but there is some flexibility here for implementations to support other types of parent resources.

The following example shows how a Route would attach to the acme-lb Gateway:

apiVersion: gateway.networking.k8s.io/v1
kind: TCPRoute
metadata:
  name: tcproute-example
spec:
  parentRefs:
    - name: acme-lb

Note that the target Gateway needs to allow TCPRoutes from the route’s namespace to be attached for the attachment to be successful.

Because the example above specifies neither a sectionName nor a port, the TCPRoute attaches to every TCP listener on the acme-lb Gateway. Listeners using other protocols are not affected.

You can also attach routes to specific sections of the parent resource. For example, let’s say that the acme-lb Gateway includes the following listeners:

  listeners:
  - name: postgres
    protocol: TCP
    port: 5432
    ...
  - name: kafka
    protocol: TCP
    port: 9092
    ...

You can bind a route to listener postgres only, using the sectionName field in parentRefs:

spec:
  parentRefs:
    - name: acme-lb
      sectionName: postgres

Alternatively, you can achieve the same effect by using the port field, instead of sectionName, in the parentRefs:

spec:
  parentRefs:
    - name: acme-lb
      port: 5432

However, when binding Routes by port number, Gateway admins will no longer have the flexibility to switch ports on the Gateway without also updating the Routes. This approach should only be used when a Route must bind to a specific port number, rather than to named listeners whose ports may change.

Rules

Rules define the list of actions to be taken with the traffic. A TCPRoute may contain only a single rule defining from 1 to 16 backendRefs.

BackendRefs

BackendRefs defines API objects where matching connections should be sent. At least one backendRef must be specified.

The following example forwards TCP connections arriving on the Gateway listener to service “my-foo-service” on port 6000:

apiVersion: gateway.networking.k8s.io/v1
kind: TCPRoute
metadata:
  name: tcp-app-1
spec:
  parentRefs:
    - name: my-tcp-gateway
      sectionName: foo
  rules:
    - backendRefs:
        - name: my-foo-service
          port: 6000

This TCPRoute attaches to the Gateway TCP listener named foo, as defined below:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-tcp-gateway
spec:
  gatewayClassName: example-gateway-class
  listeners:
    - name: foo
      protocol: TCP
      port: 8080

When multiple backends are specified, connections are distributed across them according to their weight. Each new TCP connection (SYN) is a single unit for weighting purposes. Reference the backendRef API documentation for additional details on weight and other fields. Weight support is Extended for TCPRoute.

If a backendRef is invalid, for example it refers to a nonexistent resource or a Service with no endpoints, the implementation MUST actively reject connections to that backend, respecting weight.

Mixing TCP and UDP

TCP and UDP are distinct transport protocols, so an implementation MAY support a TCP and a UDP listener on the same port without conflict. A common use case is exposing the same service over both protocols, for example DNS on port 53, where TCP traffic is routed by a TCPRoute and UDP traffic by a UDPRoute.

Status

Status defines the observed state of TCPRoute.

RouteStatus

RouteStatus defines the observed state that is required across all route types.

Parent status

Parents define a list of the Gateways (or other parent resources) that are associated with the TCPRoute, and the status of the TCPRoute with respect to each of these Gateways. When a TCPRoute adds a reference to a Gateway in parentRefs, the controller that manages the Gateway should add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route is modified.

The following example indicates TCPRoute “tcp-example” has been accepted by Gateway “gw-example” in namespace “gw-example-ns”:

apiVersion: gateway.networking.k8s.io/v1
kind: TCPRoute
metadata:
  name: tcp-example
...
status:
  parents:
    - parentRef:
        name: gw-example
        namespace: gw-example-ns
      conditions:
        - type: Accepted
          status: "True"

Merging

Multiple TCPRoutes can be attached to a single Gateway resource with different listeners that can be referenced by sectionNames. However, because a TCP listener has no hostname, SNI, or path to distinguish between connections, attaching multiple TCPRoutes to the same listener results in only one route effectively receiving traffic. All attached routes are Accepted, but following the general Gateway API route precedence rules, only the oldest route (by metadata.creationTimestamp, then alphabetically by namespace/name) receives traffic.