Gateway API
Делаю:
2026.04.10
https://www.youtube.com/watch?v=q76XVCTDZCY
https://github.com/marcel-dempers/docker-development-youtube-series/tree/master/kubernetes/gateway-api
We need a Kubernetes cluster
$ kind create cluster --name gatewayapi --image kindest/node:v1.35.0
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
gatewayapi-control-plane Ready control-plane 97s v1.35.0
Gateway API CRDs
$ kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml
This will install (Stable Channel):
- Gateway Classes:
kubectl get gatewayclass - Gateways:
kubectl get gateway - HTTP Routes:
kubectl get httproute
These APIs are part of the Experimental Channel:
- TLS Routes:
kubectl get tlsroute - TCP Routes:
kubectl get tcproute - UDP Routes:
kubectl get udproute
Note: Gateway API is very new, and all of the above is subject to change quite rapidly
Setup some example applications
1) Приложение на python
2) Приложение на go
3) Фронт приложение которое умеет делать запросы к go приложени.
The following will deploy a deployment, service and require configMap and secret for the applications to work.
$ cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-deploy
labels:
app: python-app
spec:
selector:
matchLabels:
app: python-app
replicas: 2
template:
metadata:
labels:
app: python-app
spec:
containers:
- name: python-app
image: aimvector/python:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 5000
---
kind: Service
apiVersion: v1
metadata:
name: python-svc
spec:
selector:
app: python-app
ports:
- protocol: TCP
port: 5000
targetPort: 5000
type: ClusterIP
EOF
$ cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-deploy
labels:
app: go-app
spec:
selector:
matchLabels:
app: go-app
replicas: 2
template:
metadata:
labels:
app: go-app
spec:
containers:
- name: go-app
image: aimvector/golang:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 5000
volumeMounts:
- name: secret-volume
mountPath: /secrets/
- name: config-volume
mountPath: /configs/
volumes:
- name: secret-volume
secret:
secretName: go-secret
- name: config-volume
configMap:
name: go-config
---
apiVersion: v1
kind: Secret
metadata:
name: go-secret
type: Opaque
data:
secret.json: ewogICAgImFwaV9rZXkiIDogInNvbWVzZWNyZXRnb2VzaGVyZSIKfQo=
---
apiVersion: v1
kind: ConfigMap
metadata:
name: go-config
data:
config.json: |
{
"environment" : "dev"
}
---
kind: Service
apiVersion: v1
metadata:
name: go-svc
spec:
selector:
app: go-app
ports:
- protocol: TCP
port: 5000
targetPort: 5000
type: ClusterIP
EOF
$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: web-app
labels:
app: web-app
data:
# The index.html file that NGINX will serve
index.html: |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CORS Demo Client</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; background-color: #f0f4f8; }
.container { background: white; padding: 30px; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); max-width: 600px; margin: auto; }
h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
button { background-color: #3498db; color: white; padding: 10px 15px; border: none; border-radius: 6px; cursor: pointer; margin-top: 15px; font-weight: bold; transition: background-color 0.3s; }
button:hover { background-color: #2980b9; }
pre { background-color: #ecf0f1; padding: 15px; border-radius: 6px; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; }
.status-ok { color: green; font-weight: bold; }
.status-error { color: red; font-weight: bold; }
</style>
</head>
<body>
<div class="container">
<h1>Client-Side CORS Demonstration</h1>
<button onclick="fetchData()">Make CORS Request</button>
<h2>Result:</h2>
<p>Status: <span id="status">Waiting...</span></p>
<pre id="output"></pre>
</div>
<script>
async function fetchData() {
const apiEndpoint = 'http://example-app.com/api/go';
const statusElement = document.getElementById('status');
const outputElement = document.getElementById('output');
statusElement.textContent = 'Fetching...';
outputElement.textContent = 'Request sent to ' + apiEndpoint;
try {
// This public API allows CORS, so the fetch should succeed.
const response = await fetch(apiEndpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.text();
statusElement.innerHTML = '<span class="status-ok">SUCCESS (CORS Allowed)</span>';
outputElement.textContent = data;
} catch (error) {
// If the API did NOT allow CORS, this catch block would activate,
// often showing a generic "Failed to fetch" error in the console.
statusElement.innerHTML = '<span class="status-error">FAILURE (Check Browser Console for CORS Error)</span>';
outputElement.textContent = 'Error during fetch: ' + error.message;
console.error("CORS Request Error:", error);
}
}
</script>
</body>
</html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web-app
spec:
replicas: 1
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx-web
image: nginx:stable-alpine
ports:
- containerPort: 80
volumeMounts:
- name: html-volume
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: html-volume
configMap:
name: web-app
defaultMode: 0644
---
apiVersion: v1
kind: Service
metadata:
name: web-app
labels:
app: web-app
spec:
type: ClusterIP
selector:
app: web-app
ports:
- protocol: TCP
port: 80
targetPort: 80
name: http
EOF
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
go-deploy-5449f5df89-2mhss 1/1 Running 0 35s
go-deploy-5449f5df89-jswnq 1/1 Running 0 35s
python-deploy-5fc58df78c-px8jx 1/1 Running 0 40s
python-deploy-5fc58df78c-qlmvs 1/1 Running 0 40s
web-app-679f5b5857-qw8r9 1/1 Running 0 26s
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
go-svc ClusterIP 10.96.167.54 <none> 5000/TCP 58s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8m3s
python-svc ClusterIP 10.96.218.1 <none> 5000/TCP 63s
web-app ClusterIP 10.96.236.255 <none> 80/TCP 49s
Create test Domains
We also need to imagine we have a domain called example-app.com , so let’s set that up on our hosts file
$ echo "127.0.0.1 example-app.com" | sudo tee -a /etc/hosts
$ echo "127.0.0.1 example-app-go.com" | sudo tee -a /etc/hosts
$ echo "127.0.0.1 example-app-python.com" | sudo tee -a /etc/hosts
HTTPS and TLS
$ sudo apt install -y libnss3-tools
In my video, I generate a test TLS cert using mkcert
$ curl -L https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64 -o mkcert && chmod +x mkcert && sudo mv mkcert /usr/local/bin/
#linux
$ export CAROOT=${PWD}/kubernetes/gateway-api/tls
$ mkcert -key-file kubernetes/gateway-api/tls/key.pem -cert-file kubernetes/gateway-api/tls/cert.pem example-app.com
$ mkcert -install
Now that we have a TLS cert, we can create a Kubernetes secret to store it:
$ kubectl create secret tls secret-tls -n default --cert kubernetes/gateway-api/tls/cert.pem --key kubernetes/gateway-api/tls/key.pem
We need to
- Adjust our Gateway, to enable the TLS Listener first!
- Then apply the TLS listener in our HTTP Route to enable TLS, using
sectionName
$ cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: go-route
namespace: default
spec:
parentRefs:
- name: gateway-api
sectionName: http
kind: Gateway
- name: gateway-api
sectionName: https
kind: Gateway
hostnames:
- example-app.com
rules:
- matches:
- path:
type: PathPrefix
value: /api/go
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: go-svc
port: 5000
weight: 1
EOF