すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Service Mesh:WebSocketが無効になっている場合の予期しないリターンコードの問題を解決する

最終更新日:Jan 15, 2025

WebSocketが無効になっているGoogle Chromeを使用して、Istioサイドカーインジェクションが有効になっている名前空間にデプロイされているアプリケーションにアクセスすると、レスポンスは "wasclean": false で、リターンコードは 1006 になります。これは、デフォルトまたはカスタムのリターンコードと一致しません。ただし、FirefoxまたはSafariを使用している場合は、この状況は発生しません。このトピックでは、Envoyフィルターを使用してこの問題を解決する方法について説明します。

前提条件

手順 1:サンプルアプリケーションをデプロイする

Alibaba Cloudイメージを使用するか、Dockerイメージをビルドしてアプリケーションをデプロイできます。次の操作を実行します。

方法 1:alibaba Cloudイメージを使用してアプリケーションをデプロイする

  1. 次の内容を含む sample.yaml ファイルを作成します。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: websocket-test
      namespace: default
      labels:
        app: websocket-test
        version: current
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: websocket-test
          version: current
      template:
        metadata:
          labels:
            app: websocket-test
            version: current
        spec:
          containers:
          - name: websocket-test
            image: registry.cn-hangzhou.aliyuncs.com/aliacs-app-catalog/asm-websocketsample:v1
            imagePullPolicy: Always
            command: ["node", "ws.js"]
    
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: websocket-test
      name: websocket-test
      namespace: default
    spec:
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 9900
      selector:
        app: websocket-test
      type: ClusterIP
  2. 次のコマンドを実行して、default名前空間のWebSocketサーバーにアプリケーションをデプロイします。
    default名前空間に対して自動サイドカーインジェクションを有効にする必要があります。詳細については、「自動サイドカープロキシインジェクションを有効にする」をご参照ください。
    kubectl apply -f sample.yaml

方法 2:dockerイメージをビルドしてアプリケーションをデプロイする

  1. 次の内容を含む package.json ファイルを作成します。この例では、Node.jsアプリケーションを使用しています。
    {
      "name": "wssample",
      "version": "0.0.1",
      "main": "ws.js",
      "license": "UNLICENSED",
      "scripts": {
        "start": "node --trace-warnings ./ws.js"
      },
      "dependencies": {
        "ws": "^8.0.0"
      }
    }
  2. 次のコードを実行して、WebSocketサーバーにアプリケーションをデプロイします。
    const WebSocket = require("ws");
    const http = require("http");
    const wss = new WebSocket.Server({ noServer: true });
    
    const server = http.createServer()
    
    
    server.on("upgrade", async (request, socket, head) => {
      const handleAuth = (ws) => {
        wss.emit("connection", ws, request);
      };
      wss.handleUpgrade(request, socket, head, handleAuth);
    })
    
    wss.on("connection", (conn, req) => {
      // デフォルトでは、1005 が返されます。サイドカーインジェクションが有効になっている場合は、1006 が返されます。
      // conn.close()
      // カスタムリターンコードは 4321 です。
      // ただし、サイドカーインジェクションが有効になっている場合は、1006 が返されます。
      // サイドカーインジェクションが有効になっていない場合は、4321 が返されます。
      conn.close(4321, "test")
    
    });
    
    server.listen({ host: '0.0.0.0', port: 9900 });
    
                            
  3. 次の内容を含むDockerイメージファイルを作成します。
    FROM node:16.7.0-alpine3.14
    WORKDIR /root/app
    COPY . .
    RUN yarn install

