この記事では仮想待合室システムを目指すけども結局はできておらずIstioのトラフィック制御までがメインです。方針は決まったが睡魔に負けたのでこの記事はここまで
はじめに
登壇で抽象度の高いことを人前で喋ってとても心が疲れたので技術者として手を動かしたいです。深夜ノリなのでガバガバである。今回は、Istio を用いて仮想待合室が作りたくなってたのでKubernetes環境でIstioを使用してトラフィック制御を実装する方法について、解説します。この記事では、将来的な仮想待合室システムの構築を視野に入れつつ、まずはトラフィック制御の基本的な実装に焦点を当てます。Kindを使用したローカル開発環境の構築から、Istioによるトラフィック管理の設定、そして実際のテストを実行します。
1. 環境セットアップ
まず、必要なツールをインストールしていることを確認してください。
- Docker
- Kind (Kubernetes in Docker)
- kubectl
- Istioctl
1.1 Kindクラスターの作成
Kindを使用してローカルKubernetesクラスターを作成します。以下の内容でkind-config.yaml
ファイルを作成してください。
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane kubeadmConfigPatches: - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP - containerPort: 443 hostPort: 443 protocol: TCP
この設定ファイルは、Kindクラスターにポート80と443のマッピングを追加し、Ingressコントローラーの準備をします。
次に、以下のコマンドでKindクラスターを作成します。
kind create cluster --name traffic-control --config kind-config.yaml
1.2 Istioのインストール
Istioをインストールし、デフォルトの名前空間にIstio injectionを有効化します。
istioctl install --set profile=demo -y kubectl label namespace default istio-injection=enabled
2. アプリケーションの準備
2.1 Goアプリケーションの作成
以下の内容でmain.go
ファイルを作成します。
package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the main content!") }) http.ListenAndServe(":8080", nil) }
2.2 Dockerfileの作成
FROM golang:1.22 WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY main.go . RUN go build -o main . CMD ["./main"]
2.3 イメージのビルドとロード
docker build -t waiting-room-app:latest . kind load docker-image waiting-room-app:latest --name traffic-control
3. Kubernetesリソースの定義
3.1 Kubernetes リソースの作成
waiting-room.yaml
を作成する
apiVersion: apps/v1 kind: Deployment metadata: name: waiting-room-app spec: replicas: 1 selector: matchLabels: app: waiting-room-app template: metadata: labels: app: waiting-room-app spec: containers: - name: waiting-room-app image: waiting-room-app:latest imagePullPolicy: Never ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: waiting-room-app spec: selector: app: waiting-room-app ports: - protocol: TCP port: 80 targetPort: 8080
3.2 Istioリソースの定義
istio-rules.yaml
ファイルには、Istioの主要な3つのリソース(VirtualService、DestinationRule、Gateway)が定義されています。これらのリソースは、仮想待合室システムのトラフィック制御と負荷管理を実現する上で重要な役割を果たします。
- VirtualService: VirtualServiceは、トラフィックのルーティングルールを定義します。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: waiting-room-vs
spec:
hosts:
- "*"
gateways:
- waiting-room-gateway
http:
- route:
- destination:
host: waiting-room-app
port:
number: 80
timeout: 1s
retries:
attempts: 3
perTryTimeout: 500ms
fault:
delay:
percentage:
value: 80
fixedDelay: 5s
-
hosts: "*"
: すべてのホストからのトラフィックに適用されます。 -
gateways: - waiting-room-gateway
: 特定のゲートウェイを通過するトラフィックにのみ適用されます。 -
route
: トラフィックをwaiting-room-app
サービスの80ポートにルーティングします。 -
timeout: 1s
: リクエストの最大待機時間を1秒に設定します。 -
retries
: 失敗したリクエストを最大3回、500ミリ秒間隔で再試行します。 fault
: 80%のトラフィックに5秒の遅延を導入します。これにより、仮想待合室の「待ち時間」をシミュレートします。DestinationRule: DestinationRuleは、トラフィックのロードバランシングと接続プールの設定を定義します。
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: waiting-room-dr
spec:
host: waiting-room-app
trafficPolicy:
connectionPool:
tcp:
maxConnections: 10
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
outlierDetection:
consecutive5xxErrors: 1
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 100
-
host: waiting-room-app
: このルールが適用されるサービスを指定します。 -
connectionPool
: 同時接続数を10に制限し、保留中のリクエストと接続あたりのリクエスト数を1に制限します。これにより、サーバーの過負荷を防ぎます。 outlierDetection
: 連続して5xxエラーが発生した場合、そのインスタンスを3分間トラフィックから除外します。これにより、問題のあるインスタンスを自動的に切り離し、システムの安定性を維持します。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: waiting-room-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
-
selector: istio: ingressgateway
: Istioの標準的なIngressゲートウェイを使用します。 -
servers
: HTTP トラフィックを80ポートで受け入れ、すべてのホストからのリクエストを許可します。
これらのリソースを組み合わせることで、以下のような仮想待合室の動作を実現します。
- 外部からのトラフィックはGatewayを通じて受け入れられます。
- VirtualServiceにより、80%のトラフィックに5秒の遅延が導入され、待ち時間が発生します。
- DestinationRuleにより、同時接続数が制限され、システムの過負荷が防止されます。
- 問題が発生した場合、自動的にトラフィックが健全なインスタンスにリダイレクトされます。
4. リソースの適用
以下のコマンドでKubernetesリソースを適用します。
kubectl apply -f waiting-room.yaml kubectl apply -f istio-rules.yaml
5. アクセスの設定
Istio IngressGatewayにアクセスするために、kubectl port-forward
コマンドを使用します。
kubectl port-forward -n istio-system svc/istio-ingressgateway 8080:80
このコマンドにより、ローカルマシンの8080ポートがIstio IngressGatewayの80ポートに転送されます。これにより、http://localhost:8080
でアプリケーションにアクセスできるようになります。
6. 動作確認とテスト
6.1 基本的な動作確認
新しいターミナルウィンドウを開き、以下のコマンドでアプリケーションにアクセスしてみましょう:
curl http://localhost:8080
6.2 負荷テストスクリプト
以下の内容でload_test.sh
スクリプトを作成します。
#!/bin/bash CONCURRENT=10 TOTAL_REQUESTS=50 RESULTS_DIR="access_test_results" mkdir -p "$RESULTS_DIR" make_request() { local id=$1 local start_time=$(date +%s.%N) local http_code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080) local end_time=$(date +%s.%N) local duration=$(echo "$end_time - $start_time" | bc) echo "$id,$http_code,$duration" >> "$RESULTS_DIR/results.csv" } echo "RequestID,HTTPCode,Duration" > "$RESULTS_DIR/results.csv" for i in $(seq 1 $TOTAL_REQUESTS); do make_request $i & if (( i % CONCURRENT == 0 )); then wait fi done wait echo "All requests completed. Results saved in $RESULTS_DIR/results.csv" echo "=============================== テスト結果サマリー ===============================" echo "総リクエスト数: $TOTAL_REQUESTS" echo "同時接続数: $CONCURRENT" echo -e "\nHTTPステータスコード分布:" status_codes=$(sort "$RESULTS_DIR/results.csv" | cut -d',' -f2 | sort | uniq -c | sort -nr) total_success=$(echo "$status_codes" | grep " 200" | awk '{print $1}') total_success=${total_success:-0} echo "$status_codes" | while read count code; do if [ "$code" != "HTTPCode" ]; then percentage=$(echo "scale=2; $count / $TOTAL_REQUESTS * 100" | bc) printf "%s: %s (%.2f%%)\n" "$code" "$count" "$percentage" bar=$(printf '%0.s#' $(seq 1 $(echo "$percentage/2" | bc))) printf " %s\n" "$bar" fi done success_rate=$(echo "scale=2; $total_success / $TOTAL_REQUESTS * 100" | bc) echo -e "\n成功率(200 OKの割合): ${success_rate}%" echo -e "\n応答時間統計:" awk -F',' ' NR>1 { sum+=$3; sumsq+=$3*$3; if(NR==2 || $3<min) min=$3; if(NR==2 || $3>max) max=$3; } END { avg=sum/NR; std=sqrt(sumsq/NR - avg*avg); printf "最小: %.2f秒\n", min; printf "最大: %.2f秒\n", max; printf "平均: %.2f秒\n", avg; printf "標準偏差: %.2f秒\n", std; } ' "$RESULTS_DIR/results.csv" echo -e "\n注: 詳細な結果は $RESULTS_DIR/results.csv に保存されています。"
このスクリプトに実行権限を付与し、実行します。
chmod +x load_test.sh ./load_test.sh
7. 結果の分析
テストスクリプトの実行結果を分析しましょう。以下は典型的な結果の例です。
All requests completed. Results saved in access_test_results/results.csv =============================== テスト結果サマリー =============================== 総リクエスト数: 50 同時接続数: 10 HTTPステータスコード分布: 503: 36 (72.00%) #################################### 200: 14 (28.00%) ############## 成功率(200 OKの割合): 28.00% 応答時間統計: 最小: 0.00秒 最大: 5.00秒 平均: 4.02秒 標準偏差: 1.99秒 注: 詳細な結果は access_test_results/results.csv に保存されています。
結果の説明
アクセス制限の効果: 72%のリクエストが503 (Service Unavailable) エラーを返しており、設定したアクセス制限が効果的に機能していることがわかります。
遅延の導入: 平均応答時間が4.02秒、最大が5.00秒となっており、VirtualServiceで設定した5秒の遅延が適切に適用されていることが確認できます。
成功率: 28%のリクエストのみが成功(200 OK)しており、トラフィック制御システムが効果的にリクエストを制限していることを示しています。
応答時間のばらつき: 標準偏差が1.99秒と大きいことから、一部のリクエストは即座に処理され、他は遅延が適用されていることがわかります。これは、設定した80%のトラフィックへの遅延導入が機能していることを示しています。
8. まとめ
この記事では、Kubernetes上でトラフィック制御を実装し、スケーラブルな待機システムを構築する基礎部分を解説しました。Kindを使用したローカル開発環境の構築から、Istioによるトラフィック管理、負荷テストの実施までを紹介しました。この手法は、大規模イベントやセール時のトラフィック急増への対策として有効です。
しかし、実際の運用では、継続的なモニタリングやビジネス側との調整に加え、本格的な仮想待合室システムの構築には、待ち行列管理やユーザーインターフェースの実装が不可欠になります。これらの要素については、次回の記事ではRedisやEnvoyFilterなどを活用した具体的な実装方法と合わせて詳しく解説していく予定です。お楽しみに!おやすみなさい😪