Kubernetes で WebSocket:Ingress(NGINX/ALB) 設定とスティッキーセッションの実装手順
Kubernetes 環境で WebSocket を使ったリアルタイム通信を実装する際、Ingress の設定で躓いた経験はありませんか?
WebSocket は HTTP とは異なる特性を持つため、適切な設定を行わないと接続が切断されたり、セッションが維持できなかったりする問題が発生します。特に Kubernetes のような分散環境では、複数の Pod 間でのセッション管理が課題となるでしょう。
本記事では、NGINX Ingress と AWS ALB Ingress の両方における WebSocket 設定と、スティッキーセッションの実装手順を詳しく解説します。実際の YAML ファイルやコード例を交えながら、初心者の方でも実装できるように段階的に説明していきますね。
背景
WebSocket とは
WebSocket は、クライアントとサーバー間で双方向のリアルタイム通信を可能にするプロトコルです。
従来の HTTP 通信では、クライアントがリクエストを送信し、サーバーがレスポンスを返すという一方向の通信でした。しかし、WebSocket を使うことで、一度接続を確立すれば、サーバーからクライアントへ自発的にデータを送信できるようになります。
| # | 項目 | HTTP | WebSocket |
|---|---|---|---|
| 1 | 通信方向 | 単方向(リクエスト → レスポンス) | 双方向(相互通信) |
| 2 | 接続維持 | 都度切断 | 長時間接続 |
| 3 | オーバーヘッド | 大きい(毎回ヘッダー送信) | 小さい(初回のみ) |
| 4 | リアルタイム性 | 低い(ポーリング必要) | 高い(即座に送信) |
| 5 | 用途例 | Web ページ表示、API 呼び出し | チャット、通知、ゲーム |
Kubernetes における WebSocket の課題
Kubernetes 環境では、複数の Pod がロードバランサーの背後に配置されます。
WebSocket は長時間接続を維持する必要があるため、通常の HTTP トラフィックとは異なる考慮が必要になるんです。特に、Ingress を経由する場合、適切な設定を行わないと接続が予期せず切断されてしまいます。
以下の図で、Kubernetes における WebSocket 通信の基本的な流れを確認しましょう。
mermaidflowchart LR
client["クライアント<br/>(ブラウザ)"] -->|"1. WebSocket接続要求<br/>(HTTP Upgrade)"| ingress["Ingress<br/>(NGINX/ALB)"]
ingress -->|"2. 接続振り分け"| pod1["Pod 1<br/>(WebSocketサーバー)"]
ingress -.->|"振り分け候補"| pod2["Pod 2<br/>(WebSocketサーバー)"]
ingress -.->|"振り分け候補"| pod3["Pod 3<br/>(WebSocketサーバー)"]
pod1 -->|"3. 双方向通信<br/>(長時間接続)"| ingress
ingress -->|"4. データ転送"| client
図で理解できる要点:
- クライアントは HTTP Upgrade リクエストで WebSocket 接続を開始する
- Ingress が複数の Pod から 1 つを選択して接続を確立する
- 確立後は同じ Pod との間で双方向通信が継続される
課題
接続の切断問題
Kubernetes で WebSocket を使う際、最も頻繁に遭遇するのが「接続が突然切断される」という問題です。
この問題は主に以下の原因で発生します。
- タイムアウト設定が短すぎる:Ingress やロードバランサーのアイドルタイムアウトが短いと、通信が発生しない時間が続いた際に接続が切られてしまいます。
- HTTP Upgrade ヘッダーが正しく処理されない:WebSocket は HTTP から WebSocket プロトコルへの「アップグレード」を行いますが、この処理が適切に設定されていないと接続に失敗するでしょう。
- プロキシのバッファリング:一部のプロキシは応答をバッファリングするため、リアルタイム性が損なわれます。
セッションアフィニティの必要性
WebSocket 接続では、クライアントが常に同じ Pod に接続し続ける必要があります。
なぜなら、WebSocket のセッション状態(接続情報、メッセージ履歴など)は各 Pod のメモリ内に保持されるため、接続先の Pod が変わってしまうとセッションが失われてしまうからです。
以下の図で、スティッキーセッションがない場合の問題を可視化しました。
mermaidsequenceDiagram
participant Client as クライアント
participant Ingress as Ingress
participant Pod1 as Pod 1
participant Pod2 as Pod 2
Client->>Ingress: 初回接続要求
Ingress->>Pod1: 接続確立
Pod1->>Pod1: セッション作成(メモリ)
Pod1-->>Client: 接続成功
Note over Client,Pod1: 一定時間通信
Client->>Ingress: 再接続要求
Ingress->>Pod2: 別Podへ振り分け
Pod2->>Pod2: セッション情報なし❌
Pod2-->>Client: セッションエラー
図で理解できる要点:
- スティッキーセッションがないと、再接続時に別の Pod へ振り分けられる可能性がある
- 新しい Pod にはセッション情報が存在しないため、エラーが発生する
- 一貫した接続先を維持する仕組みが必要
NGINX Ingress と ALB Ingress の違い
Kubernetes では、Ingress Controller として様々な選択肢があります。
特に一般的なのが NGINX Ingress と AWS ALB Ingress ですが、それぞれ設定方法や機能が異なるため、環境に応じた適切な設定が必要になりますね。
| # | 項目 | NGINX Ingress | AWS ALB Ingress |
|---|---|---|---|
| 1 | 提供元 | Kubernetes コミュニティ | AWS |
| 2 | 動作場所 | クラスタ内 Pod | AWS マネージドサービス |
| 3 | 設定方法 | Annotation | Annotation + TargetGroup |
| 4 | スティッキーセッション | Cookie ベース | TargetGroup 設定 |
| 5 | タイムアウト設定 | ConfigMap / Annotation | Annotation |
| 6 | 適用環境 | あらゆる環境 | AWS EKS 専用 |
解決策
NGINX Ingress での WebSocket 設定
NGINX Ingress で WebSocket を有効にするには、いくつかの Annotation を追加する必要があります。
これらの設定により、HTTP から WebSocket へのアップグレードが正しく処理され、長時間接続が維持されるようになるんです。
以下の図で、NGINX Ingress における WebSocket 処理の流れを確認しましょう。
mermaidflowchart TB
request["HTTP Upgradeリクエスト"] --> nginx["NGINX Ingress"]
nginx --> check1{"Upgrade<br/>ヘッダー<br/>確認"}
check1 -->|"存在する"| upgrade["WebSocket<br/>プロトコルへ<br/>アップグレード"]
check1 -->|"存在しない"| http["通常のHTTP<br/>処理"]
upgrade --> sticky{"スティッキー<br/>セッション<br/>設定"}
sticky -->|"有効"| cookie["Cookie発行<br/>(route)"]
sticky -->|"無効"| random["ランダムに<br/>Pod選択"]
cookie --> pod_select["同一Podへ<br/>接続維持"]
random --> pod_random["毎回異なる<br/>Podの可能性"]
pod_select --> success["接続成功✓"]
pod_random --> fail["セッション<br/>エラー❌"]
http --> success
図で理解できる要点:
- NGINX は Upgrade ヘッダーの有無で処理を分岐する
- スティッキーセッションが有効な場合、Cookie で接続先を記憶する
- 適切な設定がないとセッションエラーが発生する
基本的な Annotation の設定
まず、WebSocket 接続を有効にするための基本的な Annotation を見ていきましょう。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# WebSocket 接続を有効化
nginx.ingress.kubernetes.io/proxy-read-timeout: '3600'
nginx.ingress.kubernetes.io/proxy-send-timeout: '3600'
これらのタイムアウト設定は秒単位で指定します。3600 秒(1 時間)に設定することで、長時間のアイドル状態でも接続が切断されにくくなりますね。
HTTP Upgrade ヘッダーの処理
WebSocket は HTTP から WebSocket プロトコルへの「アップグレード」を必要とします。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# WebSocket の Upgrade ヘッダーを適切に処理
nginx.ingress.kubernetes.io/websocket-services: 'websocket-service'
この設定により、NGINX は指定されたサービスへの接続時に WebSocket プロトコルへのアップグレードを自動的に処理してくれます。
スティッキーセッションの実装
同じクライアントを常に同じ Pod に接続させるには、スティッキーセッション(アフィニティ)の設定が必要です。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# スティッキーセッションを有効化
nginx.ingress.kubernetes.io/affinity: 'cookie'
# Cookie の名前を指定
nginx.ingress.kubernetes.io/session-cookie-name: 'route'
# Cookie の有効期限(秒)
nginx.ingress.kubernetes.io/session-cookie-max-age: '3600'
この設定により、NGINX は「route」という名前の Cookie を発行し、その Cookie を持つクライアントを常に同じ Pod に振り分けるようになります。
バッファリングの無効化
リアルタイム性を確保するため、プロキシのバッファリングを無効にしましょう。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# レスポンスのバッファリングを無効化
nginx.ingress.kubernetes.io/proxy-buffering: 'off'
# リクエストのバッファリングを無効化
nginx.ingress.kubernetes.io/proxy-request-buffering: 'off'
バッファリングを無効にすることで、メッセージが即座にクライアントへ届くようになり、リアルタイム性が向上します。
AWS ALB Ingress での WebSocket 設定
AWS ALB Ingress を使う場合は、NGINX とは異なる設定方法を使います。
ALB は AWS のマネージドロードバランサーであるため、一部の設定は AWS の機能を直接活用する形になるんです。
基本的な Annotation の設定
ALB で WebSocket を有効にする基本設定を見ていきましょう。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# ALB Ingress Controller を使用
kubernetes.io/ingress.class: alb
# インターネット向け ALB を作成
alb.ingress.kubernetes.io/scheme: internet-facing
これらは ALB Ingress を使用するための基本的な設定です。
ターゲットタイプの指定
ALB がバックエンドの Pod にどのように接続するかを指定します。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# IP モードでターゲットを指定(Pod の IP に直接接続)
alb.ingress.kubernetes.io/target-type: ip
ip モードを指定することで、ALB が Pod の IP アドレスに直接接続するため、より効率的な通信が可能になります。
アイドルタイムアウトの設定
ALB のアイドルタイムアウトを長めに設定することで、WebSocket 接続が維持されやすくなります。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# アイドルタイムアウトを 3600 秒(1 時間)に設定
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=3600
この設定により、1 時間までアイドル状態が続いても接続が切断されません。
スティッキーセッションの設定
ALB でスティッキーセッションを有効にするには、TargetGroup の設定を行います。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# スティッキーセッションを有効化
alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true,stickiness.lb_cookie.duration_seconds=3600
この設定により、ALB が発行する Cookie を使って同じターゲット(Pod)への接続が維持されるようになりますね。
ヘルスチェックの設定
WebSocket サービスに対して適切なヘルスチェックを設定することも重要です。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: websocket-ingress
annotations:
# ヘルスチェックのパス
alb.ingress.kubernetes.io/healthcheck-path: /health
# ヘルスチェックのプロトコル
alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
# ヘルスチェックの間隔(秒)
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '30'
ヘルスチェックを適切に設定することで、異常な Pod へのトラフィック振り分けを防げます。
具体例
NGINX Ingress の完全な設定例
実際のプロダクション環境で使用できる、NGINX Ingress の完全な設定例を見ていきましょう。
この例では、チャットアプリケーションを想定して、WebSocket サーバーと通常の HTTP API サーバーを組み合わせた構成を示します。
Service の定義
まず、WebSocket サーバーを公開するための Service を定義しましょう。
yamlapiVersion: v1
kind: Service
metadata:
name: websocket-service
labels:
app: chat-server
spec:
# ClusterIP タイプで内部公開
type: ClusterIP
ports:
# WebSocket 接続用のポート
- port: 8080
targetPort: 8080
protocol: TCP
name: websocket
selector:
# Pod のラベルと一致させる
app: chat-server
Service は ClusterIP タイプで作成し、Ingress を経由してのみアクセス可能にします。
Deployment の定義
次に、WebSocket サーバーを実行する Pod の定義です。
yamlapiVersion: apps/v1
kind: Deployment
metadata:
name: chat-server
spec:
# 3 つの Pod を起動
replicas: 3
selector:
matchLabels:
app: chat-server
template:
metadata:
labels:
app: chat-server
spec:
containers:
- name: chat-server
# WebSocket サーバーのイメージ
image: your-registry/chat-server:latest
ports:
# コンテナのポート
- containerPort: 8080
name: websocket
この例では 3 つのレプリカを起動し、負荷分散とスティッキーセッションの動作を確認できるようにしています。
Ingress の完全な定義
すべての設定を組み合わせた Ingress の定義を見てみましょう。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: chat-ingress
annotations:
# タイムアウト設定(1 時間)
nginx.ingress.kubernetes.io/proxy-read-timeout: '3600'
nginx.ingress.kubernetes.io/proxy-send-timeout: '3600'
nginx.ingress.kubernetes.io/proxy-connect-timeout: '60'
# WebSocket の有効化
nginx.ingress.kubernetes.io/websocket-services: 'websocket-service'
# スティッキーセッション設定
nginx.ingress.kubernetes.io/affinity: 'cookie'
nginx.ingress.kubernetes.io/session-cookie-name: 'chat_route'
nginx.ingress.kubernetes.io/session-cookie-max-age: '3600'
nginx.ingress.kubernetes.io/session-cookie-path: '/'
nginx.ingress.kubernetes.io/session-cookie-secure: 'true'
nginx.ingress.kubernetes.io/session-cookie-samesite: 'Lax'
Cookie に関する詳細な設定により、セキュリティとセッション管理の両立を実現しています。
yaml # バッファリング無効化
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
# 大きなヘッダーサイズを許可
nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"
spec:
ingressClassName: nginx
rules:
- host: chat.example.com
http:
paths:
# WebSocket エンドポイント
- path: /ws
pathType: Prefix
backend:
service:
name: websocket-service
port:
number: 8080
この設定により、chat.example.com/ws へのアクセスが WebSocket サーバーにルーティングされます。
TLS の追加設定
HTTPS/WSS 接続を使う場合の TLS 設定も追加しましょう。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: chat-ingress
annotations:
# 前述の annotations に加えて
# HTTPS へのリダイレクト
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
# HTTP/2 の有効化
nginx.ingress.kubernetes.io/http2-push-preload: 'true'
spec:
ingressClassName: nginx
# TLS 証明書の設定
tls:
- hosts:
- chat.example.com
# Secret に保存された証明書を参照
secretName: chat-tls-secret
rules:
- host: chat.example.com
http:
paths:
- path: /ws
pathType: Prefix
backend:
service:
name: websocket-service
port:
number: 8080
TLS を設定することで、暗号化された安全な WebSocket 接続(WSS)が利用できるようになりますね。
AWS ALB Ingress の完全な設定例
AWS EKS 環境で ALB Ingress を使った WebSocket 設定の完全な例を見ていきます。
Service の定義(ALB 用)
ALB Ingress でも基本的な Service 定義は同じです。
yamlapiVersion: v1
kind: Service
metadata:
name: websocket-service
labels:
app: realtime-server
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
protocol: TCP
selector:
app: realtime-server
ALB の場合、ターゲットタイプを ip にする場合でも、Service のタイプは NodePort または ClusterIP で問題ありません。
Ingress の完全な定義(ALB)
すべての ALB 設定を含んだ Ingress リソースです。
yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: realtime-ingress
annotations:
# ALB Ingress Controller の指定
kubernetes.io/ingress.class: alb
# インターネット向け ALB
alb.ingress.kubernetes.io/scheme: internet-facing
# ターゲットタイプ(Pod の IP に直接接続)
alb.ingress.kubernetes.io/target-type: ip
# リスニングポート(HTTPS)
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
# HTTP から HTTPS へのリダイレクト
alb.ingress.kubernetes.io/ssl-redirect: '443'
まずは基本的な ALB の設定と、HTTP/HTTPS のリスニングポートを定義します。
yaml# SSL 証明書の ARN(AWS Certificate Manager)
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:123456789012:certificate/xxxxx
# アイドルタイムアウト(3600 秒 = 1 時間)
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=3600
# スティッキーセッション設定
alb.ingress.kubernetes.io/target-group-attributes: |
stickiness.enabled=true,
stickiness.type=lb_cookie,
stickiness.lb_cookie.duration_seconds=3600
スティッキーセッションの設定では、Cookie の有効期限を 3600 秒(1 時間)に設定しています。
yaml# ヘルスチェック設定
alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
alb.ingress.kubernetes.io/healthcheck-path: /health
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '30'
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5'
alb.ingress.kubernetes.io/success-codes: '200'
alb.ingress.kubernetes.io/healthy-threshold-count: '2'
alb.ingress.kubernetes.io/unhealthy-threshold-count: '2'
ヘルスチェックの設定により、異常な Pod を迅速に検出して切り離せます。
yaml # タグ設定(AWS リソース管理用)
alb.ingress.kubernetes.io/tags: |
Environment=production,
Application=realtime-chat,
ManagedBy=kubernetes
spec:
rules:
- host: realtime.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: websocket-service
port:
number: 8080
タグを設定することで、AWS コンソールでのリソース管理やコスト追跡が容易になりますね。
クライアント側の実装例
サーバー側の設定だけでなく、クライアント側でも適切な実装が必要です。
JavaScript/TypeScript での WebSocket 接続
ブラウザから WebSocket に接続する基本的なコード例を見ていきましょう。
typescript// WebSocket クラスのインスタンスを作成
// wss:// は WSS(WebSocket Secure)プロトコルを使用
const ws = new WebSocket('wss://chat.example.com/ws');
HTTPS サイトから接続する場合は、必ず wss://(WebSocket Secure)を使用しましょう。
typescript// 接続が確立された時のイベントハンドラー
ws.addEventListener('open', (event) => {
console.log('WebSocket 接続が確立されました');
// サーバーにメッセージを送信
ws.send(
JSON.stringify({
type: 'join',
userId: 'user123',
room: 'general',
})
);
});
接続確立時に認証情報や初期設定を送信することが一般的です。
typescript// メッセージ受信時のイベントハンドラー
ws.addEventListener('message', (event) => {
// 受信データを JSON としてパース
const data = JSON.parse(event.data);
console.log('メッセージを受信:', data);
// メッセージタイプに応じて処理を分岐
switch (data.type) {
case 'chat':
displayChatMessage(data);
break;
case 'notification':
showNotification(data);
break;
}
});
メッセージの内容に応じて適切な処理を行うことで、柔軟なリアルタイム通信が実現できます。
typescript// エラー発生時のイベントハンドラー
ws.addEventListener('error', (event) => {
console.error('WebSocket エラーが発生しました:', event);
// エラー通知を表示
showErrorNotification('接続エラーが発生しました');
});
エラーハンドリングを適切に行うことで、ユーザー体験が向上しますね。
typescript// 接続が閉じられた時のイベントハンドラー
ws.addEventListener('close', (event) => {
console.log('WebSocket 接続が閉じられました');
console.log('クローズコード:', event.code);
console.log('理由:', event.reason);
// 意図しない切断の場合は再接続を試みる
if (!event.wasClean) {
setTimeout(() => {
reconnectWebSocket();
}, 3000); // 3 秒後に再接続
}
});
予期しない切断が発生した場合に自動的に再接続する仕組みを実装することが重要です。
再接続ロジックの実装
ネットワークの不安定さに対応するため、再接続ロジックを実装しましょう。
typescript// 再接続の最大試行回数
const MAX_RECONNECT_ATTEMPTS = 5;
// 現在の再接続試行回数
let reconnectAttempts = 0;
まず、再接続に関する設定値を定義します。
typescriptfunction reconnectWebSocket() {
// 最大試行回数に達した場合は終了
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
console.error('最大再接続回数に達しました');
showErrorNotification(
'接続できませんでした。ページを再読み込みしてください。'
);
return;
}
reconnectAttempts++;
console.log(
`再接続を試行中 (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`
);
// 指数バックオフで待機時間を増やす
const delay = Math.min(
1000 * Math.pow(2, reconnectAttempts),
30000
);
setTimeout(() => {
createWebSocketConnection();
}, delay);
}
指数バックオフアルゴリズムを使うことで、サーバーへの負荷を軽減しながら再接続を試みられます。
typescriptfunction createWebSocketConnection() {
const ws = new WebSocket('wss://chat.example.com/ws');
ws.addEventListener('open', () => {
// 再接続成功時はカウンターをリセット
reconnectAttempts = 0;
console.log('再接続に成功しました');
});
// 他のイベントハンドラーも設定...
}
再接続が成功したら、試行回数をリセットすることを忘れないようにしましょう。
Node.js サーバー側の実装例
Kubernetes で動作する WebSocket サーバーの実装例も見ていきます。
Express と ws ライブラリを使った実装
まず、必要なパッケージをインストールしましょう。
bash# Express と WebSocket ライブラリをインストール
yarn add express ws
# TypeScript の型定義もインストール
yarn add -D @types/express @types/ws
これらのパッケージを使って、シンプルな WebSocket サーバーを構築できます。
typescriptimport express from 'express';
import { WebSocketServer } from 'ws';
import { createServer } from 'http';
// Express アプリケーションを作成
const app = express();
// HTTP サーバーを作成(Express と WebSocket で共有)
const server = createServer(app);
// WebSocket サーバーを作成
const wss = new WebSocketServer({
server,
path: '/ws', // WebSocket のパス
});
HTTP サーバーを Express と WebSocket サーバーで共有することで、同じポートで両方のプロトコルを扱えます。
typescript// ヘルスチェック用のエンドポイント
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
connections: wss.clients.size, // 現在の接続数
});
});
Kubernetes のヘルスチェックに応答するエンドポイントを用意することが重要ですね。
typescript// クライアント接続時の処理
wss.on('connection', (ws, req) => {
// クライアントの IP アドレスを取得
const clientIp = req.socket.remoteAddress;
console.log(`新しい接続: ${clientIp}`);
// 接続時にウェルカムメッセージを送信
ws.send(JSON.stringify({
type: 'welcome',
message: 'WebSocket サーバーに接続しました'
}));
接続時にクライアントへ情報を送信することで、接続が正常に確立されたことを確認できます。
typescript// メッセージ受信時の処理
ws.on('message', (data) => {
try {
// 受信データを JSON としてパース
const message = JSON.parse(data.toString());
console.log('受信メッセージ:', message);
// すべての接続クライアントにブロードキャスト
wss.clients.forEach((client) => {
if (client.readyState === ws.OPEN) {
client.send(JSON.stringify(message));
}
});
} catch (error) {
console.error('メッセージ処理エラー:', error);
}
});
受信したメッセージを全クライアントにブロードキャストする基本的なチャット機能です。
typescript // 接続が閉じられた時の処理
ws.on('close', (code, reason) => {
console.log(`接続が閉じられました: ${clientIp}`);
console.log(`コード: ${code}, 理由: ${reason}`);
});
// エラー発生時の処理
ws.on('error', (error) => {
console.error('WebSocket エラー:', error);
});
});
エラーや切断のログを適切に記録することで、問題の診断が容易になります。
typescript// サーバーを起動
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log(`サーバーがポート ${PORT} で起動しました`);
});
// グレースフルシャットダウン
process.on('SIGTERM', () => {
console.log('SIGTERM シグナルを受信しました');
// 新規接続を拒否
server.close(() => {
console.log('サーバーを停止しました');
process.exit(0);
});
});
Kubernetes の Pod 終了時に接続を適切に閉じることで、クライアントへの影響を最小限に抑えられますね。
まとめ
Kubernetes 環境で WebSocket を使ったリアルタイム通信を実装するには、Ingress の適切な設定とスティッキーセッションの実装が欠かせません。
本記事では、NGINX Ingress と AWS ALB Ingress の両方について、具体的な設定方法を解説しました。重要なポイントを振り返ってみましょう。
NGINX Ingress のポイント:
proxy-read-timeoutとproxy-send-timeoutでタイムアウトを延長するwebsocket-servicesアノテーションで WebSocket を有効化するaffinity: cookieでスティッキーセッションを実装するproxy-buffering: offでリアルタイム性を確保する
AWS ALB Ingress のポイント:
idle_timeout.timeout_secondsでアイドルタイムアウトを設定するtarget-type: ipで Pod への直接接続を実現するstickiness.enabled=trueでスティッキーセッションを有効化する- ヘルスチェックを適切に設定して異常 Pod を検出する
クライアント・サーバー実装のポイント:
- 再接続ロジックを実装してネットワークの不安定さに対応する
- エラーハンドリングを適切に行いユーザー体験を向上させる
- グレースフルシャットダウンで Pod 終了時の影響を最小化する
これらの設定を適切に組み合わせることで、安定した WebSocket 通信が実現できるでしょう。
環境に応じて NGINX Ingress と ALB Ingress を使い分け、要件に合った最適な構成を選択してください。本記事の設定例を参考に、ぜひ実際のプロジェクトで WebSocket を活用してみてくださいね。
関連リンク
articleKubernetes で WebSocket:Ingress(NGINX/ALB) 設定とスティッキーセッションの実装手順
articleWebSocket のペイロード比較:JSON・MessagePack・Protobuf の速度とコスト検証
articleWebSocket RFC6455 を図解速習:OPCODE・マスキング・Close コードの要点 10 分まとめ
articleWebSocket SLO/SLI 設計:接続維持率・遅延・ドロップ率の目標値と計測方法
articleWebSocket が「200 OK で Upgrade されない」原因と対処:プロキシ・ヘッダー・TLS の落とし穴
articleWebSocket 活用事例:金融トレーディング板情報の超低遅延配信アーキテクチャ
articleCRDT × Zustand:Y.js/Automerge 連携でリアルタイム共同編集を設計
articleSvelte URL ドリブン設計:検索パラメータとストアの同期パターン
articleKubernetes で WebSocket:Ingress(NGINX/ALB) 設定とスティッキーセッションの実装手順
articleStorybook × Design Tokens 設計:Style Dictionary とテーマ切替の連携
articleWebRTC Simulcast 設計ベストプラクティス:レイヤ数・ターゲットビットレート・切替条件
articleSolidJS コンポーネント間通信チート:Context・イベント・store の選択早見
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来