Les proxys sidecar d'Alibaba Cloud Service Mesh (ASM) prennent en charge le protocole WebSocket (RFC 6455) sans configuration de maillage supplémentaire pour HTTP/1.1. WebSocket est un protocole de communication qui permet une communication bidirectionnelle entre un client et un serveur. L'utilisation de WebSocket sur HTTP/2 nécessite une règle de destination et un filtre Envoy.
Cette rubrique explique comment déployer un serveur et un client WebSocket dans ASM, puis établir des connexions WebSocket à la fois sur HTTP/1.1 et HTTP/2.
HTTP/1.1 contre HTTP/2 : choisir le bon mode
Une connexion WebSocket commence par une requête HTTP standard comportant un en-tête Upgrade. Istio ne reconnaît pas directement le protocole WebSocket, mais les proxys sidecar offrent une prise en charge prête à l'emploi. La gestion de la mise à niveau par le maillage dépend de la version HTTP :
| Mode | Comportement | Configuration | Quand l'utiliser |
|---|---|---|---|
| HTTP/1.1 | Chaque connexion WebSocket occupe une connexion TCP. Une fois la réponse renvoyée pour la requête, la connexion est fermée. | Aucune au-delà de l'injection du sidecar. | Pour la plupart des cas d'utilisation. C'est la méthode la plus simple. |
| HTTP/2 | Plusieurs requêtes peuvent être traitées en parallèle sur une seule connexion. Une requête lente ne bloque pas les autres. | Règle de destination + filtre Envoy. | Pour un maillage HTTP/2 uniforme ou lorsque le multiplexage des connexions est important. |
Envoy traite les connexions WebSocket comme des flux d'octets TCP. Il génère une entrée de journal d'accès par connexion (et non par message) et écrit cette entrée uniquement après la fermeture de la connexion.
Prérequis
Une instance ASM avec un cluster Container Service for Kubernetes (ACK) ajouté. Pour plus d'informations, consultez les rubriques Créer une instance ASM et Ajouter un cluster à une instance ASM.
L'injection du sidecar activée pour le namespace cible. Pour plus d'informations, voir Configurer les politiques d'injection de proxy sidecar. Tous les exemples ci-dessous utilisent le namespace
default.
Étape 1 : Déployer un serveur et un client WebSocket
Se connecter au cluster ACK
Connectez-vous au cluster ACK à l'aide de kubectl. Pour plus d'informations, consultez la rubrique Obtenir le fichier kubeconfig d'un cluster et utiliser kubectl pour se connecter au cluster.
Déployer le serveur WebSocket
Cet exemple utilise le serveur WebSocket Python de la communauté WebSocket. Pour plus d'informations sur la personnalisation du déploiement du serveur, consultez la rubrique Déployer sur Kubernetes.
-
Créez un fichier nommé
websockets-server.yamlavec le contenu suivant :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 -
Appliquez le manifeste au namespace
default:kubectl apply -f websockets-server.yaml -n default
Déployer le client WebSocket
L'image du client WebSocket est construite à partir du Dockerfile suivant :
FROM python:3.9-alpine
RUN pip3 install websockets
-
Créez un fichier nommé
websockets-client.yamlavec le contenu suivant :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"] -
Appliquez le manifeste au namespace
default:kubectl apply -f websockets-client.yaml -n default
Étape 2 : Établir une connexion WebSocket sur HTTP/1.1
WebSocket sur HTTP/1.1 ne nécessite aucune configuration de maillage supplémentaire. Après avoir déployé le serveur et le client, testez directement la connexion.
Ouvrir un shell dans le pod client
Utilisez l'une des méthodes suivantes :
Option A : Console ACK
Connectez-vous à la console ACK. Dans le volet de navigation de gauche, cliquez sur Clusters.
Sur la page Clusters, recherchez le cluster cible et cliquez sur son nom. Dans le volet de gauche, choisissez .
Sur la page Pods, recherchez
websockets-clientet cliquez sur Terminal dans la colonne Actions. Ensuite, cliquez sur websockets-client.
Option B : kubectl
kubectl exec -it -n <namespace> websockets-client-sleep... -c websockets-client -- sh
Remplacez <namespace> par le namespace où le client est déployé (par exemple, default).
Tester la connexion WebSocket
Connectez-vous au serveur WebSocket :
python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
Sortie attendue :
Connected to ws://websockets-server.default.svc.cluster.local:8080.
Saisissez hello et world pour vérifier que le serveur echo renvoie chaque message :
> hello
< hello
> world
< world
Connection closed: 1000 (OK).
Vérifier les journaux du proxy sidecar
Consultez les journaux des deux proxys sidecar pour confirmer que la connexion WebSocket utilisait HTTP/1.1.
Journaux du proxy sidecar côté client :
Sur la page Pods, cliquez sur le nom du pod client WebSocket.
Cliquez sur l'onglet Logs et sélectionnez istio-proxy dans la liste déroulante Container.
Le journal contient une entrée avec protocol: HTTP/1.1 :
{..."upstream_host":"10.208.0.105:80","bytes_sent":23,"protocol":"HTTP/1.1",...}
Journaux du proxy sidecar côté serveur :
Sur la page Pods, cliquez sur le nom du pod serveur WebSocket.
Cliquez sur l'onglet Logs et sélectionnez istio-proxy dans la liste déroulante Container.
Le journal affiche également protocol: HTTP/1.1 :
{..."downstream_local_address":"10.208.0.105:80","upstream_local_address":"127.0.**.**:53983","protocol":"HTTP/1.1",...}
Étape 3 : Établir une connexion WebSocket sur HTTP/2
Pour multiplexer les flux WebSocket sur HTTP/2, configurez une règle de destination et un filtre Envoy. Le flux de transformation du protocole fonctionne comme suit :
Client (HTTP/1.1 Upgrade) --> Client sidecar --> HTTP/2 CONNECT --> Server sidecar --> HTTP/1.1 Upgrade --> Server
Le client envoie une requête de mise à niveau WebSocket HTTP/1.1 standard. Le sidecar côté client la met à niveau vers HTTP/2 et la transfère au sidecar côté serveur, qui la transmet à l'application.
Sur les versions d'Istio antérieures à la 1.12, les connexions WebSocket ne peuvent pas être mises à niveau de HTTP/1.1 vers HTTP/2. Le maillage renvoie le code d'état HTTP 503. Si vous rencontrez une erreur 503 lors de la connexion, vérifiez votre version d'Istio. Sur une version antérieure à la 1.12, définissez h2UpgradePolicy sur DO_NOT_UPGRADE dans la règle de destination pour conserver WebSocket sur 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
Pour Istio 1.12 ou ultérieur, suivez les étapes ci-dessous.
Créer une règle de destination
Connectez-vous à la console ASM.
Dans le volet de navigation de gauche, choisissez .
Sur la page Mesh Management, recherchez l'instance ASM cible. Cliquez sur le nom de l'instance ou cliquez sur Manage dans la colonne Actions.
Dans le volet de navigation de gauche de la page des détails, choisissez . Sur la page qui s'affiche, cliquez sur Create from YAML.
-
Sélectionnez default dans la liste déroulante Namespace, collez le code YAML suivant dans l'éditeur de code, puis cliquez sur Create : La définition de
h2UpgradePolicysurUPGRADEactive HTTP/2 pour les connexions au serveur WebSocket.apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: labels: provider: asm name: websockets-server spec: host: websockets-server trafficPolicy: connectionPool: http: h2UpgradePolicy: UPGRADE
Créer un filtre Envoy
Par défaut, WebSocket ne fonctionne pas avec le protocole HTTP/2. Cependant, Envoy prend en charge le tunneling de WebSocket sur HTTP/2. Définissez le paramètre allow_connect sur true sur le sidecar côté serveur afin que le serveur WebSocket prenne en charge les connexions HTTP/2.
Connectez-vous à la console ASM.
Dans le volet de navigation de gauche, choisissez .
Sur la page Mesh Management, recherchez l'instance ASM cible. Cliquez sur le nom de l'instance ou cliquez sur Manage dans la colonne Actions.
Dans le volet de navigation de gauche de la page des détails, choisissez .
Sur la page Market Place, cliquez sur Template that sets the allow_connect parameter to true to allow updated protocol connections.
Sur la page Plugin Detail, cliquez sur l'onglet Plugin Config. Dans la section Plugin Effective scope, sélectionnez Workload Scope et cliquez sur Add workloads to effective scope.
-
Dans la boîte de dialogue Add workloads to effective scope, définissez les paramètres comme suit :
Namespace : default
Workload Type : Deployment
Dans la section Select workloads, sélectionnez websockets-server, cliquez sur l'icône
pour la déplacer vers la section selected, puis cliquez sur OK.
Dans l'éditeur de code YAML de la section Plugin Config, saisissez
patch_context: SIDECAR_INBOUND, activez Plugin Switch et attendez que le plug-in soit activé.
Une fois le plug-in activé, ASM crée automatiquement un filtre Envoy. Le code YAML généré est similaire au suivant :
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
Tester la connexion WebSocket sur HTTP/2
Exécutez la commande suivante depuis le pod client :
python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
Sortie attendue :
Connected to ws://websockets-server.default.svc.cluster.local:8080.
Saisissez hello et world pour vérifier la réponse echo :
> hello
< hello
> world
< world
Connection closed: 1000 (OK).
Vérifier la mise à niveau du protocole dans les journaux du proxy sidecar
Journaux du proxy sidecar côté client :
Sur la page Pods, cliquez sur le nom du pod client WebSocket.
Cliquez sur l'onglet Logs et sélectionnez istio-proxy dans la liste déroulante Container.
Le journal côté client affiche protocol: HTTP/1.1 car le client émet la requête en HTTP/1.1 :
{..."authority":"websockets-server.default.svc.cluster.local:8080","upstream_service_time":null,"protocol":"HTTP/1.1",...}
Journaux du proxy sidecar côté serveur :
Sur la page Pods, cliquez sur le nom du pod serveur WebSocket.
Cliquez sur l'onglet Logs et sélectionnez istio-proxy dans la liste déroulante Container.
Le journal côté serveur affiche protocol: HTTP/2, confirmant que le sidecar a mis à niveau la connexion :
{..."method":"GET","upstream_local_address":"127.0.**.**:34477","protocol":"HTTP/2",...}