Go + Kubernetes 1.30 実践:AI推論プラットフォームをゼロから構築
なぜAI推論プラットフォームにKubernetesが必要か?
AI推論サービスには独自の運用課題があります:GPUリソースが高価、モデルロードが遅い、トラフィック変動が激しい、コールドスタートコストが高い。Kubernetes 1.30 + Go はこれらの課題を解決する最適な組み合わせです。
┌──────────────────────────────────────────────────┐
│ AI推論プラットフォームアーキテクチャ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Go API │ │ Goスケ │ │ Go監視 │ │
│ │ Gateway │ │ジューラ │ │ Monitor │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ ┌────▼────────────▼────────────▼────┐ │
│ │ Kubernetes 1.30 │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │ Pod │ │ Pod │ │ Pod │ │ │
│ │ │GPU 0 │ │GPU 1 │ │GPU 2 │ │ │
│ │ │Model │ │Model │ │Model │ │ │
│ │ │ A │ │ B │ │ A │ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
Goスケジューラ:GPUアウェアスケジューリング
カスタムスケジューラ
package scheduler
import (
"context"
"fmt"
"sort"
v1 "k8s.io/api/core/v1"
"k8s.io/kubernetes/pkg/scheduler/framework"
)
type GPUScheduler struct {
handle framework.Handle
}
func (s *GPUScheduler) Filter(ctx context.Context, state *framework.CycleState,
pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
gpuRequest := getGPURequest(pod)
if gpuRequest == 0 {
return nil
}
availableGPU := getAvailableGPU(nodeInfo)
if availableGPU < gpuRequest {
return framework.NewStatus(framework.Unschedulable,
fmt.Sprintf("insufficient GPU: need %d, available %d", gpuRequest, availableGPU))
}
return nil
}
func (s *GPUScheduler) Score(ctx context.Context, state *framework.CycleState,
pod *v1.Pod, nodeName string) (int64, *framework.Status) {
nodeInfo, _ := s.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
gpuUtilization := getGPUUtilization(nodeInfo)
// GPU使用率の低いノードを優先(負荷分散)
score := int64(100 - gpuUtilization)
return score, nil
}
func getGPURequest(pod *v1.Pod) int64 {
for _, container := range pod.Spec.Containers {
if limit, ok := container.Resources.Limits[v1.ResourceName("nvidia.com/gpu")]; ok {
return limit.Value()
}
}
return 0
}
Filter 段階でGPUリソースが足りないノードを除外し、Score 段階でGPU使用率が最も低いノードに高い優先度を割り当てます。この「Filter + Score」二段階方式はKubernetesスケジューラの標準アーキテクチャに完全準拠しています。
モデルサービング:vLLM + Kubernetes
Deployment設定
apiVersion: apps/v1
kind: Deployment
metadata:
name: llm-inference
labels:
app: llm-inference
model: qwen2.5-72b
spec:
replicas: 3
selector:
matchLabels:
app: llm-inference
template:
metadata:
labels:
app: llm-inference
spec:
schedulerName: gpu-scheduler
containers:
- name: vllm
image: vllm/vllm-openai:latest
resources:
limits:
nvidia.com/gpu: "2"
requests:
nvidia.com/gpu: "2"
memory: "32Gi"
env:
- name: MODEL_NAME
value: "Qwen/Qwen2.5-72B-Instruct"
- name: GPU_MEMORY_UTILIZATION
value: "0.90"
- name: MAX_NUM_SEQS
value: "256"
ports:
- containerPort: 8000
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 120
periodSeconds: 10
volumeMounts:
- name: model-cache
mountPath: /models
volumes:
- name: model-cache
persistentVolumeClaim:
claimName: model-cache-pvc
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
readinessProbe の initialDelaySeconds: 120 に注目——大規模モデル(72B)のロードには2分程度かかるため、起動猶予を十分に確保します。
HPA自動スケーリング
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: llm-inference-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: llm-inference
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: vllm_num_requests_running
target:
type: AverageValue
averageValue: "128"
- type: Resource
resource:
name: nvidia.com/gpu-utilization
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
重要な設計ポイント:
- スケールアップは速く(60秒の安定化ウィンドウ)、スケールダウンは遅く(300秒)——トラフィックスパイクによる頻繁な変動を防止
- GPU使用率と実行中リクエスト数の2つの指標でトリガー
- GPUは高価なので、
maxReplicas: 10でコスト上限を設定
Go APIゲートウェイ
モデルルーティングとロードバランシング
package gateway
import (
"net/http"
"net/http/httputil"
"net/url"
"sync/atomic"
"github.com/gin-gonic/gin"
)
type ModelRouter struct {
endpoints map[string][]*url.URL
counters map[string]*atomic.Uint64
}
func NewModelRouter() *ModelRouter {
return &ModelRouter{
endpoints: make(map[string][]*url.URL),
counters: make(map[string]*atomic.Uint64),
}
}
func (r *ModelRouter) RegisterModel(model string, urls ...string) {
for _, u := range urls {
parsed, _ := url.Parse(u)
r.endpoints[model] = append(r.endpoints[model], parsed)
}
r.counters[model] = &atomic.Uint64{}
}
func (r *ModelRouter) ProxyHandler(c *gin.Context) {
model := c.Param("model")
endpoints, ok := r.endpoints[model]
if !ok {
c.JSON(http.StatusNotFound, gin.H{"error": "model not found"})
return
}
counter := r.counters[model]
idx := counter.Add(1) % uint64(len(endpoints))
target := endpoints[idx]
proxy := httputil.NewSingleHostReverseProxy(target)
proxy.ServeHTTP(c.Writer, c.Request)
}
atomic.Uint64 を使用したラウンドロビン負荷分散で、ロックなしの軽量なルーティングを実現。Ginフレームワークのパフォーマンスは数百万 QPS を処理可能です。
カナリーデプロイ
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: llm-inference
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: llm-inference
service:
port: 8000
analysis:
interval: 1m
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 1m
- name: vllm-num-requests-waiting
thresholdRange:
max: 50
interval: 1m
Flaggerを使用したカナリーデプロイ:新バージョンは10%から始め、5回の分析間隔を経て徐々に50%まで拡大。成功率99%以上、レイテンシ500ms以内、待機リクエスト50未満を維持できなければ自動ロールバック。
モデル更新のゼロダウンタイム戦略:
- 新モデルバージョンのPodを起動(既存Podはそのまま)
- トラフィックの10%を新バージョンにルーティング
- 5分間メトリクスを監視(成功率、レイテンシ、GPUメモリ)
- 問題なければさらに10%ずつ増量
- 異常検出時に即時ロールバック
監視とオブザーバビリティ
# Prometheusカスタムメトリクス
apiVersion: v1
kind: ConfigMap
metadata:
name: vllm-metrics-config
data:
vllm-rules.yml: |
groups:
- name: vllm
rules:
- alert: HighQueueLength
expr: vllm_num_requests_waiting > 100
for: 2m
labels:
severity: warning
annotations:
summary: "LLM推論キューが過剰"
- alert: HighGPUUtilization
expr: nvidia_gpu_utilization > 95
for: 5m
labels:
severity: critical
annotations:
summary: "GPU使用率が高すぎる"
まとめ
Go + KubernetesでAI推論プラットフォームを構築するコアバリュー:
- Goスケジューラ:GPUアウェアスケジューリングでGPUリソース使用率を最適化
- K8s HPA:推論キュー長とGPU使用率に基づく自動スケーリング
- カナリーデプロイ:モデル更新のゼロダウンタイム、自動ロールバック
- オブザーバビリティ:GPU使用率、キュー長、推論レイテンシのフルチェーン監視
AI推論プラットフォームは「モデルをデプロイする」ことではなく「システムを運用する」こと——Kubernetesが基盤で、Goが接着剤です。
ブラウザローカルツールを無料で試す →
#Go#Kubernetes#AI推理#GPU调度#云原生