すべてのプロダクト
Search
ドキュメントセンター

Container Service for Kubernetes:TensorRT-LLM を使用した Qwen2 モデル推論サービスのデプロイ

最終更新日:Mar 01, 2026

本トピックでは、TensorRT-LLM および Triton Inference Server を活用し、Alibaba Cloud Container Service for Kubernetes (ACK) 上に Qwen2 大規模言語モデル(LLM)の推論サービスをデプロイする方法について説明します。Fluid を用いたデータオーケストレーションおよびキャッシュ機能により、モデル読み込みパフォーマンスを最適化し、効率的な AI 推論サービスを実現します。

背景情報

Qwen2 大規模言語モデル

Qwen2-1.5B-Instruct は、Alibaba Group の Tongyi Lab が開発した大規模言語モデルです。Transformer アーキテクチャを採用し、15 億パラメーターを有します。このモデルは、Web テキスト、専門書籍、コードなど多様な大量の事前学習データで学習されており、優れた自然言語理解および生成能力を備えています。

Qwen2 シリーズの主な特徴は以下のとおりです:

  • 質問応答、テキスト生成、コード理解など、複数の推論タスクをサポート

  • 実際のユースケースへの適合性を高めるため、命令チューニング(instruction tuning)を実施

  • 比較的適度なモデルサイズであり、GPU を用いた推論デプロイに適している

モデルの詳細および技術仕様については、「Qwen2 公式 GitHub リポジトリ」をご参照ください。

Triton Inference Server

Triton Inference Server は、NVIDIA が開発したオープンソースの推論サービスフレームワークであり、本番環境向けに設計されています。TensorRT、TensorFlow、PyTorch、ONNX Runtime など複数の機械学習フレームワークをバックエンドとしてサポートし、フレームワーク横断でのモデルデプロイを統一します。

Triton の主な利点は以下のとおりです:

  • モデルデプロイおよび管理を簡素化する統一推論インターフェイス

  • GPU 利用率向上のための動的バッチ処理(dynamic batching)対応

  • 高スループット推論のための最適化された同時処理機能

  • 包括的なモニタリングおよびメトリック収集機能

Triton Inference Server の詳細については、「Triton Inference Server 公式 GitHub リポジトリ」をご参照ください。

TensorRT-LLM 最適化エンジン

TensorRT-LLM は、NVIDIA が大規模言語モデル向けに最適化した推論エンジンです。LLM を高度に最適化された TensorRT 実行エンジンへコンパイルすることで、NVIDIA GPU 上での卓越した推論パフォーマンスを実現します。

主な機能は以下のとおりです:

  • モデル量子化および最適化による推論速度の大幅向上

  • テンソル並列処理およびパイプライン並列処理のサポート

  • TensorRT-LLM Backend を介した Triton との深く統合された連携

  • FP16 や INT8 など、パフォーマンスと精度のバランスを取る複数の精度モード対応

技術的な詳細については、「TensorRT-LLM 公式 GitHub リポジトリ」をご参照ください。

前提条件

デプロイを開始する前に、環境が以下の要件を満たしていることを確認してください:

  • GPU 環境の準備:NVIDIA A10 GPU を含む ACK Pro マネージドクラスター を作成済みであること。クラスターの Kubernetes バージョンは 1.22 以降である必要があります。

    推奨ドライバーのバージョン:NVIDIA ドライバー バージョン 525 を使用します。GPU ノードプールにラベル ack.aliyun.com/nvidia-driver-version:525.105.17 を付与して指定します。詳細な手順については、「GPU ドライバーのスペックアップドキュメント」をご参照ください。

  • Fluid コンポーネントのインストール:クラスター内に Fluid データオーケストレーションおよびキャッシュシステムをインストール済みであること。未インストールの場合は、「Fluid インストールガイド」に従ってインストールしてください。

  • Arena ツールの構成:モデルサービスのデプロイおよび管理を行う Arena コマンドラインインターフェイス(CLI)ツールをインストール・構成済みであること。インストール手順については、「Arena インストールドキュメント」をご参照ください。

  • OSS ストレージのセットアップ:Alibaba Cloud Object Storage Service (OSS) を有効化し、モデルファイルを格納するバケットを作成済みであること。「OSS クイックスタート」および「バケットの作成」をご参照ください。

  • 権限の構成:ご利用の Alibaba Cloud アカウントが OSS に対する読み書き権限および ACK クラスターに対する管理権限を有していること。

