TCPRoute
Standard Channel since v1.6.0
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.