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

Alibaba Cloud Service Mesh:ASM で WebSocket 接続経由でサービスにアクセスする

最終更新日:Jul 08, 2025

WebSocket は、クライアントとサーバー間の双方向通信を可能にする通信プロトコルです。WebSocket プロトコルは RFC 6455 で標準化されています。Istio サイドカープロキシは WebSocket プロトコルを標準でサポートしており、WebSocket 接続を簡単に確立することでサービスにアクセスできます。このトピックでは、Alibaba Cloud Service Mesh(ASM)で HTTP/1.1 または HTTP/2 経由で WebSocket 接続を確立してサービスにアクセスする方法について説明します。

前提条件

背景情報

WebSocket 接続は、HTTP Upgrade ヘッダーを使用して確立されます。これは、HTTP 接続を確立する方法とは異なります。Istio は WebSocket プロトコルを認識できません。ただし、Istio サイドカープロキシは WebSocket プロトコルを標準でサポートしています。Istio で WebSocket プロトコルを使用する方法の詳細については、「HTTP アップグレード」、「HTTP 接続マネージャー」、および「プロトコルの選択」をご参照ください。

HTTP/1.1 経由の WebSocket 接続と HTTP/2 経由の WebSocket 接続には、次の違いがあります。

  • HTTP/1.1 経由の WebSocket 接続: 1 つのリクエストのみを処理するために接続が確立されます。リクエストに対するレスポンスが返されると、接続は閉じられます。

  • HTTP/2 経由の WebSocket 接続: 複数のリクエストを 1 つの接続で並列処理できます。1 つのリクエストに時間がかかる場合でも、同じ接続上の他のリクエストは影響を受けません。

WebSocket クライアントと WebSocket サーバーをデプロイする

  1. kubectl を使用して ACK クラスタに接続します。詳細については、「クラスタの kubeconfig ファイルを取得し、kubectl を使用してクラスタに接続する」をご参照ください。

  2. WebSocket サーバーをデプロイします。

    この例では、WebSocket コミュニティによって提供される Python 用の WebSocket サーバーを使用します。WebSocket サーバーをデプロイするための設定を変更する方法の詳細については、「Kubernetes にデプロイする」をご参照ください。

    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
  3. WebSocket クライアントをデプロイします。

    この例では、Dockerfile を使用して WebSocket クライアントのイメージをビルドします。websockets-client.yaml ファイルには、WebSocket クライアントのイメージを使用して WebSocket クライアントをクラスタにデプロイするための設定が含まれています。

    FROM python:3.9-alpine
    RUN pip3 install websockets
    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

HTTP/1.1 経由で WebSocket 接続を確立する

WebSocket クライアントが 1 つの接続で WebSocket サーバーに複数のリクエストを送信した場合でも、サイドカープロキシのログには、WebSocket 接続のアクセスログエントリが 1 つだけ含まれます。Envoy は WebSocket 接続を TCP バイトストリームとして扱い、HTTP Upgrade ヘッダーを含むリクエストとレスポンスのみを認識できます。そのため、Envoy は接続が閉じられた後にのみアクセスログエントリを生成します。また、ログエントリには各 TCP リクエストの詳細は含まれていません。

  1. 次のいずれかの方法を使用して CLI シェルを開きます。

    • 方法 1:

      1. ACK コンソール にログインします。左側のナビゲーションペインで、[クラスタ] をクリックします。

      2. [クラスタ] ページで、管理するクラスタを見つけて、その名前をクリックします。左側のペインで、[ワークロード] > [ポッド] を選択します。

      3. [ポッド] ページで websockets-client を見つけ、[アクション] 列の [ターミナル] をクリックします。次に、[websockets-client] をクリックします。

    • 方法 2:

      次のコマンドを実行して CLI シェルを開きます。

      kubectl exec -it -n <namespace> websockets-client-sleep...  -c websockets-client -- sh
  2. 次のコマンドを実行して WebSocket サーバーにアクセスします。

    python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080

    期待される出力:

    Connected to ws://websockets-server.default.svc.cluster.local:8080.

    「hello」と「world」と入力すると、2 つの単語が期待どおりに返されます。

    > hello
    < hello
    > world
    < world
    Connection closed: 1000 (OK).
  3. サイドカープロキシのログをクエリします。

    • WebSocket クライアントのサイドカープロキシのログをクエリします。

      1. [ポッド] ページで、WebSocket クライアントのコンテナの名前をクリックします。

      2. [ログ] タブをクリックし、[コンテナ] ドロップダウンリストから [istio-proxy] を選択します。

        ログに HTTP/1.1 経由の WebSocket 接続に関するエントリが含まれていることがわかります。

        {...."upstream_host":"10.208.0.105:80","bytes_sent":23,"protocol":"HTTP/1.1",....}
    • WebSocket サーバーのサイドカープロキシのログをクエリします。

      1. [ポッド] ページで、WebSocket サーバーのコンテナの名前をクリックします。

      2. [ログ] タブをクリックし、[コンテナ] ドロップダウンリストから [istio-proxy] を選択します。

        ログに HTTP/1.1 経由の WebSocket 接続に関するエントリが含まれていることがわかります。

        {...."downstream_local_address":"10.208.0.105:80","upstream_local_address":"127.0.**.**:53983","protocol":"HTTP/1.1",....}

