Go言語で学ぶ Webアプリケーション開発5：[Kubernetesを活用したデプロイ & 負荷テスト実用編]

## はじめに

前回の記事では、Herokuへの簡単なデプロイ方法と 負荷対策（データベース最適化、キャッシュ、非同期処理、ページネーション）を解説しました。  
今回は、より高度な運用手法としてKubernetes（K8s）を活用したデプロイ方法とより具体的な負荷テストの実施方法について解説します。

**対象読者**
- Goで開発したWebアプリをKubernetes上にデプロイしたい方
- 負荷テストを実施し、パフォーマンスを計測 & 最適化したい方

**目次**
1. Kubernetesを活用したデプロイ
   - Kubernetesの基本概念
   - Kubernetesクラスターの構築（Minikubeを使用）
   - KubernetesへのGoアプリのデプロイ
2. 負荷テストの実施
   - 負荷テストの目的
   - k6を使った負荷テスト
   - 負荷テストの結果分析と最適化

---

## 1. Kubernetesを活用したデプロイ

**1.1 Kubernetesの基本概念**

**Kubernetes（K8s）** は、コンテナ化されたアプリケーションを管理・運用するためのオーケストレーションツールです。

- **自動スケーリング**：負荷に応じてコンテナを増減
- **サービスディスカバリ & ロードバランシング**：複数のコンテナにトラフィックを分散
- **自己回復機能**：クラッシュしたコンテナを自動で再起動

**1.2 Kubernetesクラスターの構築（Minikubeを使用）**

まずは、ローカル環境でKubernetesクラスターを構築するために**Minikube**を使用します。

#### **Minikubeのインストール**
```sh
# Minikubeをインストール
brew install minikube

# Minikubeを起動
minikube start
```

**1.3 KubernetesへのGoアプリのデプロイ**

**Dockerイメージの作成 & Minikubeにプッシュ**
```sh
docker build -t my-go-app .
minikube image load my-go-app
```

**Kubernetesのデプロイメント定義**

**deployment.yaml**
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: go-app
  template:
    metadata:
      labels:
        app: go-app
    spec:
      containers:
      - name: go-app
        image: my-go-app
        ports:
        - containerPort: 8080
```

**サービスの定義（Service.yaml）**
```yaml
apiVersion: v1
kind: Service
metadata:
  name: go-app-service
spec:
  type: NodePort
  selector:
    app: go-app
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
```

**Kubernetesにデプロイ**
```sh
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
```

**サービスの確認 & アクセス**
```sh
minikube service go-app-service --url
```

---

## 2. 負荷テストの実施

**2.1 負荷テストの目的**

負荷テストを行うことで、アプリケーションの限界性能を確認し、適切なスケーリングのための指標を得ることができます。

負荷テストの目的：
- 最大リクエスト数の測定
- レスポンス時間の分析
- スケールアップの必要性の判断

**2.2 k6を使った負荷テスト**

#### **k6のインストール**
```sh
brew install k6
```

#### **負荷テストのスクリプト作成（load-test.js）**
```js
import http from 'k6/http';
import { check, sleep } from 'k6';

export let options = {
  vus: 50, // 仮想ユーザー数
  duration: '30s', // テスト時間
};

export default function () {
  let res = http.get('http://localhost:8080/api/todos');
  check(res, {
    'status was 200': (r) => r.status == 200,
    'response time < 200ms': (r) => r.timings.duration < 200,
  });
  sleep(1);
}
```

#### **負荷テストの実行**
```sh
k6 run load-test.js
```

**2.3 負荷テストの結果分析と最適化**

**k6の出力例**
```
checks..................: 100.00% ✓ 1500 ✗ 0
http_req_duration......: avg=120.56ms min=90ms max=250ms
http_reqs..............: 50 requests per second
```

このデータを元に、以下の最適化を検討します。

| 課題 | 改善策 |
|------|------|
| **レスポンスが遅い** | **キャッシュ（Redis）を導入** |
| **CPU 負荷が高い** | **Kubernetesのオートスケールを設定** |
| **リクエストが増えすぎる** | **レートリミットを適用** |

#### **Kubernetesのオートスケール設定**
```sh
kubectl autoscale deployment go-app --cpu-percent=50 --min=2 --max=5
```

#### **レートリミットの設定（Gin Middleware）**
```go
import "golang.org/x/time/rate"

var limiter = rate.NewLimiter(1, 5)

func rateLimitMiddleware(c *gin.Context) {
    if !limiter.Allow() {
        c.JSON(http.StatusTooManyRequests, gin.H{"error": "Too many requests"})
        c.Abort()
        return
    }
    c.Next()
}
```

---

## まとめ

| 項目 | 説明 |
|------|------|
| **Kubernetes** | アプリケーションをスケーラブルにデプロイするためのオーケストレーションツール |
| **Minikube** | ローカル環境でKubernetesをテストするためのツール |
| **負荷テスト（k6）** | Webアプリケーションのパフォーマンスを測定するためのツール |
| **スケーリング & 最適化** | キャッシュ、オートスケール、レートリミットを活用して負荷を軽減 |

本記事では、Kubernetes を活用したデプロイ方法と負荷テストの具体的な実施方法について解説しました。  
もう少しクラウド環境（AWS, GCP, Azure）でのデプロイとかKubernetesのCI/CDパイプライン構築もやっていこうかな