Os proxies sidecar do Alibaba Cloud Service Mesh (ASM) oferecem suporte ao protocolo WebSocket (RFC 6455) sem necessidade de configuração adicional da malha para HTTP/1,1. O WebSocket é um protocolo de comunicação que permite a troca bidirecional de dados entre cliente e servidor. O uso de WebSocket sobre HTTP/2 exige uma regra de destino e um filtro Envoy.
Este tópico orienta você na implantação de um servidor e cliente WebSocket no ASM e no estabelecimento de conexões WebSocket tanto via HTTP/1,1 quanto via HTTP/2.
HTTP/1,1 vs. HTTP/2: escolha o modo adequado
Uma conexão WebSocket inicia como uma requisição HTTP padrão com um cabeçalho Upgrade. O Istio não reconhece o protocolo WebSocket diretamente, mas os proxies sidecar já trazem esse suporte nativamente. A forma como a malha processa o upgrade depende da versão do HTTP:
|
Modo |
Comportamento |
Configuração |
Quando usar |
|
HTTP/1,1 |
Cada conexão WebSocket ocupa uma conexão TCP. Após o retorno da resposta à requisição, a conexão é encerrada. |
Nenhuma além da injeção de sidecar. |
Para a maioria dos casos de uso. Caminho mais simples. |
|
HTTP/2 |
Várias requisições podem ser processadas em paralelo numa única conexão. Uma requisição lenta não bloqueia as demais. |
Regra de destino + filtro Envoy. |
Malhas uniformes em HTTP/2 ou quando a multiplexação de conexões for relevante. |
O Envoy trata conexões WebSocket como fluxos de bytes TCP. Ele gera uma entrada de log de acesso por conexão (não por mensagem) e grava essa entrada somente após o fechamento da conexão.
Pré-requisitos
Uma instância do ASM com um cluster do Container Service for Kubernetes (ACK) adicionado. Para mais informações, consulte Criar uma instância do ASM e Adicionar um cluster a uma instância do ASM.
Injeção de sidecar ativada para o namespace de destino. Para mais informações, consulte Configurar políticas de injeção de proxy sidecar. Todos os exemplos abaixo utilizam o namespace
default.
Etapa 1: Implantar um servidor e cliente WebSocket
Conectar-se ao cluster ACK
Conecte-se ao cluster ACK usando kubectl. Para mais informações, consulte Obter o arquivo kubeconfig de um cluster e usar kubectl para conectar-se ao cluster.
Implantar o servidor WebSocket
Este exemplo utiliza o servidor WebSocket em Python da comunidade WebSocket. Para mais detalhes sobre como personalizar a implantação do servidor, consulte Implantar no Kubernetes.
-
Crie um arquivo chamado
websockets-server.yamlcom o seguinte conteúdo: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 -
Aplique o manifesto no namespace
default:kubectl apply -f websockets-server.yaml -n default
Implantar o cliente WebSocket
A imagem do cliente WebSocket é construída a partir do seguinte Dockerfile:
FROM python:3.9-alpine
RUN pip3 install websockets
-
Crie um arquivo chamado
websockets-client.yamlcom o seguinte conteúdo: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"] -
Aplique o manifesto no namespace
default:kubectl apply -f websockets-client.yaml -n default
Etapa 2: Estabelecer uma conexão WebSocket sobre HTTP/1,1
O uso de WebSocket sobre HTTP/1,1 não requer configurações adicionais na malha. Após implantar o servidor e o cliente, teste a conexão diretamente.
Abrir um shell no pod do cliente
Utilize um dos métodos a seguir:
Opção A: Console do ACK
Faça login no console do ACK. No painel de navegação à esquerda, clique em Clusters.
Na página Clusters, localize o cluster desejado e clique no nome dele. No painel à esquerda, escolha .
Na página Pods, encontre
websockets-cliente clique em Terminal na coluna Actions. Em seguida, clique em websockets-client.
Opção B: kubectl
kubectl exec -it -n <namespace> websockets-client-sleep... -c websockets-client -- sh
Substitua <namespace> pelo namespace onde o cliente foi implantado (por exemplo, default).
Testar a conexão WebSocket
Conecte-se ao servidor WebSocket:
python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
Saída esperada:
Connected to ws://websockets-server.default.svc.cluster.local:8080.
Digite hello e world para verificar se o servidor de eco retorna cada mensagem:
> hello
< hello
> world
< world
Connection closed: 1000 (OK).
Verificar os logs do proxy sidecar
Consulte os logs de ambos os proxies sidecar para confirmar que a conexão WebSocket utilizou HTTP/1,1.
Logs do proxy sidecar no lado do cliente:
Na página Pods, clique no nome do pod do cliente WebSocket.
Clique na aba Logs e selecione istio-proxy na lista suspensa Container.
O log contém uma entrada com protocol: HTTP/1.1:
{..."upstream_host":"10.208.0.105:80","bytes_sent":23,"protocol":"HTTP/1.1",...}
Logs do proxy sidecar no lado do servidor:
Na página Pods, clique no nome do pod do servidor WebSocket.
Clique na aba Logs e selecione istio-proxy na lista suspensa Container.
O log também exibe protocol: HTTP/1.1:
{..."downstream_local_address":"10.208.0.105:80","upstream_local_address":"127.0.**.**:53983","protocol":"HTTP/1.1",...}
Etapa 3: Estabelecer uma conexão WebSocket sobre HTTP/2
Para multiplexar fluxos WebSocket sobre HTTP/2, configure uma regra de destino e um filtro Envoy. O fluxo de transformação de protocolo funciona da seguinte maneira:
Client (HTTP/1.1 Upgrade) --> Client sidecar --> HTTP/2 CONNECT --> Server sidecar --> HTTP/1.1 Upgrade --> Server
O cliente envia uma requisição de upgrade WebSocket HTTP/1,1 padrão. O sidecar do cliente faz o upgrade para HTTP/2 e encaminha a requisição ao sidecar do servidor, que a repassa à aplicação.
Em versões do Istio anteriores à 1,12, conexões WebSocket não podem ser atualizadas de HTTP/1,1 para HTTP/2. A malha retorna o código de status HTTP 503. Caso encontre um erro 503 ao se conectar, verifique sua versão do Istio. Se estiver numa versão anterior à 1,12, defina h2UpgradePolicy como DO_NOT_UPGRADE na regra de destino para manter o WebSocket em 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
Para Istio 1,12 ou superior, siga as etapas abaixo.
Criar uma regra de destino
Faça login no console do ASM.
No painel de navegação à esquerda, escolha .
Na página Mesh Management, localize a instância do ASM desejada. Clique no nome da instância ou em Manage na coluna Actions.
No painel de navegação à esquerda da página de detalhes, escolha . Na página exibida, clique em Create from YAML.
-
Selecione default na lista suspensa Namespace, cole o YAML a seguir no editor de código e clique em Create: Definir
h2UpgradePolicycomoUPGRADEhabilita HTTP/2 para conexões com o servidor WebSocket.apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: labels: provider: asm name: websockets-server spec: host: websockets-server trafficPolicy: connectionPool: http: h2UpgradePolicy: UPGRADE
Criar um filtro Envoy
Por padrão, o WebSocket não funciona com o protocolo HTTP/2. No entanto, o Envoy suporta tunelamento de WebSocket sobre HTTP/2. Defina o parâmetro allow_connect como true no sidecar do servidor para que conexões HTTP/2 sejam suportadas pelo servidor WebSocket.
Faça login no console do ASM.
No painel de navegação à esquerda, escolha .
Na página Mesh Management, localize a instância do ASM desejada. Clique no nome da instância ou em Manage na coluna Actions.
No painel de navegação à esquerda da página de detalhes, escolha .
Na página Market Place, clique em Template that sets the allow_connect parameter to true to allow updated protocol connections.
Na página Plugin Detail, clique na aba Plugin Config. Na seção Plugin Effective scope, selecione Workload Scope e clique em Add workloads to effective scope.
-
Na caixa de diálogo Add workloads to effective scope, configure os parâmetros conforme descrito a seguir:
Namespace: default
Workload Type: Deployment
Na seção Select workloads, selecione websockets-server, clique no ícone
para movê-lo para a seção selected e clique em OK.
No editor de código YAML da seção Plugin Config, insira
patch_context: SIDECAR_INBOUND, ative a opção Plugin Switch e aguarde até que o plug-in seja habilitado.
Após a ativação do plug-in, o ASM cria automaticamente um filtro Envoy. O YAML gerado é semelhante ao seguinte:
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
Testar a conexão WebSocket sobre HTTP/2
Execute o comando a partir do pod do cliente:
python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
Saída esperada:
Connected to ws://websockets-server.default.svc.cluster.local:8080.
Digite hello e world para verificar a resposta de eco:
> hello
< hello
> world
< world
Connection closed: 1000 (OK).
Verificar o upgrade de protocolo nos logs do proxy sidecar
Logs do proxy sidecar no lado do cliente:
Na página Pods, clique no nome do pod do cliente WebSocket.
Clique na aba Logs e selecione istio-proxy na lista suspensa Container.
O log do lado do cliente mostra protocol: HTTP/1.1 porque o cliente origina a requisição como HTTP/1,1:
{..."authority":"websockets-server.default.svc.cluster.local:8080","upstream_service_time":null,"protocol":"HTTP/1.1",...}
Logs do proxy sidecar no lado do servidor:
Na página Pods, clique no nome do pod do servidor WebSocket.
Clique na aba Logs e selecione istio-proxy na lista suspensa Container.
O log do lado do servidor exibe protocol: HTTP/2, confirmando que o sidecar fez o upgrade da conexão:
{..."method":"GET","upstream_local_address":"127.0.**.**:34477","protocol":"HTTP/2",...}