HTTP/2 経由で WebSocket 接続を確立する

1.12 より前のバージョンの Istio を使用している場合、HTTP/1.1 接続を HTTP/2 接続にアップグレードすることで WebSocket サーバーに WebSocket 接続を確立することはできません。この場合、HTTP ステータスコード 503 が返されます。

1.12 より前のバージョンの Istio の場合、宛先ルールで h2UpgradePolicyDO_NOT_UPGRADE に設定します。こうすることで、HTTP/1.1 接続は HTTP/2 にアップグレードされず、HTTP/1.1 を使用して WebSocket サーバーに WebSocket 接続を正常に確立できます。

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 以降を使用している場合は、次の手順を実行して HTTP/2 を使用して WebSocket 接続を確立できます。

  1. 宛先ルールを作成します。

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

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

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

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

    5. 作成ページで、既定[名前空間] ドロップダウンリストから 作成 を選択し、次の内容をコードエディタにコピーします。次に、 をクリックします。

      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 の値は、WebSocket サーバーで HTTP/2 が有効になっていることを示します。

  2. Envoy フィルタを作成します。

    デフォルトでは、WebSocket は HTTP/2 プロトコルでは機能しません。ただし、Envoy は HTTP/2 経由の WebSocket のトンネリングをサポートしています。こうすることで、ASM インスタンス内のすべての通信を HTTP/2 経由で実行できます。宛先ワークロードの Envoy フィルタの allow_connect パラメータを true に設定できます。その後、HTTP/2 接続は WebSocket サーバーでサポートされます。

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

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

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

    4. ASM インスタンスの詳細ページで、左側のナビゲーションペインの [プラグイン拡張センター] > [マーケットプレイス] を選択します。

    5. [マーケットプレイス] ページで、[allow_connect パラメータを True に設定して更新されたプロトコル接続を許可するテンプレート] をクリックします。

    6. [プラグインの詳細] ページで、[プラグイン設定] タブをクリックします。[プラグインの有効範囲] セクションで、[ワークロードのスコープ] を選択し、[有効範囲にワークロードを追加] をクリックします。

    7. [有効範囲にワークロードを追加] ダイアログボックスで、[名前空間] パラメータを [default] に、[ワークロードタイプ][デプロイメント] に設定します。[ワークロードを選択] セクションで、[websockets-server] を選択し、Add icon アイコンをクリックして [websockets-server][選択済み] セクションに追加し、[OK] をクリックします。

    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」と「world」と入力すると、2 つの単語が期待どおりに返されます。

    > hello
    < hello
    > world
    < world
    Connection closed: 1000 (OK).
  4. サイドカープロキシのログをクエリします。

    • WebSocket クライアントのサイドカープロキシのログをクエリします。

      1. [ポッド] ページで、WebSocket クライアントのコンテナの名前をクリックします。

      2. [ログ] タブをクリックし、[コンテナ] ドロップダウンリストから [istio-proxy] を選択します。

        ログに HTTP/1.1 経由の WebSocket 接続に関するエントリが含まれていることがわかります。これは、WebSocket クライアントが HTTP/1.1 を使用してリクエストを送信していることを示します。

        {...."authority":"websockets-server.default.svc.cluster.local:8080","upstream_service_time":null,"protocol":"HTTP/1.1",....}
    • WebSocket サーバーのサイドカープロキシのログをクエリします。

      1. [ポッド] ページで、WebSocket サーバーのコンテナの名前をクリックします。

      2. [ログ] タブをクリックし、[コンテナ] ドロップダウンリストから [istio-proxy] を選択します。

        ログに HTTP/2 経由の WebSocket 接続に関するエントリが含まれていることがわかります。これは、WebSocket サーバーがプロトコルが HTTP/2 にアップグレードされたリクエストを受信していることを示します。

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