チュートリアル:本番対応コンテナのデプロイ¶
プレミアム機能
Workload APIはプレミアム機能です。 この機能を有効にする方法については、DataRobotの担当者または管理者にお問い合わせください。
完全なガバナンス(ロックされたアーティファクト、importance、共有、監視)を備えたコンテナ化されたAIサービスをデプロイします。ドラフトのワークロード(Hello, Workload を参照)とは異なり、これは長期にわたって実行される本番環境レベルのものです。
このチュートリアルでは、以下の機能を提供するFastAPIベースのエージェントサービス(otkachnlp/fastapi-server-example、DataRobotが公開したものではない一般に利用可能なサードパーティのイメージ)をデプロイします。
- OpenAI互換の
/chat/completions。DataRobot LLM Gatewayに接続されており、個別のLLMデプロイは必要ありません。 - LangGraphの
/agentエンドポイント:ArXiv検索を行うReActエージェント。 /healthz、/readyz、および/health。それぞれ生存(liveness)、準備完了(readiness)、詳細なステータスを提供します。
作業方法に一致するタブを選択してください。cURLはREST APIを直接呼び出します。CLIは同じ呼び出しを dr workload / dr artifact コマンドでラップします(サブコマンドが存在しない場合は curl にフォールバックします)。Pulumiはロックされたアーティファクトとワークロードをコードとして宣言します。実行可能なノートブックを使用したい場合は、以下を選択してください。
一目でわかるロックされたアーティファクトのワークロード¶
| プロパティ | 値 |
|---|---|
| Lifetime | 無期限。明示的に停止または削除されるまで持続します。 |
| Artifact mutability | ロックされると不変(Immutable)になります。 |
importance |
オプション。デフォルトは low です。本番環境用に明示的に設定します(critical、high、moderate、または low)。 |
| Workloads per artifact | 無制限。1つのロックされたアーティファクトが複数のワークロードをバックアップできます。 |
| 置換 | サポートされています。ロックされたものとロックされたもののみ置換します。 |
ドラフトとロックの完全な比較については、ワークロードの概念 を参照してください。
前提条件¶
curlとjqが使用可能なターミナル。- DataRobot APIのエンドポイントとトークン:
export DATAROBOT_ENDPOINT="[https://app.datarobot.com/api/v2](https://app.datarobot.com/api/v2)"
export DATAROBOT_API_TOKEN="<your-api-token>"
- 認証済みの DataRobot CLI (
dr)。ワークロードコマンドが有効になっていること(export DATAROBOT_CLI_FEATURE_WORKLOAD=true)。 - CLIに対応するものがない呼び出し(共有とメタデータの更新)用の
curlとjq。
- Pulumi CLI および DataRobot Pulumi プロバイダー がインストールされ、スタックが設定されていること(
datarobot:endpoint、datarobot:apikey)。 - Pulumiがモデル化していない共有用の
curl。Pulumiを使用するタイミング を参照してください。
次に、実行ごとに異なる値を設定します。
export MODEL="azure/gpt-5-nano-2025-08-07"
export RECIPIENT_USER_ID="" # 共有するユーザー、グループ、または組織のID。スキップする場合は空白のままにします
ワークロードの作成¶
アーティファクトは常に draft として作成されるため、cURLおよびCLIを使用する場合は、最初に importance を設定してワークロードを作成し、次のステップでアーティファクトをロックします。ロックにより、その背後にあるワークロードはロックされた(本番)ライフサイクルに切り替わります:無期限のライフタイム、不変のspec、ロックからロックへの置換の対象。
アーティファクトの spec はコンテナのトポロジ(イメージ、ポート、エントリポイント、環境変数、プローブ)など、デプロイ間でアーティファクトとともに移動するあらゆるものを定義します。レプリカ数、CPU/メモリー、およびオートスケーリングはデプロイ時の懸念事項であり、 runtime.containerGroups[] に存在します。エントリは、グループとコンテナの name によってアーティファクトと一致させられます。コンテナは、プラットフォームが解決し {"source": "api-key"} を介して自動的に注入するワークロードごとのAPIトークンを使用して、DataRobot LLM Gatewayに対して認証を行います。specには値が設定されていないため、トークンが GET /artifacts/{id} の応答に表示されることはありません。また、 DATAROBOT_ENDPOINT もプラットフォームマネージドであるため、設定する必要はありません。完全なリストについては、環境変数のタイプを参照してください。
readinessProbe.path は running 状態への移行を制御します。プラットフォームはこのパスをポーリングし、2xxが返された場合にのみワークロードを running に移行させます。このチュートリアルでは、プローブのポイントを /healthz に設定します。これは、FastAPIプロセスが立ち上がるとすぐに2xxを返します。コンテナは、LLM接続を実行するより深い /readyz エンドポイントも公開しますが、readiness probeは /healthz を指したままにしてください:外部依存関係で running を制御すると、その依存関係に問題が発生するたびにワークロードのステータスがばたつきます。起動をブロックするのではなく、ディープチェックを監視およびランブックのための明示的なエンドポイントとして到達可能に保ちます。
curl -s -X POST "${DATAROBOT_ENDPOINT}/workloads" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg model "$MODEL" \
'{
"name": "agent-service",
"importance": "high",
"artifact": {
"name": "agent-service-artifact",
"type": "service",
"spec": {
"containerGroups": [{
"name": "default",
"containers": [{
"name": "agent",
"imageUri": "otkachnlp/fastapi-server-example:latest",
"port": 8080,
"primary": true,
"entrypoint": ["python", "server.py"],
"environmentVars": [
{"name": "MODEL", "value": $model},
{"source": "api-key"}
],
"readinessProbe": {"path": "/healthz", "port": 8080}
}]
}]
}
},
"runtime": {
"containerGroups": [{
"name": "default",
"replicaCount": 1,
"containers": [{
"name": "agent",
"resourceAllocation": {"cpu": 1, "memory": "512MB"}
}]
}]
}
}'
)" | tee /tmp/workload.json
export WORKLOAD_ID=$(jq -r '.id' /tmp/workload.json)
export ARTIFACT_ID=$(jq -r '.artifactId' /tmp/workload.json)
specをファイルに保存し、$MODELを代入します。
Save the spec to a file, substituting $MODEL:
cat > workload.yaml <<EOF
name: agent-service
importance: high
artifact:
name: agent-service-artifact
type: service
spec:
containerGroups:
- name: default
containers:
- name: agent
imageUri: otkachnlp/fastapi-server-example:latest
port: 8080
primary: true
entrypoint: ["python", "server.py"]
environmentVars:
- name: MODEL
value: $MODEL
- source: api-key
readinessProbe:
path: "/healthz"
port: 8080
runtime:
containerGroups:
- name: default
replicaCount: 1
containers:
- name: agent
resourceAllocation:
cpu: 1
memory: "512MB"
EOF
dr workload create --spec-file workload.yaml --output-format json | tee /tmp/workload.json
export WORKLOAD_ID=$(jq -r '.id' /tmp/workload.json)
export ARTIFACT_ID=$(jq -r '.artifactId' /tmp/workload.json)
datarobot.Artifactリソースは、 pulumi up の終了までに常に locked として解決されるため(Pulumiの使用時期を参照)、このフローには個別のロック手順はありません。 pulumi up はアーティファクトをすでにロックされた状態で作成します。
import pulumi
import pulumi_datarobot as datarobot
artifact = datarobot.Artifact(
"agent-service-artifact",
name="agent-service-artifact",
type="service",
spec={
"container_groups": [{
"name": "default",
"containers": [{
"name": "agent",
"image_uri": "otkachnlp/fastapi-server-example:latest",
"port": 8080,
"primary": True,
"entrypoint": ["python", "server.py"],
"environment_vars": [
{"name": "MODEL", "value": pulumi.Config().require("model")},
{"source": "api-key"},
],
"readiness_probe": {"path": "/healthz", "port": 8080},
}],
}],
},
)
workload = datarobot.Workload(
"agent-service",
name="agent-service",
importance="high",
artifact_id=artifact.artifact_id,
runtime={
"container_groups": [{
"name": "default",
"replica_count": 1,
"containers": [{
"name": "agent",
"resource_allocation": {"cpu": 1, "memory": "512MB"},
}],
}],
},
opts=pulumi.ResourceOptions(replace_on_changes=["artifact_id"]),
)
pulumi.export("artifactId", artifact.artifact_id)
pulumi.export("workloadId", workload.id)
pulumi.export("endpoint", workload.endpoint)
pulumi config set model "azure/gpt-5-nano-2025-08-07"
pulumi up
pulumi upはワークロードがrunningになるまでブロックするため、戻ってきたらサービスの呼び出しに進みます。
アーティファクトのロック¶
アーティファクトを draft から locked に移行させます。このワークロードはドラフトアーティファクトをバックアップする唯一のワークロードであるため、ワークロードのライフサイクルはそれと一緒にロック済みに移行します。ロックは一方向です:ロックされたアーティファクトをドラフトに戻すことはできません。
curl -X PATCH "${DATAROBOT_ENDPOINT}/artifacts/${ARTIFACT_ID}" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"status": "locked"}'
PATCH /artifacts/{artifact_id}は、アーティファクトがまだdraftの状態である間のその他の更新の name、description、およびspecも受け入れます。
dr artifact lock "$ARTIFACT_ID"
ここで実行することはありません。アーティファクトは前の手順で既にロックされた状態で作成されています。
実行を待機する¶
runningに達するまで、ワークロードのステータスをポーリングします。想定される正常なパスの進行: submitted → provisioning → launching → running 。 erroredは最終的な状態であり、ポーリングしてやり過ごす一時的な異常ではありません。これを確認した場合は、待機を続けるのではなく、停止して調査(dr workload get "$WORKLOAD_ID"またはイベントエンドポイント)してください。
curl -s "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" | jq -r '.status'
``` bash dr workload status "$WORKLOAD_ID"
ここで実行することはありません。 pulumi upはすでにrunningまでブロックしています。
サービスの起動¶
ワークロードから呼び出しURLを読み取り、それに対してアプリケーションルートを呼び出します。
ENDPOINT=$(curl -s "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" | jq -r '.endpoint')
curl -X POST "${ENDPOINT}/chat/completions" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"model": "'"${MODEL}"'", "messages": [{"role": "user", "content": "Hello!"}]}'
ENDPOINT=$(dr workload endpoint "$WORKLOAD_ID")
curl -X POST "${ENDPOINT}/chat/completions" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"model": "'"${MODEL}"'", "messages": [{"role": "user", "content": "Hello!"}]}'
ENDPOINT=$(pulumi stack output endpoint)
curl -X POST "${ENDPOINT}/chat/completions" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"model": "'"${MODEL}"'", "messages": [{"role": "user", "content": "Hello!"}]}'
サーバーには、ArXivをツールで呼び出すエージェントもあります。これをテストするには、 {"query": "..."} 本文を使用して ${ENDPOINT}/agent に対して同じ方法で呼び出します。
ワークロードのガバナンス¶
これが本番環境のワークロードになったので、重要度と共有を設定します。
# Raise importance to critical
curl -X PATCH "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"importance": "critical"}'
# Share with another user, group, or organization (skip if RECIPIENT_USER_ID is blank)
if [ -n "$RECIPIENT_USER_ID" ]; then
curl -X PATCH "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}/sharedRoles" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"operation": "updateRoles",
"roles": [{"id": "'"${RECIPIENT_USER_ID}"'", "role": "USER", "shareRecipientType": "user"}]
}'
fi
重要度と共有の更新はREST APIを直接経由します。dr workloadは、作成、読み取り、ライフサイクル、およびログをカバーしており、メタデータや共有の更新はカバーしていません。
# Raise importance to critical
curl -X PATCH "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"importance": "critical"}'
# Share with another user, group, or organization (skip if RECIPIENT_USER_ID is blank)
if [ -n "$RECIPIENT_USER_ID" ]; then
curl -X PATCH "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}/sharedRoles" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"operation": "updateRoles",
"roles": [{"id": "'"${RECIPIENT_USER_ID}"'", "role": "USER", "shareRecipientType": "user"}]
}'
fi
importance は宣言的です。コード内で変更して再適用します。
workload = datarobot.Workload(
"agent-service",
name="agent-service",
importance="critical", # was "high"
artifact_id=artifact.artifact_id,
runtime={ ... },
opts=pulumi.ResourceOptions(replace_on_changes=["artifact_id"]),
)
pulumi up
共有の設定はプロバイダー側では行われません。RESTまたはコンソールを使用して/sharedRolesを管理してください(Pulumiを使用するケースを参照してください)。
if [ -n "$RECIPIENT_USER_ID" ]; then
curl -X PATCH "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}/sharedRoles" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"operation": "updateRoles",
"roles": [{"id": "'"${RECIPIENT_USER_ID}"'", "role": "USER", "shareRecipientType": "user"}]
}'
fi
PATCHのスコープ
PATCH /workloads/{id} は、 name、description、およびimportanceを受け入れます。ランタイムの変更(レプリカ、リソース)については、ローリング置換をトリガーするPATCH /workloads/{id}/settingsを使用します。ランタイム設定を参照してください。
観測¶
ロックされたワークロードは、組織で設定されたテレメトリ保持期間とともに、完全な監視基盤を公開します。監視の概念:保持期間の概要を参照してください。
| 機能 | エンドポイント |
|---|---|
| サービスの正常性、レイテンシー、エラー率 | GET /workloads/{id} (ワークロード上の計算フィールド) |
| ライフサイクルイベント(監査証跡) | GET /workloads/{id}/events |
| 集計リクエスト統計 | GET /workloads/{id}/stats |
| 指標ごとの時系列 | GET /workloads/{id}/stats/{metric_name} |
| レプリカごとのステータス | GET /workloads/{id}/protons/{proton_id}/statusDetails |
これらはすべて、ワークロードを作成するために使用したインターフェイスに関係なく、REST APIから直接読み取られます。 dr workload logsはコンテナのstdout/stderrをカバーしますが、これはこの表のシグナルとは別のシグナルです。
curl -s "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}/events" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}"
curl -s "${DATAROBOT_ENDPOINT}/workloads/${WORKLOAD_ID}/stats" \
-H "Authorization: Bearer ${DATAROBOT_API_TOKEN}"
サマリー¶
このチュートリアルでは、以下を行いました:
- ドラフトアーティファクトにバックアップされ、
importanceが設定されたワークロードを作成し、アーティファクトをロックして、本番環境(無期限)パスに移動させました。 - プラットフォームによって自動的に注入される、ワークロードごとのAPIトークンを使用して、DataRobot LLM Gatewayを呼び出すFastAPIエージェントサービスをデプロイしました。アーティファクトのspecに資格情報が表示されることはありませんでした。
- OpenAI互換の
/chat/completionsルートとLangGraphの/agentルートの両方を呼び出しました。 importanceを引き上げ、ワークロードを別のユーザー、グループ、または組織と共有しました。- 監視サーフェスからイベントを読み取り、統計を集計しました。
次のステップ¶
| リソース | 説明 |
|---|---|
| Workload concepts | オブジェクトモデル、ライフサイクルの状態、およびドラフトとロック済みの決定についての詳細。 |
| Tutorial: Replace the artifact behind a running Workload | エンドポイントを削除せずに新しいコンテナバージョンをシップします。 |
| Deploy an open-weight model from Hugging Face | GPUコンピュートバンドルのサイズを設定し、Hugging Face Hubモデルを提供します。 |
| Instrument a Workload with OpenTelemetry (Python) | 各リクエストの内部にトレース、指標、およびログを追加します。 |