WebSocket是基于RFC 6455标准,用于客户端和服务器端之间进行双向通信的协议。Istio Sidecar Proxy提供了开箱即用方式使用WebSocket协议,便于您使用WebSocket协议实现服务访问。本文介绍如何在ASM中使用WebSocket over HTTP/1.1和HTTP/2协议访问服务。
背景信息
WebSocket与HTTP协议不同,WebSocket协议使用HTTP Upgrade标头来建立各方之间的连接。Istio无法识别WebSocket协议,但Istio Sidecar Proxy提供了开箱即用方式支持WebSocket协议。关于Istio支持WebSocket协议详细介绍,请参见HTTP upgrades、HTTP connection manager和Protocol Selection。
您可以在ASM中使用WebSocket over HTTP/1.1和HTTP/2协议访问服务,区别如下:
- WebSocket over HTTP/1.1协议:一次请求和响应,建立一个连接,用完关闭连接。
- WebSocket over HTTP/2协议:多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行。
部署WebSocket客户端和服务端
- 通过kubectl工具连接集群。
- 部署WebSocket服务端。
本文使用WebSocket社区提供的Python库中WebSocket服务端为例。如果您想修改WebSocket服务端的部署配置,请参见
容器化应用程序。
- 使用以下内容,创建websockets-server.yaml。
apiVersion: v1
kind: Service
metadata:
name: websockets-server
labels:
app: websockets-server
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 80
name: http-websocket
selector:
app: websockets-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: websockets-server
labels:
app: websockets-server
spec:
selector:
matchLabels:
app: websockets-server
template:
metadata:
labels:
app: websockets-server
spec:
containers:
- name: websockets-test
image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/istio-websockets-test:1.0
ports:
- containerPort: 80
- 在default命名空间下部署WebSocket服务端。
kubectl apply -f websockets-server.yaml -n default
- 部署WebSocket客户端。
本文使用以下Dockerfile创建WebSocket客户端镜像,
websockets-client.yaml文件中使用已经构建完成的WebSocket客户端镜像,您可以直接部署到集群中。
FROM python:3.9-alpine
RUN pip3 install websockets
- 使用以下内容,创建websockets-client.yaml。
apiVersion: v1
kind: Service
metadata:
name: websockets-client
labels:
app: websockets-client
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 80
name: http-websockets-client
selector:
app: websockets-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: websockets-client-sleep
labels:
app: websockets-client
spec:
selector:
matchLabels:
app: websockets-client
template:
metadata:
labels:
app: websockets-client
spec:
containers:
- name: websockets-client
image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/istio-websockets-client-test:1.0
command: ["sleep", "14d"]
- 在default命名空间下部署WebSocket客户端。
kubectl apply -f websockets-client.yaml -n default
使用WebSocket over HTTP/1.1协议
使用WebSocket客户端向服务端发送了多个请求,Sidecar Proxy日志只会包含一个WebSocket连接的访问日志条目。 Envoy将WebSocket连接视为TCP字节流,并且代理只能理解HTTP升级请求或响应,因此Envoy只会在连接关闭后创建该访问日志条目,并且也不会看到每个TCP请求的任何消息。
- 任选以下方式,打开Shell命令行窗口。
- 方式一:
- 登录容器服务管理控制台,在左侧导航栏中单击集群。
- 在集群列表页面中,单击目标集群名称,然后在左侧导航栏中,选择。
- 在容器组页面单击websockets-client右侧操作列下终端,单击容器:websockets-client。
- 方式二:
执行以下命令,打开Shell命令行窗口。
kubectl exec -it -n <namespace> websockets-client-sleep... -c websockets-client -- sh
- 执行以下命令,访问WebSocket服务端。
python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
预期输出:
Connected to ws://websockets-server.default.svc.cluster.local:8080.
输入hello和word,可以看到返回hello和word。
> hello
< hello
> world
< world
Connection closed: 1000 (OK).
- 查看Sidecar Proxy日志。
- 查看WebSocket客户端的Sidecar Proxy日志。
- 在容器组页面单击WebSocket客户端容器名称。
- 单击日志页签,设置容器为istio-proxy。
可以看到日志中包含使用WebSocket over HTTP/1.1协议记录。
{...."upstream_host":"10.208.0.105:80","bytes_sent":23,"protocol":"HTTP/1.1",....}
- 查看WebSocket服务端的Sidecar Proxy日志。
- 在容器组页面单击WebSocket服务端容器名称。
- 单击日志页签,设置容器为istio-proxy。
可以看到日志中包含使用WebSocket over HTTP/1.1协议记录。
{...."downstream_local_address":"10.208.0.105:80","upstream_local_address":"127.0.**.**:53983","protocol":"HTTP/1.1",....}
使用WebSocket over HTTP/2协议
低于1.12版本的Istio使用WebSocket over HTTP/2协议,将不能正常连接到WebSocket服务器端, 并返回503错误。
如果您已经为低于1.12版本的Istio设置HTTP/2升级,并发生报错,您可以通过在目标规则中定义
h2UpgradePolicy为
DO_NOT_UPGRADE的方式,使低于1.12版本的Istio可以正常使用WebSocket over HTTP/1.1协议。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
labels:
provider: asm
name: websockets-server
spec:
host: websockets-server
trafficPolicy:
connectionPool:
http:
h2UpgradePolicy: DO_NOT_UPGRADE
Istio 1.12或以上版本使用WebSocket over HTTP/2协议的操作如下:
- 创建目标规则。
- 登录ASM控制台。
- 在左侧导航栏,选择。
- 在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
- 在网格详情页面左侧导航栏选择,然后在右侧页面单击使用YAML创建。
- 设置命名空间为default,复制以下内容到文本框中,然后单击创建。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
labels:
provider: asm
name: websockets-server
spec:
host: websockets-server
trafficPolicy:
connectionPool:
http:
h2UpgradePolicy: UPGRADE
h2UpgradePolicy:设置为UPGRADE,表示为websockets-server启用HTTP/2协议。
- 创建EnvoyFilter。
默认情况下,WebSocket不支持HTTP/2协议,但Envoy却支持WebSocket在HTTP/2流上进行隧道传输,以便在整个部署过程中可以使用统一的HTTP/2网络。您可以通过EnvoyFilter针对目标工作负载设置allow_connect: true
,从而使WebSocket服务端允许HTTP/2协议连接。
- 登录ASM控制台。
- 在左侧导航栏,选择。
- 在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
- 在网格详情页面左侧导航栏选择。
- 在插件市场页面,单击设置allow_connect为true允许升级的协议连接。
- 在插件详情页面,单击插件配置页签,在插件生效范围区域,选中工作负载生效,然后单击添加工作负载到生效范围。
- 在添加工作负载到生效范围对话框中,设置命名空间为default,工作负载类型为Deployment,在选择负载区域选中websockets-server,单击
图标,将websockets-server添加到已选择区域中,然后单击确定。
- 在插件配置区域的YAML框中输入
patch_context: SIDECAR_INBOUND
,然后打开生效开关,等待插件启用。在插件启用后,ASM会自动创建Envoy过滤器,Envoy过滤器的YAML示例如下:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: h2-upgrade-wss
labels:
asm-system: 'true'
provider: asm
spec:
workloadSelector:
labels:
app: websockets-server
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_INBOUND
proxy:
proxyVersion: '^1\.*.*'
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
http2_protocol_options:
allow_connect: true
- 执行以下命令,访问WebSocket服务端。
python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
预期输出:
Connected to ws://websockets-server.default.svc.cluster.local:8080.
输入hello和word,可以看到返回hello和word。
> hello
< hello
> world
< world
Connection closed: 1000 (OK).
- 查看Sidecar Proxy日志。
- 查看WebSocket客户端的Sidecar Proxy日志。
- 在容器组页面单击WebSocket客户端容器名称。
- 单击日志页签,设置容器为istio-proxy。
可以看到日志中包含使用WebSocket over HTTP/1.1协议记录,说明客户端发起请求使用的是HTTP/1.1协议。
{...."authority":"websockets-server.default.svc.cluster.local:8080","upstream_service_time":null,"protocol":"HTTP/1.1",....}
- 查看WebSocket服务端的Sidecar Proxy日志。
- 在容器组页面单击WebSocket服务端容器名称。
- 单击日志页签,设置容器为istio-proxy。
可以看到日志中包含使用WebSocket over HTTP/2协议记录,说明WebSocket服务端的接收到的协议已经升级为HTTP/2。
{...."method":"GET","upstream_local_address":"127.0.**.**:34477","protocol":"HTTP/2",....}