手順 2:ASMインスタンスを構成する

  1. ASMコンソールにログインします。

  2. 左側のナビゲーションペインで、[サービスメッシュ] > [メッシュ管理] を選択します。

  3. [メッシュ管理] ページで、構成する ASM インスタンスを見つけます。[管理] 列の ASM インスタンス名をクリックするか、[アクション] をクリックします。

  4. ゲートウェイを作成します。
    1. ASMインスタンスの詳細ページで、左側のナビゲーションペインの [ASMゲートウェイ] > [ゲートウェイ] を選択します。表示されるページで、[YAMLから作成] をクリックします。

    2. [名前空間][default] に設定し、シナリオテンプレートを選択し、次の内容を [YAML] エディターボックスに貼り付けて、[作成] をクリックします。
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: websocket-test
        namespace: default
      spec:
        selector:
          istio: ingressgateway
        servers:
          - hosts:
              - '*'
            port:
              name: http
              number: 80
              protocol: HTTP
  5. デスティネーションルールを作成します。
    1. ASMインスタンスの詳細ページで、左側のナビゲーションペインの [トラフィック管理センター] > [destinationrule] を選択します。表示されるページで、[YAMLから作成] をクリックします。

    2. [名前空間][default] に設定し、シナリオテンプレートを選択し、次の内容を [YAML] エディターボックスに貼り付けて、[作成] をクリックします。
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: websocket-test
        namespace: default
      spec:
        host: websocket-test
        subsets:
        - name: current
          labels:
            version: current
  6. 仮想サービスを作成します。
    1. ASMインスタンスの詳細ページで、左側のナビゲーションペインの [トラフィック管理センター] > [virtualservice] を選択します。表示されるページで、[YAMLから作成] をクリックします。

    2. [名前空間][default] に設定し、シナリオテンプレートを選択し、次の内容を [YAML] エディターボックスに貼り付けて、[作成] をクリックします。
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: websocket-test
        namespace: default
      spec:
        gateways:
        - websocket-test
        hosts:
        - '*'
        http:
        - name: default
          route:
          - destination:
              host: websocket-test
              subset: current

手順 3:WebSocketサーバー上のアプリケーションにアクセスする

WebSocketサーバー上のアプリケーションに直接アクセスするか、Envoyフィルターを使用してアクセスできます。このトピックでは、2つの方法を比較します。アクセスが成功した場合、この例ではカスタムコード 4321 が返されます。

方法 1:websocketサーバー上のアプリケーションに直接アクセスする

  1. 次の内容を含む client.html ファイルを作成します。
    サンプルYAMLファイルのイングレスゲートウェイのIPアドレスを使用しているイングレスゲートウェイのIPアドレスに置き換えます。
    <!DOCTYPE html>
    <html>
    
    <head>
        <title>WebSocket example</title>
    
    </head>
    
    <body>
    
        <script>
            var ws=new WebSocket('ws://{イングレスゲートウェイの IP アドレス}');
    
            ws.onopen = function (ev) {
                console.log(ev)
            };
            ws.onmessage = function (ev) {
                console.log("on msg", ev)
            };
            ws.onclose = function (ev) {
                console.log("on close", ev)
            };
            ws.onerror = function (ev) {
                console.log("on error", ev)
            };
    
        </script>
    </body>
    
    </html>
  2. Google Chromeを使用して client.html ファイルを開き、キーボードのF12キーを押してデベロッパーツールを開きます。
  3. ページを更新します。[コンソール] タブで、リターンコードを確認します。
    次の図に示すように、リターンコードはカスタムリターンコード 4321 ではなく 1006 です。1006

方法 2:envoyフィルターを使用してwebsocketサーバー上のアプリケーションにアクセスする

  1. 次の内容を含むEnvoyフィルターを作成します。
    apiVersion: networking.istio.io/v1alpha3
    kind: EnvoyFilter
    metadata:
      labels:
        asm-system: 'true'
        provider: asm
      name: hack-to-fix-delayedclosetimeout-istio-upper-version
      namespace: istio-system
    spec:
      configPatches:
        - applyTo: NETWORK_FILTER
          match:
            listener:
              filterChain:
                filter:
                  name: envoy.filters.network.http_connection_manager
            proxy:
              proxyVersion: ^1.*.*
          patch:
            operation: MERGE
            value:
              typed_config:
                '@type': >-
                  type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                delayed_close_timeout: 0s
                    
  2. Envoyフィルターを指定されたワークロードまたは名前空間にバインドします。詳細については、「手順 2:Envoyフィルターテンプレートをワークロードまたは名前空間にバインドする」をご参照ください。
  3. Google Chromeを使用して client.html ファイルを開き、キーボードのF12キーを押してデベロッパーツールを開きます。
  4. ページを更新します。[コンソール] タブで、リターンコードを確認します。
    次の図に示すように、リターンコードは 4321 で、期待どおりです。したがって、Envoyフィルターを使用して、不整合なリターンコードの問題を解決できます。4321