第42章 可落地完整参考实现:一套能跑的多协议转发栈
学习目标
- 把第 39-41 章的原理落成一套可
kubectl apply的参考清单 - 一个栈同时承载:web-vscode(WS) + SSE + gRPC + SSH(L4) + 普通 HTTP
- 拿到逐协议的验证命令,确认每条链路真的通
前置知识
说明:以下清单是参考骨架,
image、host、证书 secret 需按你的环境替换。目的是展示"各协议在一个栈里如何正确共存",而非开箱即用的产品。
Demo 拓扑
┌─ ide.demo.com (WebSocket) ─▶ code-server
Client ─443─▶ 边缘nginx ─┼─ sse.demo.com (SSE) ─▶ sse-app
(TLS终止) ├─ grpc.demo.com (gRPC/h2) ─▶ grpc-backend
▼ └─ www.demo.com (HTTP) ─▶ web-app
ingress-nginx
Client ─2222─────────────(L4 tcp-services)────────────▶ sshd:22
️ 一、命名空间与 ingress-nginx 前置
apiVersion: v1
kind: Namespace
metadata: { name: demo }
# 装 ingress-nginx,并开启 L4 tcp-services(SSH 用)
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set tcp.2222="demo/sshd:22" \ # 节点 2222 → demo/sshd:22(第40章方案A)
--set controller.service.type=LoadBalancer
# 或手动维护 ingress-nginx/tcp-services ConfigMap 并让 controller Service 暴露 2222
️ 二、web-vscode(code-server,WebSocket)
apiVersion: apps/v1
kind: Deployment
metadata: { name: code-server, namespace: demo }
spec:
replicas: 1 # WS 长连接:单副本省心(第40章)
selector: { matchLabels: { app: code-server } }
template:
metadata: { labels: { app: code-server } }
spec:
containers:
- name: code-server
image: codercom/code-server:latest # 替换为你的镜像
args: ["--bind-addr", "0.0.0.0:8080", "--auth", "password"]
env: [{ name: PASSWORD, value: "change-me" }]
ports: [{ containerPort: 8080 }]
---
apiVersion: v1
kind: Service
metadata: { name: code-server, namespace: demo }
spec:
selector: { app: code-server }
ports: [{ port: 8080, targetPort: 8080 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ide
namespace: demo
annotations:
# 铁律一:长超时(WS 空闲不被掐);铁律二对 WS 无害
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
ingressClassName: nginx
tls: [{ hosts: [ide.demo.com], secretName: ide-tls }]
rules:
- host: ide.demo.com
http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: code-server, port: { number: 8080 } } } }] }
️ 三、SSE 示例服务
apiVersion: apps/v1
kind: Deployment
metadata: { name: sse-app, namespace: demo }
spec:
selector: { matchLabels: { app: sse-app } }
template:
metadata: { labels: { app: sse-app } }
spec:
containers:
- name: sse
image: your/sse-demo:latest # 一个发 text/event-stream 的小服务
ports: [{ containerPort: 8090 }]
# 应用响应里带:Content-Type: text/event-stream + X-Accel-Buffering: no(第40章)
---
apiVersion: v1
kind: Service
metadata: { name: sse-app, namespace: demo }
spec: { selector: { app: sse-app }, ports: [{ port: 8090, targetPort: 8090 }] }
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sse
namespace: demo
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" # 铁律一
nginx.ingress.kubernetes.io/proxy-buffering: "off" # 铁律二:流式必须
spec:
ingressClassName: nginx
tls: [{ hosts: [sse.demo.com], secretName: sse-tls }]
rules:
- host: sse.demo.com
http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: sse-app, port: { number: 8090 } } } }] }
️ 四、gRPC 后端(端到端 h2)
apiVersion: apps/v1
kind: Deployment
metadata: { name: grpc-backend, namespace: demo }
spec:
replicas: 3 # 多副本演示 gRPC 负载(第41章)
selector: { matchLabels: { app: grpc-backend } }
template:
metadata: { labels: { app: grpc-backend } }
spec:
containers:
- name: grpc
image: your/grpc-server:latest # 在 50051 提供 gRPC
ports: [{ containerPort: 50051 }]
---
apiVersion: v1
kind: Service
metadata: { name: grpc-backend, namespace: demo }
spec: { selector: { app: grpc-backend }, ports: [{ port: 50051, targetPort: 50051 }] }
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grpc
namespace: demo
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "GRPC" # 关键:h2+trailers(第41章)
spec:
ingressClassName: nginx
tls: [{ hosts: [grpc.demo.com], secretName: grpc-tls }]
rules:
- host: grpc.demo.com
http: { paths: [{ path: /, pathType: Prefix, backend: { service: { name: grpc-backend, port: { number: 50051 } } } }] }
️ 五、SSH(L4,走 tcp-services)
apiVersion: apps/v1
kind: Deployment
metadata: { name: sshd, namespace: demo }
spec:
selector: { matchLabels: { app: sshd } }
template:
metadata: { labels: { app: sshd } }
spec:
containers:
- name: sshd
image: linuxserver/openssh-server:latest # 替换/配置好账号密钥
ports: [{ containerPort: 22 }]
---
apiVersion: v1
kind: Service
metadata: { name: sshd, namespace: demo }
spec: { selector: { app: sshd }, ports: [{ port: 22, targetPort: 22 }] }
# 节点 2222 → demo/sshd:22 已在第一步 tcp-services 配好(L4,无 Ingress 资源)
️ 六、边缘 nginx(两级第一跳)
把 第40章 的边缘配置放进 ConfigMap,作为前置 Pod(或直接跑在边缘 VM/云 LB):
apiVersion: v1
kind: ConfigMap
metadata: { name: edge-nginx-conf, namespace: demo }
data:
nginx.conf: |
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
upstream ingress { server ingress-nginx-controller.ingress-nginx:443; keepalive 64; }
server {
listen 443 ssl;
server_name *.demo.com;
ssl_certificate /etc/certs/tls.crt;
ssl_certificate_key /etc/certs/tls.key;
client_max_body_size 0; # 大文件每跳放开(第41章)
location / {
proxy_pass https://ingress;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # 铁律三
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s; proxy_send_timeout 3600s; # 铁律一
proxy_buffering off; # 铁律二
}
}
# 配 Deployment 挂这个 ConfigMap + 证书 secret 即可(略)
注意:边缘到 ingress 是 TLS→TLS(重加密,第05章);gRPC 经边缘时,若边缘做 L7 解析需保证 h2 不被降级(生产中 gRPC 常单独走一条端到端 h2 的边缘 server 块或 L4 透传)。
逐协议验证清单
# 1. 普通 HTTP
curl -sI https://www.demo.com/ | head -1 # 200
# 2. WebSocket(code-server)—— 期望 101
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" \
https://ide.demo.com/ | grep -i "101"
# 3. SSE —— 期望数据实时一行行出(不是憋一批)
curl -N https://sse.demo.com/events
# 4. gRPC —— 期望列出服务(端到端 h2+trailers)
grpcurl grpc.demo.com:443 list
# 5. SSH(L4 tcp-services)
ssh -o ServerAliveInterval=30 -p 2222 user@<ingress-lb-ip>
# 6. 大文件上传 —— 期望非 413
curl -X POST --data-binary @big.bin https://www.demo.com/upload -w "%{http_code}\n"
逐条对照 第40章/第41章 的排错矩阵——哪条不通,就回去查对应那条铁律/那一跳。
排错(栈级)
| 现象 | 根因 | 解决 |
|---|---|---|
| 全部 HTTPS 不通 | 证书 secret 缺/边缘 TLS 错 | 建好各 host 的 tls secret |
| 只有 WS/SSE 在 ~60s 断 | 漏配某跳超时 | 边缘 + ingress 两跳都配 3600s |
| SSE 憋住 | 漏配某跳关缓冲 | 边缘 proxy_buffering off + ingress annotation |
| gRPC 不通 | 边缘把 h2 降级 / ingress 没标 GRPC | 端到端 h2 + backend-protocol: GRPC |
| SSH 2222 不通 | tcp-services 没配 / controller 没暴露端口 | 查 ConfigMap + controller Service 端口 |
| 上传 413 | 某跳 body 上限 | 边缘 client_max_body_size 0 + ingress proxy-body-size: 0 |
本章小结
- 一套栈可同时承载 HTTP / WebSocket / SSE / gRPC / SSH:关键是每协议在每一跳都按其铁律配对。
- WS/SSE 靠超时+关缓冲+Upgrade;gRPC 靠端到端 h2 +
backend-protocol: GRPC;SSH 靠 L4tcp-services;大文件靠每跳放开体积上限。 - 逐协议验证清单让你确认链路真的通,不通就沿链定位到具体哪一跳、哪条铁律。
全书终章
到这里,《代理技术全栈手册》42 章 + 3 附录 真正完结。我们走过的路:
- 原理 → 协议 → 层级 → 组件 → 多语言 → 容器K8s → 进阶(1-33 章):看懂、会配、能手写
- 底层机制(34-38 章):背压、状态机、h2 内部、算法与韧性——理解代理在压力下怎么活下来
- 综合实战(39-42 章):把全书拉进真实企业多跳拓扑,让 WS/SSE/gRPC/SSH/UDP 在一条链上共存
代理的本质始终是那一句:在两点之间多一跳,从而获得控制力。 而真正的功力,体现在让这一跳——在协议的多样性、速度的差异、连接的风暴、后端的故障、多跳的协调下——依然稳健、可观测、可排查。
愿你从此看到任何"代理",都能一眼看穿它的类型、层级、协议、机制与落点。回到 手册首页。