全部產品
Search
文件中心

Alibaba Cloud Service Mesh:在ASM中使用WebSocket協議訪問服務

更新時間:Jul 31, 2024

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 upgradesHTTP connection managerProtocol Selection

您可以在ASM中使用WebSocket over HTTP/1.1和HTTP/2協議訪問服務,區別如下:

  • WebSocket over HTTP/1.1協議:一次請求和響應,建立一個串連,用完關閉串連。

  • WebSocket over HTTP/2協議:多個請求可同時在一個串連上並存執行,某個請求任務耗時嚴重,不會影響到其它串連的正常執行。

前提條件

部署WebSocket用戶端和服務端

  1. 部署WebSocket服務端。

    說明

    本文使用WebSocket社區提供的Python庫中WebSocket服務端為例。如果您想修改WebSocket服務端的部署配置,請參見容器化應用程式

    1. 使用以下內容,建立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
    2. 執行以下命令,在default命名空間下部署WebSocket服務端。

      kubectl apply -f websockets-server.yaml -n default
  2. 部署WebSocket用戶端。

    1. 使用以下內容,建立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"]
    2. 在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請求的任何訊息。

  1. 任選以下方式,開啟Shell命令列視窗。

    • 方式一:

      1. 登入Container Service管理主控台,在左側導覽列單擊叢集

      2. 叢集列表頁面,單擊目的地組群名稱,然後在左側導覽列,選擇工作負載 > 容器組

      3. 容器組頁面單擊websockets-client右側操作列下終端,單擊websockets-client

    • 方式二:

      執行以下命令,開啟Shell命令列視窗。

      kubectl exec -it -n <namespace> websockets-client-sleep...  -c websockets-client -- sh
  2. 執行以下命令,訪問WebSocket服務端。

    python3 -m websockets ws://websockets-server.default.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).
  3. 查看Sidecar Proxy日誌。

    • 查看WebSocket用戶端的Sidecar Proxy日誌。

      1. 容器組頁面單擊WebSocket用戶端容器名稱。

      2. 單擊日誌頁簽,設定容器istio-proxy

        可以看到日誌中包含使用WebSocket over HTTP/1.1協議記錄。

        {...."upstream_host":"10.208.0.105:80","bytes_sent":23,"protocol":"HTTP/1.1",....}
    • 查看WebSocket服務端的Sidecar Proxy日誌。

      1. 容器組頁面單擊WebSocket服務端容器名稱。

      2. 單擊日誌頁簽,設定容器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升級,並發生報錯,您可以通過在目標規則中定義h2UpgradePolicyDO_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協議的操作如下:

  1. 建立目標規則。

    1. 登入ASM控制台

    2. 在左側導覽列,選擇服務網格 > 網格管理

    3. 網格管理頁面,找到待配置的執行個體,單擊執行個體的名稱或在操作列中單擊管理

    4. 在網格詳情頁面左側導覽列,選擇流量管理中心 > 目標規則,然後在右側頁面,單擊使用YAML建立

    5. 設定命名空間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協議。

  2. 建立EnvoyFilter。

    預設情況下,WebSocket不支援HTTP/2協議,但Envoy卻支援WebSocket在HTTP/2流上進行隧道傳輸,以便在整個部署過程中可以使用統一的HTTP/2網路。您可以通過EnvoyFilter針對目標工作負載設定allow_connect: true,從而使WebSocket服務端允許HTTP/2協議串連。

    1. 登入ASM控制台

    2. 在左側導覽列,選擇服務網格 > 網格管理

    3. 網格管理頁面,找到待配置的執行個體,單擊執行個體的名稱或在操作列中單擊管理

    4. 在網格詳情頁面左側導覽列選擇外掛程式擴充中心 > 外掛程式市場

    5. 外掛程式市場頁面,單擊設定allow_connect為true允許升級的協議串連

    6. 外掛程式詳情頁面,單擊建立外掛程式執行個體頁簽,在外掛程式生效範圍地區,選中工作負載生效,然後單擊添加工作負載到生效範圍

    7. 添加工作負載到生效範圍對話方塊中,設定命名空間default工作負載類型Deployment,在選擇負載地區選中websockets-server,單擊添加表徵圖,將websockets-server添加到已選擇地區中,然後單擊確定

    8. 外掛程式配置地區的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
  3. 執行以下命令,訪問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).
  4. 查看Sidecar Proxy日誌。

    • 查看WebSocket用戶端的Sidecar Proxy日誌。

      1. 容器組頁面單擊WebSocket用戶端容器名稱。

      2. 單擊日誌頁簽,設定容器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日誌。

      1. 容器組頁面單擊WebSocket服務端容器名稱。

      2. 單擊日誌頁簽,設定容器istio-proxy

        可以看到日誌中包含使用WebSocket over HTTP/2協議記錄,說明WebSocket服務端的接收到的協議已經升級為HTTP/2。

        {...."method":"GET","upstream_local_address":"127.0.**.**:34477","protocol":"HTTP/2",....}