| 元件 | 版本 |
|---|---|
| Kubernetes | v1.35 |
| kind | 最新 stable |
| Gateway API | v1.5(Standard + Experimental) |
| Helm | 3.x |
| 容器執行環境 | Docker 或 Podman |
Gateway 與 HTTPRoute
選 kind 而不是 minikube / k3d 的關鍵理由是乾淨:這個系列要裝三個實作互相比較,任何預裝元件(例如 k3d 內建的 Traefik)都是干擾。
versions.env# versions.env
export CLUSTER_NAME="gwapi-lab"
export KIND_NODE_IMAGE="kindest/node:v1.35.0"
export GATEWAY_API_VERSION="v1.5.0"
export ENVOY_GATEWAY_VERSION="v1.8.0"
export TRAEFIK_CHART_VERSION="37.0.0" # Traefik Proxy v3.7
export ISTIO_VERSION="1.29.0"
export GIE_VERSION="v1.2.0"
# kind-cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: gwapi-lab
nodes:
- role: control-plane # 兼任資料平面的入口節點
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
- role: worker # 讓應用 Pod 有地方跑
- role: worker
networking:
podSubnet: "10.244.0.0/16"
serviceSubnet: "10.96.0.0/16"
extraPortMappings 是最關鍵的六行,它把主機的 80/443 埠直接映射到 control-plane 容器的 80/443:
瀏覽器 :80 → 主機 :80 → control-plane 容器 :80 → Envoy / Traefik → 後端 Service
有了它就能直接以 docker inspect 取得容器 IP,也避開了 macOS / Windows 上無法直連容器 IP 的限制。
node-labels: "ingress-ready=true" 則讓三個實作的 Helm chart 都能用 nodeSelector 把資料平面 Pod 釘死在 control-plane 上。這很重要——extraPortMappings 只對 control-plane 生效,資料平面若被排到 worker,流量就過不來了。應用 Pod 則落在兩個 worker 上,「流量進 control-plane → 轉發到 worker 上的 Pod」這條跨節點路徑因此是可觀察的,比單節點拓撲更接近實際部署。
source versions.env
kind create cluster --config kind-cluster.yaml --image $KIND_NODE_IMAGE
kubectl get nodes # 1. 三個節點都 Ready
kubectl get nodes -l ingress-ready=true # 2. 標籤貼在 control-plane
docker port gwapi-lab-control-plane # 3. 埠映射生效
NAME STATUS ROLES AGE VERSION
gwapi-lab-control-plane Ready control-plane 65s v1.35.0
gwapi-lab-worker Ready <none> 48s v1.35.0
gwapi-lab-worker2 Ready <none> 48s v1.35.0
443/tcp -> 0.0.0.0:443
80/tcp -> 0.0.0.0:80
三項都對,叢集就成了。
Gateway API 不是 Kubernetes 內建的 API——它是一組 CRD,必須先安裝,API Server 才認得這些型別:
$ kubectl get gateways.gateway.networking.k8s.io
error: the server doesn't have a resource type "gateways"
| 通道 | 內容 | 穩定性承諾 |
|---|---|---|
| Standard | GA 資源:GatewayClass、Gateway、HTTPRoute、GRPCRoute、ReferenceGrant、BackendTLSPolicy |
有向後相容保證 |
| Experimental | Standard 的超集,多了 TCPRoute、TLSRoute、UDPRoute 與 alpha 欄位 |
無保證,可能破壞性變更 |
兩者不能同時安裝。本系列裝 Experimental,因為需要 L4 Route 對外開放 Redis、DNS 這類非 HTTP 服務。正式環境請裝 Standard。
kubectl apply --server-side -f "https://github.com/kubernetes-sigs/gateway-api/releases/download/${GATEWAY_API_VERSION}/experimental-install.yaml"
# 正式環境把 experimental-install.yaml 換成 standard-install.yaml
kubectl get crd httproutes.gateway.networking.k8s.io # 最重要的一項
kubectl get crd -o name | grep -c 'gateway\.networking\.k8s\.io'
第二條精確數出 10。若改用寬鬆的 kubectl get crd | grep gateway.networking 會得到 12 行,因為它同時命中另一個 API 群組 gateway.networking.x-k8s.io(XBackendTrafficPolicy、XMesh 這兩個更早期的孵化資源,本系列不會用到)。十個正式資源裡的 listenersets 是 v1.5 才進來的 XListenerSet,本篇不涉及但計數時會看到。Day 2 講的「Route 家族」到這裡具體化了。
CRD 裝好後,kubectl explain 就是隨身文件:
kubectl explain httproute.spec.rules.matches
kubectl explain gateway.spec.listeners.allowedRoutes
這正是 Day 2 談的「設定必須結構化且可驗證」的具體收益——欄位定義可直接向叢集查詢,不必依賴外部文件。
映像檔採用 traefik/whoami,它會把收到的 HTTP request 原樣回吐,便於觀察路由行為與驗證標頭改寫。
# manifests/demo-apps.yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-v1
namespace: demo
spec:
replicas: 2
selector:
matchLabels: { app: whoami, version: v1 }
template:
metadata:
labels: { app: whoami, version: v1 }
spec:
containers:
- name: whoami
image: traefik/whoami:v1.10
args: ["--name=whoami-v1"]
ports:
- { name: http, containerPort: 80 }
---
apiVersion: v1
kind: Service
metadata:
name: whoami-v1
namespace: demo
spec:
selector: { app: whoami, version: v1 }
ports:
- { name: http, port: 80, targetPort: http }
把上面的 Deployment 與 Service 再複製一份、v1 全部改成 v2,就得到第二組可區分的後端。
kubectl apply -f manifests/demo-apps.yaml
kubectl -n demo get pods -o wide
kubectl -n demo run curlpod --rm -it --image=curlimages/curl:8.11.1 \
--restart=Never -- curl -s http://whoami-v1/ | head -3
注意 -o wide 的 NODE 欄位——Pod 都在 worker 上,而資料平面被釘在 control-plane。這個跨節點路徑就是本系列各篇流量實際走的路。