ステップ 1:Fluid データセットおよびキャッシュの構成

本ステップでは、モデルデータの管理および高性能キャッシュを提供するため、Fluid Dataset および JindoRuntime を作成します。Dataset はデータを整理し、JindoRuntime は分散キャッシュを提供することで、モデル読み込みおよび推論パフォーマンスを大幅に向上させます。

パフォーマンスに関するヒント:メモリキャッシュを活用すると、モデル読み込み時間は数分から数秒に短縮されます。

  1. OSS アクセス認証情報の作成

    Kubernetes Secret を作成し、OSS の認証情報を格納します。

    kubectl apply -f-<<EOF                                            
    apiVersion: v1
    kind: Secret
    metadata:
      name: fluid-oss-secret
    stringData:
      fs.oss.accessKeyId: <YourAccessKey ID>
      fs.oss.accessKeySecret: <YourAccessKey Secret>
    EOF

    セキュリティに関する注意事項<YourAccessKey ID> および <YourAccessKey Secret> を、実際の Alibaba Cloud AccessKey ペアに置き換えてください。AccessKey ペアの取得方法については、「AccessKey 管理ドキュメント」をご参照ください。

    正常終了時には、以下の出力が表示されます:

    secret/fluid-oss-secret created
  2. Dataset および JindoRuntime の構成

    Dataset および JindoRuntime リソースを定義するファイル dataset.yaml を作成します。Dataset はデータソースを記述し、JindoRuntime は分散キャッシュを提供します。

    構成の詳細については、「Fluid 構成ドキュメント」をご参照ください。

    # Dataset リソースを作成し、OSS データソースを構成します。
    apiVersion: data.fluid.io/v1alpha1
    kind: Dataset
    metadata:
      name: qwen2-oss
    spec:
      mounts:
      - mountPoint: oss://<oss_bucket>/qwen2-1.5b  # 実際の OSS バケット名に置き換えてください。
        name: qwen2
        path: /
        options:
          fs.oss.endpoint: <oss_endpoint>  # 実際の OSS エンドポイントに置き換えてください。
        encryptOptions:
          - name: fs.oss.accessKeyId
            valueFrom:
              secretKeyRef:
                name: fluid-oss-secret
                key: fs.oss.accessKeyId
          - name: fs.oss.accessKeySecret
            valueFrom:
              secretKeyRef:
                name: fluid-oss-secret
                key: fs.oss.accessKeySecret
      accessModes:
        - ReadWriteMany
    ---
    # JindoRuntime リソースを作成し、キャッシュポリシーを構成します。
    apiVersion: data.fluid.io/v1alpha1
    kind: JindoRuntime
    metadata:
      name: qwen2-oss
    spec:
      replicas: 2
      tieredstore:
        levels:
          - mediumtype: MEM
            volumeType: emptyDir
            path: /dev/shm
            quota: 20Gi
            high: "0.95"
            low: "0.7"
      fuse:
        properties:
          fs.oss.read.buffer.size: "8388608"  # 8 MB の読み取りバッファー。
          fs.oss.download.thread.concurrency: "200"  # 同時ダウンロードスレッド数。
          fs.oss.read.readahead.max.buffer.count: "200"  # 読み-ahead バッファー数。
          fs.oss.read.sequence.ambiguity.range: "2147483647"  # シークエンス読み取り範囲。
        args:
          - -oauto_cache
          - -oattr_timeout=1
          - -oentry_timeout=1
          - -onegative_timeout=1

    構成に関する補足

    • mountPoint:モデルファイルが格納されている OSS 内のパスを指します。

    • quota: 20Gi:キャッシュ用に 20 GB のメモリを割り当てます。

    • replicas: 2:可用性向上のため、2 つのキャッシュインスタンスをデプロイします。

  3. デプロイメントリソースの構成

    構成ファイルを適用して、Dataset および JindoRuntime リソースを作成します:

    kubectl apply -f dataset.yaml

    正常終了時には、以下の出力が表示されます:

    dataset.data.fluid.io/qwen2-oss created
    jindoruntime.data.fluid.io/qwen2-oss created

    これにより、Dataset および JindoRuntime リソースが正常に作成・実行中であることが確認できます。

  4. デプロイメント状態の確認

    Dataset のデプロイメント状態およびキャッシュ状態を確認します:

    kubectl get dataset qwen2-oss

    期待される出力例:

    NAME        UFS TOTAL SIZE   CACHED   CACHE CAPACITY   CACHED PERCENTAGE   PHASE   AGE
    qwen2-oss   0.00B            0.00B    20.00GiB         0.0%                Bound   57s

    状態に関する補足PHASE: Bound は Dataset が正常にバインドされたことを示します。CACHE CAPACITY: 20.00GiB は割り当てられた 20 GB のメモリキャッシュ領域を示します。

