CrewAIを本番環境に展開する際、私が最初に出会ったのがConnectionError: timeout exceeded while connecting to agent endpointという厄介なエラーでした。本番環境のネットワーク制約下では、開発環境では発生しなかった 수많은問題が表面化します。この記事では、Dockerコンテナ化からKubernetesによる自動スケーリングまで、私が実際に直面した問題を解決しながらCrewAIの本番運用のベストプラクティスを解説します。
Dockerfileの構築:ベースイメージの選択
CrewAIのコンテナ化において最も重要なのは、Pythonランタイムと依存関係の適切な管理です。以下のDockerfileは、本番運用に必要なセキュリティとパフォーマンスを考慮した構成になっています。
# syntax=docker/dockerfile:1.4
FROM python:3.11-slim-bookworm AS builder
マルチステージビルドでイメージサイズを最適化
WORKDIR /app
依存関係を先にインストール
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
本番用ステージ
FROM python:3.11-slim-bookworm
WORKDIR /app
セキュリティ更新と必要パッケージ
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
ユーザー切り替え(root回避)
RUN useradd -m -u 1000 crewai && mkdir -p /home/crewai/.cache
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
TRANSFORMERS_CACHE=/home/crewai/.cache/huggingface
ビルドステージから依存関係をコピー
COPY --from=builder /root/.local /home/crewai/.local
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY . .
、非rootユーザーで実行
USER crewai
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD ["python", "-m", "crewai", "serve", "--host", "0.0.0.0", "--port", "8000"]
requirements.txtにはCrewAI本体と本番運用必需的ヘルパーライブラリを指定します。
# requirements.txt
crewai>=0.80.0
crewai-tools>=0.15.0
langchain-openai>=0.3.0
langchain-community>=0.3.0
pydantic>=2.0.0
pydantic-settings>=2.0.0
uvicorn[standard]>=0.30.0
fastapi>=0.115.0
prometheus-client>=0.20.0
redis>=5.0.0
httpx>=0.27.0
Kubernetes Deployment:YAML構成の詳細
Production環境ではHorizontal Pod Autoscaler(HPA)を使用した自動スケーリングが不可欠です。以下は私が実際に使用しているDeploymentとServiceの定義です。
# crewai-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: crewai-api
namespace: production
labels:
app: crewai-api
version: v1
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: crewai-api
template:
metadata:
labels:
app: crewai-api
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8000"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: crewai-service-account
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: crewai-api
image: registry.example.com/crewai-api:v1.2.3
imagePullPolicy: Always
ports:
- containerPort: 8000
name: http
protocol: TCP
env:
- name: OPENAI_API_BASE
value: "https://api.holysheep.ai/v1"
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: crewai-secrets
key: holysheep-api-key
- name: REDIS_URL
value: "redis://redis-cluster:6379/0"
- name: LOG_LEVEL
value: "INFO"
- name: MAX_CONCURRENT_AGENTS
value: "50"
- name: AGENT_TIMEOUT_SECONDS
value: "120"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
volumeMounts:
- name: crewai-cache
mountPath: /home/crewai/.cache
volumes:
- name: crewai-cache
persistentVolumeClaim:
claimName: crewai-model-cache
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: crewai-api
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: crewai-api-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: crewai-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: crewai_active_agents
target:
type: AverageValue
averageValue: "25"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
私はこのHPA設定で、アクティブエージェント数が25を超えた際に自動でPod数を増やし、CPU使用率が70%に達しても自動スケーリングがトリガーされるように設定しています。HolySheep AIの<50msレイテンシであれば、スケールアウト時のエージェント起動も迅速に完了するため、ユーザーは待ち時間をほとんど感じません。
FastAPI統合: crewai_api.py
CrewAIをFastAPIアプリケーションとしてラップし、本番環境に最適なエンドポイントを提供します。
# crewai_api.py
from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
from contextlib import asynccontextmanager
import asyncio
import logging
from crewai import Agent, Task, Crew
from crewai_tools import SerpDevTool, WebsiteSearchTool
from langchain_openai import ChatOpenAI
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
HolySheep AI のエンドポイントを明示的に指定
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
LLM_CONFIG = {
"api_key": "YOUR_HOLYSHEEP_API_KEY", # 實際には環境変数から取得
"base_url": HOLYSHEEP_BASE_URL,
"model": "gpt-4o",
"temperature": 0.7,
"max_tokens": 4096
}
llm = ChatOpenAI(**LLM_CONFIG)
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("CrewAI API starting up...")
yield
logger.info("CrewAI API shutting down...")
app = FastAPI(
title="CrewAI Production API",
version="1.2.3",
lifespan=lifespan
)
app.add_middleware(
CORSMiddleware,
allow_origins=["https://yourapp.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class CrewRequest(BaseModel):
task_description: str = Field(..., min_length=10, max_length=5000)
agent_count: int = Field(default=3, ge=1, le=10)
tools: List[str] = Field(default=["web_search"])
model: str = Field(default="gpt-4o")
timeout: int = Field(default=300, ge=30, le=600)
class TaskResponse(BaseModel):
task_id: str
status: str
result: Optional[str] = None
execution_time_ms: Optional[int] = None
tasks_store: Dict[str, Dict[str, Any]] = {}
@app.get("/health")
async def health_check():
return {"status": "healthy", "version": "1.2.3"}
@app.get("/ready")
async def readiness_check():
return {"status": "ready"}
@app.post("/crew/execute", response_model=TaskResponse)
async def execute_crew_task(request: CrewRequest, background_tasks: BackgroundTasks):
import uuid
task_id = str(uuid.uuid4())
try:
tools = []
if "web_search" in request.tools:
tools.append(SerpDevTool())
if "website_search" in request.tools:
tools.append(WebsiteSearchTool())
researcher = Agent(
role="Research Analyst",
goal="Gather and analyze relevant information",
backstory="Expert data researcher with years of experience",
tools=tools,
llm=llm,
verbose=True
)
analyst = Agent(
role="Data Analyst",
goal="Interpret and synthesize findings",
backstory="Senior analyst specializing in pattern recognition",
tools=[],
llm=llm,
verbose=True
)
task1 = Task(
description=f"Research: {request.task_description}",
agent=researcher,
expected_output="Comprehensive research findings"
)
task2 = Task(
description="Analyze the research findings",
agent=analyst,
expected_output="Actionable insights and summary",
context=[task1]
)
crew = Crew(
agents=[researcher, analyst],
tasks=[task1, task2],
verbose=True
)
tasks_store[task_id] = {"status": "running"}
result = crew.kickoff()
tasks_store[task_id] = {
"status": "completed",
"result": str(result),
"model": request.model
}
return TaskResponse(
task_id=task_id,
status="completed",
result=str(result),
execution_time_ms=300
)
except Exception as e:
logger.error(f"Task {task_id} failed: {str(e)}")
tasks_store[task_id] = {"status": "failed", "error": str(e)}
raise HTTPException(status_code=500, detail=str(e))
@app.get("/crew/status/{task_id}")
async def get_task_status(task_id: str):
if task_id not in tasks_store:
raise HTTPException(status_code=404, detail="Task not found")
return tasks_store[task_id]
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000, workers=4)
リソースQuotaとNamespace設計
本番環境ではNamespaceレベルのリソース管理も重要です。以下のResourceQuota設定で、チーム全体のコストとリソース使用を制御できます。
# namespace-and-quota.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: production
team: ai-platform
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "50"
services: "10"
configmaps: "20"
persistentvolumeclaims: "5"
---
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- max:
cpu: "4"
memory: 8Gi
min:
cpu: 100m
memory: 128Mi
default:
cpu: 500m
memory: 1Gi
defaultRequest:
cpu: 250m
memory: 512Mi
type: Container
よくあるエラーと対処法
エラー1:ConnectionError: timeout exceeded while connecting to agent endpoint
私が初めて本番環境にデプロイした際に発生したのは、コンテナ間の通信タイムアウトエラーでした。Kubernetes環境では、Service名解決やDNS解決に時間がかかることがあり、デフォルトのタイムアウト値では不十分な場合があります。
# 解決策:Deployment設定に適切なタイムアウトとリトライポリシーを追加
(前述のdeployment.yamlに以下の設定をmerge)
➊ kube-proxy の設定調整(ConfigMapで変更)
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-proxy
namespace: kube-system
data:
config.conf: |
mode: "iptables"
# 接続タイムアウトを延長
conntrack:
maxPerCore: 0
min: 100000
tcpEstablishedTimeout: 86400s
tcpCloseWaitTimeout: 10800s
➋ アプリケーション側のタイムアウト設定
env:
- name: CREW_AGENT_TIMEOUT
value: "180"
- name: HTTP_CLIENT_TIMEOUT
value: "180"
- name: GRPC_KEEPALIVE_TIME_MS
value: "30000"
エラー2:401 Unauthorized - Invalid API Key
APIキーが無効または期限切れの場合に発生します。HolySheep AIではキーを直接シークレットに埋め込むのではなく、External Secrets Operatorを活用した動的なシークレット管理を推奨しています。
# 解決策:External Secrets OperatorでAPIキーを動的管理
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: crewai-api-keys
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: crewai-secrets
creationPolicy: Owner
data:
- secretKey: holysheep-api-key
remoteRef:
key: production/holysheep
property: api-key
- secretKey: redis-password
remoteRef:
key: production/redis
property: password
Vault側のシークレット設定例
vault kv put production/holysheep api-key="sk-xxxxx..."
エラー3:OOMKilled - Container out of memory
モデルキャッシュが増加し、メモリ制限を超えた際にPodが強制終了されます。HuggingFaceのトランスフォーマーモデルをキャッシュする場合は、永続化Volumeの使用と適切なメモリ管理が必要です。
# 解決策: PersistentVolumeClaimとメモリ оптимизация
PVC設定(前述のdeployment.yaml内で参照)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: crewai-model-cache
namespace: production
spec:
accessModes:
- ReadWriteMany # 複数Pod間で共有
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
---
コンテナ設定の оптимизация
resources:
limits:
memory: "4Gi" # モデルサイズに応じて増加
ephemeral-storage: "2Gi"
requests:
memory: "2Gi"
キャッシュ肥大化防止: модели自動クリーンアップ設定
env:
- name: HF_HOME
value: "/home/crewai/.cache/huggingface"
- name: TRANSFORMERS_OFFLINE
value: "0"
- name: MODEL_CLEANUP_INTERVAL
value: "3600"
Init Containerで必要な моделиのみ事前ダウンロード
initContainers:
- name: model-downloader
image: crewai-api:v1.2.3
command: ["python", "-c",
"from transformers import AutoTokenizer; "
"AutoTokenizer.from_pretrained('sentence-transformers/all-MiniLM-L6-v2')"
]
volumeMounts:
- name: crewai-cache
mountPath: /home/crewai/.cache
エラー4:CrashLoopBackOff - アプリケーション起動失敗
依存サービスの起動順序や設定ミスが原因でPodが繰り返しクラッシュします。
# 解決策: Readiness/Liveness Probeの调整と依存サービス確認
Deployment設定に以下を追加
initContainers:
- name: wait-for-redis
image: busybox:1.36
command: ['sh', '-c',
'echo "Waiting for Redis..."; '
'until nc -z redis-cluster 6379; do echo "Redis not ready"; sleep 2; done; '
'echo "Redis is ready"'
]
Probe設定の最適化
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60 # 起動待機時間を延長
periodSeconds: 15
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
起動時の环境変数確認
env:
- name: STARTUP_DELAY
value: "10"
- name: VALIDATE_DEPENDENCIES
value: "true"
エラー5:HPAがスケールダウンしない(安定性ウィンドウ問題)
トラフィックが変動する際に、HPAがスケールダウン stabilizeWindowSeconds のせいでPod数を減らせない場合があります。最適な値はワークロードの特性に依存します。
# 解決策: ワークロードに応じたHPA設定の調整
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: crewai-api-hpa-tuned
namespace: production
spec:
minReplicas: 2
maxReplicas: 15
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60 # 70%から60%に変更(より早期にスケールアップ)
behavior:
scaleDown:
stabilizationWindowSeconds: 180 # 5分から3分に短縮
policies:
- type: Pods
value: 2 # 1度に2 Podまでスケールダウン可能
periodSeconds: 60
- type: Percent
value: 20 # または現在のPod数の20%まで
periodSeconds: 60
selectPolicy: Min # より積極的なポリシーを選択
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Pods
value: 5
periodSeconds: 15
監視とアラート設定
本番運用品質を保つためには、適切な監視体制が不可欠です。PrometheusとGrafanaを使用した監視設定の例を示します。
# prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: crewai-alerts
namespace: production
spec:
groups:
- name: crewai-performance
rules:
- alert: HighAgentLatency
expr: histogram_quantile(0.95, rate(crewai_agent_duration_seconds_bucket[5m])) > 30
for: 5m
labels:
severity: warning
annotations:
summary: "CrewAI エージェントレイテンシが高い"
description: "P95レイテンシが30秒を超えています"
- alert: LowSuccessRate
expr: rate(crewai_task_success_total[5m]) / rate(crewai_task_total[5m]) < 0.95
for: 10m
labels:
severity: critical
annotations:
summary: "CrewAI タスク成功率低下"
description: "成功率が95%を下回っています"
- alert: HighMemoryUsage
expr: (container_memory_working_set_bytes / container_spec_memory_limit_bytes) > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "コンテナメモリ使用率が高い"
description: "Pod {{ $labels.pod }} のメモリ使用率が85%を超えています"
まとめ:成本最適化のポイント
CrewAIの本番運用において、私が最も重要だと感じているのは適切なスケーリング戦略とAPIコスト管理です。HolySheep AIの料金体系を活用すれば、今すぐ登録して得られる無料クレジットで экспериメント的从入门到精通まで一试着我们できます。特にDeepSeek V3.2の$0.42/MTokという低価格は、高频度のエージェント実行において大幅なコスト削减につながります。
コンテナ化とKubernetes自動スケーリングを組み合わせることで、需要の変動に柔軟に対応しながら、必要最小限のリソースで効率的な運用が可能になります。私の经验では|scale-down|安定性窗口Seconds|を適切に调整することが、成本とパフォーマンスの 균형を取る上で非常重要|でした。
👉 HolySheep AI に登録して無料クレジットを獲得