WebSocketが無効になっているGoogle Chromeを使用して、Istioサイドカーインジェクションが有効になっている名前空間にデプロイされているアプリケーションにアクセスすると、レスポンスは "wasclean": false
で、リターンコードは 1006
になります。これは、デフォルトまたはカスタムのリターンコードと一致しません。ただし、FirefoxまたはSafariを使用している場合は、この状況は発生しません。このトピックでは、Envoyフィルターを使用してこの問題を解決する方法について説明します。
前提条件
ACKマネージドクラスターが作成されていること。詳細については、「ACKマネージドクラスターを作成する」をご参照ください。
Service Mesh(ASM)インスタンスが作成されていること。ACKクラスターがASMインスタンスに追加されていること。詳細については、「ASMインスタンスを作成する」および「ASMインスタンスにクラスターを追加する」をご参照ください。
- 少なくとも1つのイングレスゲートウェイサービスがデプロイされていること。詳細については、「イングレスゲートウェイを作成する」をご参照ください。
ASMインスタンスに追加されたクラスターにアプリケーションがデプロイされていること。詳細については、「ASMインスタンスに追加されたACKクラスターにアプリケーションをデプロイする」をご参照ください。
- kubectlを使用してACKクラスターおよびASMインスタンスに接続していること。詳細については、「kubectlを使用してACKクラスターに接続する」および「コントロールプレーンでkubectlを使用してIstioリソースにアクセスする」をご参照ください。
手順 1:サンプルアプリケーションをデプロイする
Alibaba Cloudイメージを使用するか、Dockerイメージをビルドしてアプリケーションをデプロイできます。次の操作を実行します。方法 1:alibaba Cloudイメージを使用してアプリケーションをデプロイする
- 次の内容を含む 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
- 次のコマンドを実行して、default名前空間のWebSocketサーバーにアプリケーションをデプロイします。default名前空間に対して自動サイドカーインジェクションを有効にする必要があります。詳細については、「自動サイドカープロキシインジェクションを有効にする」をご参照ください。
kubectl apply -f sample.yaml
方法 2:dockerイメージをビルドしてアプリケーションをデプロイする
- 次の内容を含む 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" } }
- 次のコードを実行して、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 });
- 次の内容を含むDockerイメージファイルを作成します。
FROM node:16.7.0-alpine3.14 WORKDIR /root/app COPY . . RUN yarn install
手順 2:ASMインスタンスを構成する
ASMコンソールにログインします。
左側のナビゲーションペインで、 を選択します。
[メッシュ管理] ページで、構成する ASM インスタンスを見つけます。[管理] 列の ASM インスタンス名をクリックするか、[アクション] をクリックします。
- ゲートウェイを作成します。
ASMインスタンスの詳細ページで、左側のナビゲーションペインの を選択します。表示されるページで、[YAMLから作成] をクリックします。
- [名前空間] を [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
- デスティネーションルールを作成します。
ASMインスタンスの詳細ページで、左側のナビゲーションペインの を選択します。表示されるページで、[YAMLから作成] をクリックします。
- [名前空間] を [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
- 仮想サービスを作成します。
ASMインスタンスの詳細ページで、左側のナビゲーションペインの を選択します。表示されるページで、[YAMLから作成] をクリックします。
- [名前空間] を [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サーバー上のアプリケーションに直接アクセスする
- 次の内容を含む 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>
- Google Chromeを使用して client.html ファイルを開き、キーボードのF12キーを押してデベロッパーツールを開きます。
- ページを更新します。[コンソール] タブで、リターンコードを確認します。次の図に示すように、リターンコードはカスタムリターンコード 4321 ではなく 1006 です。
方法 2:envoyフィルターを使用してwebsocketサーバー上のアプリケーションにアクセスする
- 次の内容を含む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
- Envoyフィルターを指定されたワークロードまたは名前空間にバインドします。詳細については、「手順 2:Envoyフィルターテンプレートをワークロードまたは名前空間にバインドする」をご参照ください。
- Google Chromeを使用して client.html ファイルを開き、キーボードのF12キーを押してデベロッパーツールを開きます。
- ページを更新します。[コンソール] タブで、リターンコードを確認します。次の図に示すように、リターンコードは 4321 で、期待どおりです。したがって、Envoyフィルターを使用して、不整合なリターンコードの問題を解決できます。