ステップ 2:モデル推論環境の構築

本ステップでは、Fluid Dataflow を活用して、モデルデプロイの主要な工程を自動化します。具体的には、ModelScope からの Qwen2 モデルのダウンロード、TensorRT-LLM 形式への変換、推論エンジンの構築、およびキャッシュへの事前読み込み(preload)を実行します。この宣言型アプローチにより、一貫性と再現性のあるデプロイメントが保証されます。

Dataflow は、複雑なマルチステップ操作を自動化されたワークフローにパッケージ化します。これにより、手動作業が削減され、デプロイメント効率が向上します。

  1. Dataflow 構成ファイルの作成

    3 ステップの自動化ワークフローを定義するファイル dataflow.yaml を作成します:

    1. ModelScope から Qwen2-1.5B-Instruct ベースモデルをダウンロード

    2. TensorRT-LLM ツールチェーンを用いてモデルを変換し、推論エンジンを構築

    3. Dataload を用いて最適化済みモデルデータをキャッシュに事前読み込み

    # ステップ 1:ModelScope から Qwen2 モデルをダウンロードします。
    apiVersion: data.fluid.io/v1alpha1
    kind: DataProcess
    metadata:
      name: step1-download-model
    spec:
      dataset:
        name: qwen2-oss
        namespace: default
        mountPath: /mnt/models/
      processor:
        script:
          image: ac2-registry.cn-hangzhou.cr.aliyuncs.com/ac2/base:ubuntu22.04
          imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure
          command:
          - bash
          source: |
            #!/bin/bash
            echo "モデルのダウンロードを開始します..."
            if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct" ]; then
                echo "モデルディレクトリが存在します。ダウンロードをスキップします。"
            else
                echo "Git LFS をインストールし、モデルをダウンロードします..."
                apt update && apt install -y git git-lfs
                git clone https://www.modelscope.cn/qwen/Qwen2-1.5B-Instruct.git Qwen2-1.5B-Instruct
                mv Qwen2-1.5B-Instruct ${MODEL_MOUNT_PATH}
                echo "モデルのダウンロードが完了しました。"
            fi
          env:
          - name: MODEL_MOUNT_PATH
            value: "/mnt/models"
    ---
    # ステップ 2:モデルを変換し、TensorRT-LLM エンジンを構築します。
    apiVersion: data.fluid.io/v1alpha1
    kind: DataProcess
    metadata:
      name: step2-trtllm-convert
    spec:
      runAfter:
        kind: DataProcess
        name: step1-download-model
        namespace: default
      dataset:
        name: qwen2-oss
        namespace: default
        mountPath: /mnt/models/
      processor:
        script:
          image: kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/tritonserver-build:24.07-trtllm-python-py3
          imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure
          command:
          - bash
          source: |
            #!/bin/bash
            set -ex
            
            echo "モデル変換を開始します..."
            cd /tensorrtllm_backend/tensorrt_llm/examples/qwen
            
            # チェックポイントを変換します。
            if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-ckpt" ]; then
                echo "チェックポイントが存在します。変換をスキップします。"
            else
                echo "モデルチェックポイントを変換します..."
                python3 convert_checkpoint.py \
                  --model_dir ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct \
                  --output_dir /root/Qwen2-1.5B-Instruct-ckpt \
                  --dtype float16
                mv /root/Qwen2-1.5B-Instruct-ckpt ${MODEL_MOUNT_PATH}
                echo "チェックポイントの変換が完了しました。"
            fi
            
            sleep 2
            
            # TensorRT エンジンを構築します。
            if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-engine" ]; then
                echo "エンジンが存在します。構築をスキップします。"
            else
                echo "TensorRT-LLM エンジンを構築します..."
                trtllm-build \
                  --checkpoint_dir ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-ckpt \
                  --gemm_plugin float16 \
                  --paged_kv_cache enable \
                  --output_dir /root/Qwen2-1.5B-Instruct-engine
                mv /root/Qwen2-1.5B-Instruct-engine ${MODEL_MOUNT_PATH}
                echo "エンジンの構築が完了しました。"
            fi
            
            # Triton モデルを構成します。
            if [ -d "${MODEL_MOUNT_PATH}/tensorrtllm_backend" ]; then
                echo "構成が存在します。構成をスキップします。"
            else
                echo "Triton モデルを構成します..."
                cd /tensorrtllm_backend
                cp all_models/inflight_batcher_llm/ qwen2_ifb -r
                
                export QWEN2_MODEL=${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct
                export ENGINE_PATH=${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-engine
                
                # 各コンポーネントの構成ファイルを生成します。
                python3 tools/fill_template.py -i qwen2_ifb/preprocessing/config.pbtxt \
                  tokenizer_dir:${QWEN2_MODEL},triton_max_batch_size:8,preprocessing_instance_count:1
                python3 tools/fill_template.py -i qwen2_ifb/postprocessing/config.pbtxt \
                  tokenizer_dir:${QWEN2_MODEL},triton_max_batch_size:8,postprocessing_instance_count:1
                python3 tools/fill_template.py -i qwen2_ifb/tensorrt_llm_bls/config.pbtxt \
                  triton_max_batch_size:8,decoupled_mode:False,bls_instance_count:1,accumulate_tokens:False
                python3 tools/fill_template.py -i qwen2_ifb/ensemble/config.pbtxt \
                  triton_max_batch_size:8
                python3 tools/fill_template.py -i qwen2_ifb/tensorrt_llm/config.pbtxt \
                  triton_backend:tensorrtllm,triton_max_batch_size:8,decoupled_mode:False,\
                  max_beam_width:1,engine_dir:${ENGINE_PATH},max_tokens_in_paged_kv_cache:1280,\
                  max_attention_window_size:1280,kv_cache_free_gpu_mem_fraction:0.5,\
                  exclude_input_in_output:True,enable_kv_cache_reuse:False,\
                  batching_strategy:inflight_fused_batching,max_queue_delay_microseconds:0
                
                mkdir -p ${MODEL_MOUNT_PATH}/tensorrtllm_backend
                mv /tensorrtllm_backend/qwen2_ifb ${MODEL_MOUNT_PATH}/tensorrtllm_backend
                echo "Triton 構成が完了しました。"
            fi
          env:
          - name: MODEL_MOUNT_PATH
            value: "/mnt/models"
          resources:
            requests:
              cpu: 2
              memory: 10Gi
              nvidia.com/gpu: 1
            limits:
              cpu: 12
              memory: 30Gi
              nvidia.com/gpu: 1
    ---
    # ステップ 3:キャッシュデータを事前読み込みします。
    apiVersion: data.fluid.io/v1alpha1
    kind: DataLoad
    metadata:
      name: step3-warmup-cache
    spec:
      runAfter:
        kind: DataProcess
        name: step2-trtllm-convert
        namespace: default
      dataset:
        name: qwen2-oss
        namespace: default
      loadMetadata: true
      target:
      - path: /Qwen2-1.5B-Instruct-engine
      - path: /tensorrtllm_backend

    この Dataflow 構成により、生モデルの取得から本番運用可能な推論サービスの構成まで、エンドツーエンドのモデルデプロイメントプロセスが自動化されます。

  2. Dataflow ワークフローのデプロイ

    Dataflow 構成ファイルを適用し、自動化されたワークフローを作成します:

    kubectl create -f dataflow.yaml

    正常終了時には、以下の出力が表示されます:

    dataprocess.data.fluid.io/step1-download-model created
    dataprocess.data.fluid.io/step2-trtllm-convert created
    dataload.data.fluid.io/step3-warmup-cache created

    これにより、全 3 ステップのカスタムリソースが正常に作成されたことが確認できます。

  3. 実行進捗の監視

    Dataflow の実行状態を追跡し、すべてのステップが完了するまで待ちます:

    kubectl get dataprocess

    実行中の状態遷移例:

    NAME                   DATASET     PHASE      AGE   DURATION
    step1-download-model   qwen2-oss   Running    2m    -
    step2-trtllm-convert   qwen2-oss   Pending    0s    -

    完了時の出力例:

    NAME                   DATASET     PHASE      AGE   DURATION
    step1-download-model   qwen2-oss   Complete   23m   3m2s
    step2-trtllm-convert   qwen2-oss   Complete   20m   19m58s

    状態に関する補足Running はステップが実行中であることを示します。Complete はステップが正常終了したことを示します。Pending はそのステップが先行ステップの完了を待っていることを示します。

完全なモデル準備プロセスには通常 20~30 分かかります。実際の所要時間はネットワーク状況および GPU の性能に依存します。

ステップ 3:Triton 推論サービスのデプロイ

Arena を用いて、TensorRT-LLM で最適化された Qwen2 推論サービスをデプロイします。Triton Server は RESTful および gRPC インターフェイスを公開します。

  1. Arena を用いたサービスのデプロイ

    カスタム推論サービスをデプロイするコマンドを実行します:

    主な構成に関する補足

    • サービス名:qwen2-chat、バージョン:v1

    • リソース割り当て:GPU 1 台、レプリカ 1 台

    • ポート構成:HTTP ポート 8000、gRPC ポート 8001、メトリックポート 8002

    • データマウント:--data フラグを用いて Fluid PVC を /mnt/models にマウント

    arena serve custom \
      --name=qwen2-chat \
      --version=v1 \
      --gpus=1 \
      --replicas=1 \
      --restful-port=8000 \
      --readiness-probe-action="tcpSocket" \
      --readiness-probe-action-option="port: 8000" \
      --readiness-probe-option="initialDelaySeconds: 30" \
      --readiness-probe-option="periodSeconds: 30" \
      --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/tritonserver:24.07-trtllm-python-py3 \
      --data=qwen2-oss:/mnt/models \
      "tritonserver \
        --model-repository=/mnt/models/tensorrtllm_backend/qwen2_ifb \
        --http-port=8000 \
        --grpc-port=8001 \
        --metrics-port=8002 \
        --disable-auto-complete-config \
        --backend-config=python,shm-region-prefix-name=prefix0_"

    正常にデプロイされた場合、以下の出力が表示されます:

    service/qwen2-chat-v1 created
    deployment.apps/qwen2-chat-v1-custom-serving created
    INFO[0003] The Job qwen2-chat has been submitted successfully
    INFO[0003] You can run `arena serve get qwen2-chat --type custom-serving -n default` to check the job status

    これにより、推論サービスが Kubernetes クラスターに正常に送信されたことが確認できます。

  2. サービス状態の確認

    推論サービスの詳細および実行状態を確認します:

    arena serve get qwen2-chat

    サービスが正常に実行中の場合、以下の出力が表示されます:

    Name:       qwen2-chat
    Namespace:  default
    Type:       Custom
    Version:    v1
    Desired:    1
    Available:  1
    Age:        2m
    Address:    192.168.10.15
    Port:       RESTFUL:8000
    GPU:        1
    
    Instances:
      NAME                                           STATUS   AGE  READY  RESTARTS  GPU  NODE
      ----                                           ------   ---  -----  --------  ---  ----
      qwen2-chat-v1-custom-serving-657869c698-hl665  Running  2m   1/1    0         1    cn-hangzhou.192.168.10.15

    準備完了の指標Available: 1 および READY: 1/1 は、サービスが推論リクエストの受付に完全に準備できていることを意味します。

サービスの起動には通常 1~2 分かかります。初期化中には、Available フィールドの値が 0 から 1 に変化します。

ステップ 4:推論サービスのテスト

ローカルポートフォワーディングおよび API 呼び出しを用いて、推論サービスの機能およびパフォーマンスをテストします。

  1. ポートフォワーディングの設定

    サービスのテスト用にローカルポートフォワーディングチャネルを作成します:

    ポートフォワーディングコマンドは現在のターミナルセッションで実行されます。Ctrl+C を押すと停止できます。

    kubectl port-forward svc/qwen2-chat-v1 8000:8000

    正常終了時には、以下の出力が表示されます:

    Forwarding from 127.0.0.1:8000 -> 8000
    Forwarding from [::1]:8000 -> 8000

    これにより、localhost:8000 で推論サービスにアクセスできるようになります。

  2. 推論リクエストの送信

    curl を用いてモデルに対して推論リクエストを送信します:

    curl -X POST localhost:8000/v2/models/ensemble/generate \
      -H "Content-Type: application/json" \
      -d '{
        "text_input": "機械学習とは何ですか?",
        "max_tokens": 50,
        "bad_words": "",
        "stop_words": "",
        "pad_id": 2,
        "end_id": 2
      }'

    期待される応答例:

    {
      "context_logits": 0.0,
      "cum_log_probs": 0.0,
      "generation_logits": 0.0,
      "model_name": "ensemble",
      "model_version": "1",
      "output_log_probs": [0.0, 0.0, 0.0, 0.0],
      "sequence_end": false,
      "sequence_id": 0,
      "sequence_start": false,
      "text_output": " 機械学習とは、明示的にプログラミングすることなく、コンピューターシステムがデータからパターンやルールを学習する人工知能の手法です。アルゴリズムを用いて大量のデータを分析することで、機械学習モデルは複雑な関係性を特定し、予測や意思決定を行うことができます。"
    }

    成功の検証text_output フィールドにモデルが生成した関連性のある回答が含まれている場合、推論サービスが正しく動作していることを確認できます。

テストに関するヒント

  • モデルの汎化能力をテストするために、異なる質問を試してください

  • 出力長を制御するため、max_tokens パラメーターを調整してください

  • 応答時間および出力品質を観察してください

(任意)ステップ 5:環境のクリーンアップ

推論サービスが不要になった場合、以下の手順で関連リソースをクリーンアップします:

重要なお知らせ:クリーンアップ処理では、モデルデータおよびサービス構成を含むすべての関連リソースが削除されます。実行前に重要なデータをバックアップしてください。

  1. 推論サービスの削除

    Arena を用いてデプロイ済みのサービスを削除します:

    arena serve delete qwen2-chat

    削除が成功したことを確認します:

    INFO[0001] Deleting service: qwen2-chat
    INFO[0002] Service qwen2-chat deleted successfully
  2. Fluid リソースのクリーンアップ

    Dataset および JindoRuntime リソースを削除します:

    kubectl delete dataset qwen2-oss
    kubectl delete jindoruntime qwen2-oss
  3. アクセス認証情報の削除

    OSS アクセスキーをクリーンアップします:

    kubectl delete secret fluid-oss-secret

クリーンアップ後、以下のコマンドですべてのリソースが削除されたことを確認できます:kubectl get all -l app=qwen2-chat