Envoy Gateway 中使用 HTTP3/QUIC
- Xunzhuo
- Envoy gateway
- December 21, 2023
本文介绍如何通过 Envoy Gateway 处理 HTTP3/QUIC 的流量
什么是 QUIC 协议
HTTP/3 是一种新的网络传输协议,它是 HTTP/2 的后续版本,旨在提高网络性能和安全性。HTTP/3 使用了一个名为 QUIC(Quick UDP Internet Connections)的底层传输协议,它基于 UDP(User Datagram Protocol)而不是传统的 TCP(Transmission Control Protocol)。
QUIC 协议的主要优势在于它可以减少网络延迟、提高连接的可靠性和安全性。以下是 QUIC 协议的一些关键特性:
- 连接建立速度更快:QUIC 使用零轮往返(0-RTT)握手,这意味着在建立连接时,客户端和服务器只需交换一次数据包即可。这大大减少了网络延迟,特别是在高延迟或丢包率较高的网络环境中。
- 内置加密:QUIC 协议内置了 TLS 1.3 加密,确保了数据传输的安全性。这使得 QUIC 协议在安全性方面与 HTTPS 类似,但传输效率更高。
- 更好的拥塞控制:QUIC 协议具有更先进的拥塞控制算法,可以更有效地处理网络拥塞,从而提高数据传输速度。
- 多路复用:与 HTTP/2 类似,HTTP/3 支持多路复用,允许在单个连接上同时传输多个请求和响应。这有助于减少网络延迟和提高带宽利用率。
- 连接迁移:QUIC 支持连接迁移,这意味着当客户端的 IP 地址或网络接口发生变化时,连接可以在不中断的情况下继续传输数据。这对于移动设备尤为重要,因为它们可能在使用过程中频繁切换网络。
如何在 Envoy Gateway 使用
前置条件
- 安装
openssl
用于生成 TLS 证书 - kubernetes 集群,并且包含 Service 的 Loadbalancer 实现
步骤
安装 Envoy Gateway 以及 Gateway API
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v0.0.0-latest -n envoy-gateway-system --create-namespace
确保 Envoy Gateway 可用:
kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available
创建 GatewayClass、Gateway、HTTPRoute 以及 Backend
创建 GatewayClass
cat <<EOF | kubectl apply -f -
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
EOF
创建 Gateway
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
EOF
创建 Backend
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend
---
apiVersion: v1
kind: Service
metadata:
name: backend
labels:
app: backend
service: backend
spec:
ports:
- name: http
port: 3000
targetPort: 3000
selector:
app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
version: v1
template:
metadata:
labels:
app: backend
version: v1
spec:
serviceAccountName: backend
containers:
- image: gcr.io/k8s-staging-ingressconformance/echoserver:v20221109-7ee2f3e
imagePullPolicy: IfNotPresent
name: backend
ports:
- containerPort: 3000
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
EOF
创建 HTTPRoute:
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: backend
spec:
parentRefs:
- name: eg
hostnames:
- "www.example.com"
rules:
- backendRefs:
- group: ""
kind: Service
name: backend
port: 3000
weight: 1
matches:
- path:
type: PathPrefix
value: /
EOF
查看 GatewayClass、Gateway、HTTPRoute 状态
❯ kg gatewayclass
NAME CONTROLLER ACCEPTED AGE
eg gateway.envoyproxy.io/gatewayclass-controller True 46s
❯ kg gateway
NAME CLASS ADDRESS PROGRAMMED AGE
eg eg 172.18.255.200 True 50s
❯ kg httproute
NAME HOSTNAMES AGE
backend ["www.example.com"] 54s
可以看到上述资源状态都为正常,并且能获取正确的 LB IP
TLS 证书
生成根证书和私钥 用来签署其他证书:
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
为
www.example.com
创建证书签名请求 (CSR) 和一个新的私钥:openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization" openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt
使用根证书签署 CSR 生成
www.example.com
的证书:openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt
将证书和密钥存储在 Kubernetes Secret 中:
kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt
更新 Kubernetes Gateway
添加 HTTPS 监听器,监听 443 端口,并关联
example-cert
Secretkubectl patch gateway eg --type=json --patch '[{ "op": "add", "path": "/spec/listeners/-", "value": { "name": "https", "protocol": "HTTPS", "port": 443, "tls": { "mode": "Terminate", "certificateRefs": [{ "kind": "Secret", "group": "", "name": "example-cert", }], }, }, }]'
使用 ClientTrafficPolicy 启用 HTTP3
kubectl apply -f - <<EOF apiVersion: gateway.envoyproxy.io/v1alpha1 kind: ClientTrafficPolicy metadata: name: enable-http3 spec: http3: {} targetRef: group: gateway.networking.k8s.io kind: Gateway name: eg namespace: default EOF
检查 Gateway 状态:
可以看到 Gateway 状态是正常
❯ kubectl get gateway/eg NAME CLASS ADDRESS PROGRAMMED AGE eg eg 172.18.255.200 True 6m36s
测试
获取 Gateway 的 External IP
export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')
通过 Gateway 查询示例应用程序:
下面的示例使用了自定义的 docker 镜像和内置 http3 的自定义 curl 二进制文件
docker run --net=host --rm ghcr.io/macbre/curl-http3 curl -kv --http3 -HHost:www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" https://www.example.com/get
结果:
可以看到 HTTP3 的请求成功被 Envoy Gateway 处理
* Added www.example.com:443:172.18.255.200 to DNS cache * Hostname www.example.com was found in DNS cache * Trying 172.18.255.200:443... * Connect socket 5 over QUIC to 172.18.255.200:443 * Sent QUIC client Initial, ALPN: h3,h3-29,h3-28,h3-27 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Skipped certificate verification * Connected to www.example.com () port 443 (#0) * h2h3 [:method: GET] * h2h3 [:path: /get] * h2h3 [:scheme: https] * h2h3 [:authority: www.example.com] * h2h3 [user-agent: curl/7.84.0-DEV] * h2h3 [accept: */*] * Using HTTP/3 Stream ID: 0 (easy handle 0x4001e77ac0) > GET /get HTTP/3 > Host:www.example.com > user-agent: curl/7.84.0-DEV > accept: */* > < HTTP/3 200 < content-type: application/json < x-content-type-options: nosniff < date: Thu, 21 Dec 2023 09:05:52 GMT < content-length: 513 < x-envoy-upstream-service-time: 0 < alt-svc: h3=":10443"; ma=86400 < server: envoy < { [513 bytes data] { "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "User-Agent": [ "curl/7.84.0-DEV" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Envoy-Internal": [ "true" ], "X-Forwarded-For": [ "172.18.0.1" ], "X-Forwarded-Proto": [ "https" ], "X-Request-Id": [ "0c165237-5993-4539-8942-0899d6120409" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-58d58f745-l878w" 100 513 100 513 0 0 3977 0 --:--:-- --:--:-- --:--:-- 13864 * Connection #0 to host www.example.com left intact }%
至此,你已经通过 Envoy Gateway 使用 HTTP3 监听下游服务,并访问到目标后端服务。