Skip to main content

Proxy TCP Traffic by Port

Route TCP connections to a MySQL Service based on the incoming gateway port using either a Gateway API TCPRoute or an APISIX CRD stream route.

Prerequisites

  1. Complete Set Up Ingress Controller and Gateway.
  2. Install MySQL Shell to initiate connections with MySQL server.

Start an Example Upstream Service

Create a Kubernetes manifest file for an example MySQL upstream service with the root password my-secret-pw:

mysql.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: aic
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:9.4
env:
- name: MYSQL_ROOT_PASSWORD
value: "my-secret-pw"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumes:
- name: mysql-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: aic
spec:
selector:
app: mysql
ports:
- name: mysql
port: 3306
targetPort: 3306

Apply the configuration to your cluster:

kubectl apply -f mysql.yaml

Enable Gateway Stream Proxy

Upgrade your gateway to enable stream mode and set TCP port 9100:

helm upgrade -n aic apisix apisix/apisix \
--set ... \ # add other parameters
--set "service.stream.enabled=true" \
--set "service.stream.tcp[0]=9100"

Configure TCP Routing

In this section, you will configure a route that listens for TCP traffic on port 9100.

Update your Gateway manifest file to define a listener for TCP traffic:

gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: aic
name: apisix
spec:
gatewayClassName: apisix
listeners:
- name: http
protocol: HTTP
port: 80
- name: tcp
protocol: TCP
port: 9100
allowedRoutes:
kinds:
- kind: TCPRoute
infrastructure:
parametersRef:
group: apisix.apache.org
kind: GatewayProxy
name: apisix-config

Create a Kubernetes manifest for a TCPRoute:

tcp-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: TCPRoute
metadata:
name: stream-route-mysql
namespace: aic
spec:
parentRefs:
- name: apisix
sectionName: tcp
rules:
- backendRefs:
- name: mysql
port: 3306

When listener_port_match_mode is explicit or auto, the sectionName: tcp reference adds a server_port match for 9100. The Gateway listener port must equal the physical APISIX stream listener port. The default off mode does not add this match.

Apply the configuration to your cluster:

kubectl apply -f gateway.yaml -f tcp-route.yaml

Set the Upstream Transport

Use tcp for a plain TCP backend or tls when the gateway must establish TLS to the backend. The L4 schemes apply only to stream routes.

Attach a BackendTrafficPolicy to the backend Service:

mysql-upstream-policy.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: mysql-transport
namespace: aic
spec:
targetRefs:
- group: ""
kind: Service
name: mysql
sectionName: mysql
scheme: tcp

Apply the policy:

kubectl apply -f mysql-upstream-policy.yaml

To attach stream plugins to the TCPRoute, see Apply Plugins to L4 Routes.

Verify

Expose the gateway’s service port to your local machine:

# replace with your gateway’s service name
kubectl port-forward svc/<gateway-service-name> 9100:9100 &

Connect with the MySQL server as root and key in the password my-secret-pw once prompted:

mysqlsh --sqlc --host=127.0.0.1 --port=9100 --user=root --password

If successful, MySQL Shell opens a classic protocol session and displays output similar to the following:

Creating a Classic session to 'root@127.0.0.1:9100'
Your MySQL connection id is 9
Server version: 9.4.0 MySQL Community Server - GPL