附註:
- 此教學課程需要存取 Oracle Cloud。若要註冊免費帳戶,請參閱開始使用 Oracle Cloud Infrastructure Free Tier 。
- 其使用 Oracle Cloud Infrastructure 證明資料、租用戶以及區間的範例值。完成實驗室時,請將這些值替代為雲端環境特定的值。
在 Oracle Kubernetes 引擎 (OKE) 上部署 OpenAI vLLM Production Stack
簡介
採用大型語言模型 (LLM) 進行生產工作負載的組織面臨關鍵基礎架構決策:依賴第三方推論 API 或部署自行代管的推論堆疊。自主代管的部署具有顯著的優勢:完整的資料隱私與合規控制、子 100 毫秒的推論延遲,可免除往返網路、大規模可預測的成本,以及無供應商綁定的自由微調和提供任何開放原始碼模型。
不過,從頭開始建立生產級 LLM 推論堆疊相當複雜。它需要 GPU 感知容器協調、跨多個模型複本的智慧型要求路由、大型模型權重的永久儲存體,以及持續監控,而且全都能夠可靠地整合及執行。
Oracle Cloud Infrastructure 提供多種 AI 推論路徑。OCI Generative AI 服務提供完全託管的體驗,將專用 AI 叢集隔離到您的租用戶中,適用於想要快速開始使用受支援模型的團隊。本教學課程採用另一種方法:在 OKE 上部署您自己的推論堆疊。此路徑是專為需要精確控制 GPU 驅動程式、CUDA 版本、模型組態及提供參數的團隊所設計,或是訓練和微調自訂模型並想要直接提供服務的團隊所設計。OCI 提供由超低延遲 RDMA 叢集網路連線的 NVIDIA A10、A100 和 H100 GPU 裸機 GPU 執行個體,讓您享有與內部部署相同層級的硬體控制,同時享有雲端彈性。
vLLM Production Stack 透過在 vLLM 上建置的開放原始碼 Kubernetes 原生平台 (即 Meta、Mistral AI 和 IBM 等組織在生產中使用的高輸送量推論引擎),解決了自行代管推論的複雜性。透過高效率的 GPU 記憶體管理和 KV 快取最佳化,與標準服務架構相比,傳輸量最高可提高 24x。與 OKE 和 OCI GPU 資源配置結合,您將獲得具備企業級網路、儲存及安全性的符合生產環境需求推論平台。本教學課程中使用的 OCI 部署命令檔是在官方 vLLM 生產堆疊儲存區域中提供和維護。
本教學課程將逐步引導您完成 OKE 上的 vLLM Production Stack 部署,從基礎架構佈建到執行您的第一個推論要求。
注意:本教學課程會逐步佈建使用 OCI CLI 的資源,協助您瞭解 GPU 推論部署所需的 OCI 雲端資源完整流程。對於生產環境,建議使用 Terraform 或 OCI Resource Manager (Shepherd) 為可重複且由版本控制的部署編碼此基礎架構。

本教學課程使用下列 OCI 服務:
| 服務 | 目的 |
|---|---|
| Oracle Kubernetes 引擎 (OKE) | 適用於容器協調和 GPU 工作負載排程的受管理 Kubernetes 叢集 |
| OCI Compute (GPU 資源配置) | 用於模型推論的 NVIDIA A10 (24GB) 和 A100 (80GB) GPU 執行個體 |
| OCI 區塊磁碟區 | 透過可設定的效能層提供模型權重的永久儲存 |
| OCI 虛擬雲端網絡 (VCN) | 網路基礎架構,包括子網路、閘道和安全清單 |
| OCI 負載平衡器 | 外部存取推論端點 |
| OCI 堡壘主機 | 專用叢集存取的受管理 SSH 通道 |
| OCI Object Storage | 使用預先認證要求 (PAR) URL 的替代模型來源 |
目標
在本教學中,您將:
- 使用 OCI CLI 部署具備啟用 GPU 之節點集區的 OKE 叢集
- 設定 Kubernetes 工作負載的 OCI 網路 (VCN、子網路、閘道)
- 安裝並設定用於 GPU 排程的 NVIDIA 裝置外掛程式 Name
- 展開 GPU 節點檔案系統以使用完整的開機磁碟區容量
- 使用與 OpenAI 相容的推論端點部署 vLLM Production Stack
- 對 OpenAI GPT-OSS-20B 模型測試 API 要求的 LLM 推論
- 在裸機資源配置上為大型模型設定多 GPU 張量平行程度
- 使用 OCI Object Storage 作為替代模型來源
- 清除所有 OCI 資源以避免持續收費
必備條件
- 一個 Oracle Cloud Infrastructure 帳戶,包含下列項目:
- 具備建立及管理 OKE 叢集權限的區間
- 您所需資源配置的 GPU 運算配額 (例如
VM.GPU.A10.1或BM.GPU.A100-v2.8)。如果您沒有 GPU 配額,請透過支援回報項目要求 - 建立 VCN、子網路、網際網路閘道以及負載平衡器的權限
- 存取 OCI Block Volumes 以取得永久儲存
- 存取 OCI 物件儲存 (適用於進階模型載入區段)
注意:本教學課程中的輸出和螢幕擷取畫面範例使用 us-chicago-1 。您可以透過設定
OCI_REGION,在任何支援的區域中部署。GPU 容量因區域和可用性網域而異,因此在部署之前,請確認您的目標 GPU 資源配置可供使用。請查看依區域區分的 GPU 資源配置可用性,如果您發生容量錯誤,請準備好嘗試其他可用性網域 (GPU_AD_INDEX)。
注意:本教學課程提供付費 GPU 資源 (例如
VM.GPU.A10.1)。它不是 OCI 永遠免費工作負載。完成時一律執行清除步驟,以避免持續收費。
-
OCI CLI 已安裝並配置
oci setup config -
已安裝 jq 以進行 JSON 剖析
-
已安裝 kubectl
-
已安裝 Helm
-
堡壘主機存取的 SSH 金鑰組 (例如
~/.ssh/id_rsa和~/.ssh/id_rsa.pub)。視需要使用ssh-keygen -t rsa -b 4096產生一個 -
熟悉 Kubernetes 概念 (Pod、服務、部署、節點集區)
注意:本教學課程部署
openai/gpt-oss-20b,這是來自 OpenAI 的 Apache 2.0 授權模型。不需要 Hugging Face 權杖。如果您想要部署關卡模型 (例如 Meta Llama 3.1),您將需要一個具有 API 權杖的 Hugging Face 帳戶。
工作 1:設定環境變數
請先設定必要的 OCI 組態後再部署基礎架構。
-
在 OCI 主控台中找到您的區間 OCID。導覽至身分識別與安全 > 區間,然後按一下您的目標區間並複製 OCID。
oci iam compartment list --query 'data[].{name:name,id:id}' --output table
-
匯出必要的環境變數。
export OCI_COMPARTMENT_ID="ocid1.compartment.oc1..xxxxx" -
您可以選擇設定下列任一環境變數來覆寫預設組態。
變數 Default 描述 OCI_REGIONus-ashburn-1用於部署的 OCI 區域 OCI_PROFILEDEFAULTOCI CLI 組態設定檔 CLUSTER_NAMEproduction-stackOKE 叢集的名稱 GPU_SHAPEVM.GPU.A10.1節點集區的 GPU 運算資源配置 GPU_NODE_COUNT1集區中的 GPU 節點數目 GPU_BOOT_VOLUME_GB200GPU 節點的開機磁區大小 (GB) CPU_BOOT_VOLUME_GB100CPU 節點的開機磁區大小 (GB) GPU_AD_INDEX1GPU 位置的可用性網域索引 (以 0 為基礎) PRIVATE_CLUSTERtrue對公用 Kubernetes API 端點設為 falseKUBERNETES_VERSIONv1.31.10OKE 叢集的 Kubernetes 版本 例如,若要部署兩個 A100 GPU 節點:
export OCI_COMPARTMENT_ID="ocid1.compartment.oc1..xxxxx" export GPU_SHAPE="BM.GPU.A100-v2.8" export GPU_NODE_COUNT="2" -
請複查可用的 GPU 資源配置,並根據您的模型大小需求選取一個資源配置。
形狀 GPU GPU 型態 GPU 記憶體 建議為 VM.GPU.A10.11 NVIDIA A10 24 GB 7B – 13B 參數模型 VM.GPU.A10.22 NVIDIA A10 48 GB Tensor 與小型模型平行 BM.GPU4.88 NVIDIA A100 40 GB 320 GB 70B 模型,符合成本效益 BM.GPU.A100-v2.88 NVIDIA A100 80 GB 640 GB 70B+ 參數模型 BM.GPU.H100.88 NVIDIA H100 640 GB 最大的模型,RDMA 支援 備註:裸機資源配置 (
BM.*) 提供專屬硬體,不會產生虛擬化負荷,同時支援多 GPU Tensor 平行機制。虛擬機器資源配置 (VM.*) 對小型模型而言更具成本效益。注意:本教學課程使用
VM.GPU.A10.1(具有 24 GB GPU 記憶體的單一 NVIDIA A10) 來部署openai/gpt-oss-20b,這是一款通常適用於單一 A10 GPU 之 3.6B 作用中參數的專家混合 (MoE) 模型。進階部分針對大型模型 (例如 Llama 3.1 70B) 使用BM.GPU.H100.8示範多 GPU 組態。
工作 2:使用自動命令檔部署 (快速入門)
vLLM Production Stack 包含自動化部署指令碼,可佈建所有 OCI 資源,並使用單一指令部署推論堆疊。使用此方法進行快速部署。任務 3 到 10 會針對想要自訂處理的使用者個別涵蓋每個步驟。
-
複製 vLLM Production Stack 儲存區域。
git clone https://github.com/vllm-project/production-stack.git cd production-stack/deployment_on_cloud/oci -
匯出您的區間 OCID。
export OCI_COMPARTMENT_ID="ocid1.compartment.oc1..xxxxx" -
執行部署指令碼。
./entry_point.sh setup
若為公用叢集 (
PRIVATE_CLUSTER=false),則設定會以單一命令建立所有基礎架構,並部署 vLLM 堆疊。將 Helm 值檔案傳送為第二個引數:PRIVATE_CLUSTER=false ./entry_point.sh setup ./production_stack_specification.yaml若為專用叢集 (預設值),則設定會建立基礎架構,但無法直接連線 Kubernetes API。開啟個別的終端機並啟動通道,然後部署:
# In a separate terminal, start the SSH tunnel (auto-reconnects on drops): ./entry_point.sh tunnel # Back in the first terminal, deploy vLLM: ./entry_point.sh deploy-vllm ./production_stack_specification.yaml -
驗證部署是否在執行中。
kubectl get pods預期輸出:
NAME READY STATUS RESTARTS AGE vllm-deployment-router-xxxxxxxxxx-xxxxx 1/1 Running 0 5m vllm-gpt-oss-deployment-vllm-xxxxxxxxxx-xxxxx 1/1 Running 0 5m
注意:如果兩個 Pod 都顯示
Running狀態,您的部署就緒。先跳過工作 10:測試推論端點。
注意: GPU 執行個體受 OCI 容量限制。如果指令碼停留在「等待 GPU 節點」迴圈超過 15 分鐘,則選取的可用性網域中可能無法使用 GPU 資源配置。檢查節點集區狀態與
oci ce node-pool get,並尋找「超出主機容量」錯誤。若要解決此問題,請使用./entry_point.sh cleanup進行清除,然後使用不同的可用性網域 (例如GPU_AD_INDEX=0或GPU_AD_INDEX=2) 或其他 GPU 資源配置 (例如GPU_SHAPE=VM.GPU.A10.2) 重新部署。
注意:部署命令檔使用會產生大量成本的 GPU 執行處理 (單一 A10 GPU 的每日約 50 美元)。完成時一律執行
./entry_point.sh cleanup,以避免持續收費。
作業 3:建立 VCN 和網路
建立 OKE 叢集所需的 OCI 網路基礎架構。這包括虛擬雲端網路 (VCN)、閘道、路由表、安全清單以及子網路。每個網路資源會在幾秒鐘內建立;完整的一組指令會在 2 分鐘內完成。
-
建立一個含有
10.0.0.0/16CIDR 區塊的 VCN。VCN_ID=$(oci network vcn create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --display-name "${CLUSTER_NAME}-vcn" \ --cidr-blocks '["10.0.0.0/16"]' \ --dns-label "prodstack" \ --query "data.id" \ --raw-output) -
建立公用子網路路由的網際網路閘道。
IGW_ID=$(oci network internet-gateway create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-igw" \ --is-enabled true \ --query "data.id" \ --raw-output) -
建立專用子網路輸出流量的 NAT 閘道。
NAT_ID=$(oci network nat-gateway create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-nat" \ --query "data.id" \ --raw-output) -
建立服務閘道以存取 Oracle Services Network。OKE 雲端控制器會使用 Oracle 服務來初始化工作者節點 (設定可用性網域標籤、移除初始化原則)。若無服務閘道,GPU 節點可能會維持未起始狀態,而區塊磁碟區佈建將會失敗。
SGW_SERVICE_ID=$(oci network service list \ --query "data[?contains(name, 'All') && contains(name, 'Services')].id | [0]" \ --raw-output) SGW_SERVICE_NAME=$(oci network service list \ --query "data[?contains(name, 'All') && contains(name, 'Services')].\"cidr-block\" | [0]" \ --raw-output) SGW_ID=$(oci network service-gateway create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-sgw" \ --services "[{\"serviceId\": \"${SGW_SERVICE_ID}\"}]" \ --query "data.id" \ --raw-output) -
建立專用和公用子網路的路由表。
PRIVATE_RT_ID=$(oci network route-table create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-private-rt" \ --route-rules "[ {\"cidrBlock\": \"0.0.0.0/0\", \"networkEntityId\": \"${NAT_ID}\"}, {\"destination\": \"${SGW_SERVICE_NAME}\", \"destinationType\": \"SERVICE_CIDR_BLOCK\", \"networkEntityId\": \"${SGW_ID}\"} ]" \ --query "data.id" \ --raw-output) PUBLIC_RT_ID=$(oci network route-table create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-public-rt" \ --route-rules "[{\"cidrBlock\": \"0.0.0.0/0\", \"networkEntityId\": \"${IGW_ID}\"}]" \ --query "data.id" \ --raw-output)注意:專用路由表有兩個規則:用於一般網際網路存取的 NAT 閘道路由 (提取容器映像檔、下載模型),以及用於直接存取 Oracle Services Network 的服務閘道路由。服務閘道路由至關重要。若無,OKE 雲端控制器便無法初始化工作節點,以防止區塊磁碟區佈建。公用路由表使用網際網路閘道存取負載平衡器。
-
使用 OKE 所需的傳入和傳出規則建立安全清單。
SL_ID=$(oci network security-list create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-sl" \ --egress-security-rules '[{"destination": "0.0.0.0/0", "protocol": "all", "isStateless": false}]' \ --ingress-security-rules '[ {"source": "0.0.0.0/0", "protocol": "6", "isStateless": false, "tcpOptions": {"destinationPortRange": {"min": 22, "max": 22}}, "description": "SSH access"}, {"source": "10.0.0.0/16", "protocol": "all", "isStateless": false, "description": "VCN internal traffic"}, {"source": "10.244.0.0/16", "protocol": "all", "isStateless": false, "description": "Kubernetes pods CIDR"}, {"source": "10.96.0.0/16", "protocol": "all", "isStateless": false, "description": "Kubernetes services CIDR"}, {"source": "0.0.0.0/0", "protocol": "1", "isStateless": false, "icmpOptions": {"type": 3, "code": 4}, "description": "Path MTU discovery"} ]' \ --query "data.id" \ --raw-output)安全性備註:此安全性清單的範圍廣泛,以簡化操作。若為生產環境,請將 SSH 限制在堡壘主機子網路和您的 IP 範圍,而且偏好個別的安全清單或每個子網路的 NSG,因此負載平衡器子網路不允許使用來自
0.0.0.0/0的 SSH。安全預設值:從將 SSH 限制為您的公用 IP 開始,然後只將 SSH 規則連附至堡壘主機子網路。您可以將 Kubernetes Pod/ 服務 CIDR 保留在工作者子網路上,並完全從負載平衡器子網路省略 SSH。
選擇性 (建議) 分割:為堡壘主機子網路建立僅限 SSH 的小型安全清單,並為工作者 /LB 子網路建立個別清單。
BASTION_SL_ID=$(oci network security-list create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-bastion-sl" \ --egress-security-rules '[{"destination": "0.0.0.0/0", "protocol": "all", "isStateless": false}]' \ --ingress-security-rules '[ {"source": "YOUR_PUBLIC_IP/32", "protocol": "6", "isStateless": false, "tcpOptions": {"destinationPortRange": {"min": 22, "max": 22}}, "description": "SSH from your IP"} ]' \ --query "data.id" \ --raw-output) WORKER_SL_ID=$(oci network security-list create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-worker-sl" \ --egress-security-rules '[{"destination": "0.0.0.0/0", "protocol": "all", "isStateless": false}]' \ --ingress-security-rules '[ {"source": "10.0.0.0/16", "protocol": "all", "isStateless": false, "description": "VCN internal traffic"}, {"source": "10.244.0.0/16", "protocol": "all", "isStateless": false, "description": "Kubernetes pods CIDR"}, {"source": "10.96.0.0/16", "protocol": "all", "isStateless": false, "description": "Kubernetes services CIDR"}, {"source": "0.0.0.0/0", "protocol": "1", "isStateless": false, "icmpOptions": {"type": 3, "code": 4}, "description": "Path MTU discovery"} ]' \ --query "data.id" \ --raw-output) LB_SL_ID=$(oci network security-list create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-lb-sl" \ --egress-security-rules '[{"destination": "0.0.0.0/0", "protocol": "all", "isStateless": false}]' \ --ingress-security-rules '[ {"source": "10.0.0.0/16", "protocol": "all", "isStateless": false, "description": "VCN internal traffic"}, {"source": "0.0.0.0/0", "protocol": "6", "isStateless": false, "tcpOptions": {"destinationPortRange": {"min": 80, "max": 80}}, "description": "HTTP (public LB)"}, {"source": "0.0.0.0/0", "protocol": "6", "isStateless": false, "tcpOptions": {"destinationPortRange": {"min": 443, "max": 443}}, "description": "HTTPS (public LB)"} ]' \ --query "data.id" \ --raw-output)注意:如果您只使用內部負載平衡器,請將上方的
0.0.0.0/0來源取代為10.0.0.0/16(或您的 VCN CIDR)。用法:將BASTION_SL_ID附加至堡壘主機子網路、將WORKER_SL_ID附加至 API/ 工作者子網路,以及將LB_SL_ID附加至負載平衡器子網路。注意: GPU 工作節點必須要有 Kubernetes Pod CIDR (
10.244.0.0/16) 和服務 CIDR (10.96.0.0/16) 規則,才能向叢集註冊。ICMP 類型 3 代碼 4 規則會啟用路徑 MTU 尋找,以避免發生封包片段問題。 -
建立子網路。叢集需要四個子網路:一個用於 Kubernetes API 端點、一個用於工作節點、一個用於負載平衡器,另一個用於存取專用叢集的堡壘主機。
API_SUBNET_ID=$(oci network subnet create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-api-subnet" \ --cidr-block "10.0.0.0/28" \ --route-table-id "${PRIVATE_RT_ID}" \ --security-list-ids "[\"${SL_ID}\"]" \ --dns-label "kubeapi" \ --prohibit-public-ip-on-vnic true \ --query "data.id" \ --raw-output) WORKER_SUBNET_ID=$(oci network subnet create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-worker-subnet" \ --cidr-block "10.0.10.0/24" \ --route-table-id "${PRIVATE_RT_ID}" \ --security-list-ids "[\"${SL_ID}\"]" \ --dns-label "workers" \ --prohibit-public-ip-on-vnic true \ --query "data.id" \ --raw-output) LB_SUBNET_ID=$(oci network subnet create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-lb-subnet" \ --cidr-block "10.0.20.0/24" \ --route-table-id "${PUBLIC_RT_ID}" \ --security-list-ids "[\"${SL_ID}\"]" \ --dns-label "loadbalancers" \ --query "data.id" \ --raw-output) BASTION_SUBNET_ID=$(oci network subnet create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --vcn-id "${VCN_ID}" \ --display-name "${CLUSTER_NAME}-bastion-subnet" \ --cidr-block "10.0.30.0/24" \ --route-table-id "${PUBLIC_RT_ID}" \ --security-list-ids "[\"${SL_ID}\"]" \ --dns-label "bastion" \ --query "data.id" \ --raw-output)子網路 CIDR 可見性 目的 API 端點 10.0.0.0/28專用 Kubernetes API 伺服器 工作節點 10.0.10.0/24專用 GPU 運算節點 負載平衡器 10.0.20.0/24公用 外部服務存取 堡壘主機 10.0.30.0/24公用 專用叢集存取的 SSH 通道
作業 4:建立 OKE 叢集
使用在任務 3 中建立的網路資源,在 OKE 上部署託管的 Kubernetes 叢集。叢集佈建時間約為 10 分鐘。本教學課程會建立一個專用叢集 (命令檔預設值),不會對 Kubernetes API 端點使用保留的公用 IP。生產環境工作負載建議使用專用叢集,因為 API 伺服器未公開至公用網際網路。
-
建立具有專用端點的 OKE 叢集。
oci ce cluster create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --name "${CLUSTER_NAME}" \ --vcn-id "${VCN_ID}" \ --kubernetes-version "${KUBERNETES_VERSION}" \ --endpoint-subnet-id "${API_SUBNET_ID}" \ --service-lb-subnet-ids "[\"${LB_SUBNET_ID}\"]" \ --endpoint-public-ip-enabled false指令會傳回工作要求 ID。從叢集清單中取得叢集 ID。
CLUSTER_ID=$(oci ce cluster list \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --lifecycle-state CREATING \ --query 'data[0].id' \ --raw-output) echo "CLUSTER_ID=${CLUSTER_ID}"注意:專用叢集不需要保留的公用 IP。工作者節點仍可透過 NAT 閘道存取網際網路,以提取容器映像檔和下載模型。唯有
kubectl存取需要透過堡壘主機的 SSH 通道 (在後續步驟中設定)。 -
等待叢集變成 ACTIVE。此步驟大約需要 10 分鐘。
oci ce cluster get \ --cluster-id "${CLUSTER_ID}" \ --query "data.\"lifecycle-state\"" \ --raw-output輪詢命令,直到輸出傳回
ACTIVE為止。選擇性:顯示簡潔的狀態摘要 (包括專用 API 端點)。
oci ce cluster get \ --cluster-id "${CLUSTER_ID}" \ --query 'data.{name:name,state:"lifecycle-state","k8s-version":"kubernetes-version",endpoint:endpoints."private-endpoint"}' \ --output table
kubectl get nodes -o wide
-
建立 OCI 堡壘主機以存取專用叢集。此堡壘主機為專用 Kubernetes API 端點提供受管理的 SSH 通道。
BASTION_ID=$(oci bastion bastion create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --bastion-type STANDARD \ --target-subnet-id "${BASTION_SUBNET_ID}" \ --name "${CLUSTER_NAME}-bastion" \ --client-cidr-list '["YOUR_PUBLIC_IP/32"]' \ --query "data.id" \ --raw-output)注意:請以您目前的公用 IP 取代
YOUR_PUBLIC_IP/32。如果是共用網路,請改用公司 CIDR 區塊。等待堡壘主機變成 ACTIVE (約 1 分鐘)。
oci bastion bastion get \ --bastion-id "${BASTION_ID}" \ --query "data.\"lifecycle-state\"" \ --raw-output安全性備註:對於生產,請勿使用
0.0.0.0/0。將--client-cidr-list限制為您的公用 IP 或公司 CIDR (例如"YOUR_PUBLIC_IP/32"),否則網際網路上的任何人都可以嘗試堡壘主機階段作業。 -
使用專用端點下載 kubeconfig。
oci ce cluster create-kubeconfig \ --cluster-id "${CLUSTER_ID}" \ --file "${HOME}/.kube/config" \ --region "${OCI_REGION}" \ --token-version 2.0.0 \ --kube-endpoint PRIVATE_ENDPOINT -
取得 SSH 通道的專用端點 IP 位址。
PRIVATE_ENDPOINT=$(oci ce cluster get \ --cluster-id "${CLUSTER_ID}" \ --query "data.endpoints.\"private-endpoint\"" \ --raw-output) PRIVATE_IP="${PRIVATE_ENDPOINT%:*}" echo "Private endpoint IP: ${PRIVATE_IP}" -
建立堡壘主機連接埠轉送階段作業。您將需要一個 SSH 公開金鑰檔案。
SESSION_ID=$(oci bastion session create-port-forwarding \ --bastion-id "${BASTION_ID}" \ --target-private-ip "${PRIVATE_IP}" \ --target-port 6443 \ --session-ttl 10800 \ --display-name "kubectl-tunnel" \ --ssh-public-key-file ~/.ssh/id_rsa.pub \ --query "data.id" \ --raw-output)等待階段作業變成 ACTIVE,然後取得 SSH 命令。
oci bastion session get \ --session-id "${SESSION_ID}" \ --query "data.{state:\"lifecycle-state\", ssh:\"ssh-metadata\".command}" 2>&1 -
開啟個別的終端機,然後使用上一個步驟的命令啟動 SSH 通道。通道會將本機連接埠 6443 轉送至專用 Kubernetes API。
ssh -i ~/.ssh/id_rsa -o IdentitiesOnly=yes -N -L 6443:<PRIVATE_IP>:6443 \ -p 22 -o ServerAliveInterval=30 \ <SESSION_OCID>@host.bastion.<REGION>.oci.oraclecloud.com注意:將
<PRIVATE_IP>、<SESSION_OCID>和<REGION>取代為上一個步驟的值。在作業階段期間保持開啟此終端機。當您的 SSH 代理程式載入多個金鑰時,-o IdentitiesOnly=yes旗標會防止「認證失敗太多」錯誤。 -
更新 kubeconfig 以透過本機通道連線。
CLUSTER_NAME_KUBE=$(kubectl config view --minify -o jsonpath='{.clusters[0].name}') kubectl config set-cluster "${CLUSTER_NAME_KUBE}" \ --server=https://127.0.0.1:6443 \ --insecure-skip-tls-verify=true注意:由於已針對專用端點 IP 發出叢集憑證,而非
127.0.0.1,因此需要--insecure-skip-tls-verify旗標。這是安全的,因為流量是透過 SSH 通道進行加密。 -
如果您使用非預設的 OCI CLI 設定檔 (例如,
API_KEY_AUTH),請更新 kubeconfig 以使用它。產生的 kubeconfig 預設為產生權杖的DEFAULT設定檔。kubectl config set-credentials \ $(kubectl config view --minify -o jsonpath='{.users[0].name}') \ --exec-env=OCI_CLI_PROFILE=${OCI_PROFILE}提示:步驟 6-9 會由
./entry_point.sh tunnel自動化,如果 SSH 通道在長時間執行的作業 (例如磁碟擴充) 中刪除,也會自動重新連線。在個別的終端機執行該程序,並在階段作業期間讓它繼續執行。 -
驗證叢集存取。
kubectl get nodes
此時,輸出將不會顯示任何節點,因為尚未新增 GPU 節點集區。
No resources found
作業 5:新增 GPU 節點集區
新增具有 GPU 運算執行處理的節點集區至 OKE 叢集。
-
尋找與 GPU 相容的最新 OKE 節點映像檔。OKE 需要預先安裝 kubelet 和節點註冊元件的特定影像。使用
node-pool-optionsAPI 尋找 Kubernetes 版本的正確映像檔。GPU_IMAGE_ID=$(oci ce node-pool-options get \ --node-pool-option-id all \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --query "data.sources[?contains(\"source-name\", 'GPU') && contains(\"source-name\", 'OKE-${KUBERNETES_VERSION#v}') && contains(\"source-name\", '8.10')].\"image-id\" | [0]" \ --raw-output) echo "GPU Image: ${GPU_IMAGE_ID}"注意:符合您 Kubernetes 版本 (例如
OKE-1.31.10) 之 Oracle Linux 8.10 GPU 映像檔的查詢篩選。如果您需要以 ARM 為基礎的影像,請以適當的篩選器取代8.10。 -
決定具有 GPU 資源配置的可用性網域。並非所有可用性網域都有 GPU 容量。
AD=$(oci iam availability-domain list \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --query "data[${GPU_AD_INDEX}].name" \ --raw-output) echo "Availability Domain: ${AD}"注意: GPU 容量因區域和可用性網域而異。如果建立節點集區因發生「超出主機容量」錯誤而失敗,請嘗試其他可用性網域 (
GPU_AD_INDEX) 或 GPU 資源配置,或透過一般 OCI 處理作業要求容量。 -
建立具有 200 GB 開機磁碟區的 GPU 節點集區。
oci ce node-pool create \ --compartment-id "${OCI_COMPARTMENT_ID}" \ --cluster-id "${CLUSTER_ID}" \ --name "${GPU_NODE_POOL_NAME:-gpu-pool}" \ --kubernetes-version "${KUBERNETES_VERSION}" \ --node-shape "${GPU_SHAPE}" \ --node-image-id "${GPU_IMAGE_ID}" \ --node-boot-volume-size-in-gbs "${GPU_BOOT_VOLUME_GB:-200}" \ --size "${GPU_NODE_COUNT}" \ --placement-configs "[{\"availabilityDomain\": \"${AD}\", \"subnetId\": \"${WORKER_SUBNET_ID}\"}]" \ --initial-node-labels '[{"key": "app", "value": "gpu"}, {"key": "nvidia.com/gpu", "value": "true"}]'注意: vLLM Helm 圖表稍後會使用節點標籤
app=gpu和nvidia.com/gpu=true來排定 GPU 節點上的推論 Pod。200 GB 開機磁碟區提供 vLLM 容器映像檔 (~10 GB) 和模型權重的空間,但檔案系統必須先擴充後才能使用 (請參閱作業 8)。 -
等待 GPU 節點變成「就緒」。這通常需要 5 – 10 分鐘的時間,而節點佈建、開機、安裝 GPU 驅動程式,並向叢集註冊。
注意: GPU 執行處理會受到容量限制的限制。如果節點集區維持「建立中」狀態,請檢查 OCI 主控台中的節點狀態,或使用
oci ce node-pool get。「主機容量不足」錯誤表示該可用性網域中沒有可用的 GPU 執行處理。若要解決此問題,請嘗試使用其他可用性網域 (GPU_AD_INDEX=0或GPU_AD_INDEX=2)、嘗試其他 GPU 資源配置,或透過 OCI 主控台或支援回報項目要求保留容量。kubectl get nodes -w節點就緒後預期輸出:
NAME STATUS ROLES AGE VERSION 10.0.10.x Ready node 5m v1.31.10 -
驗證在節點上偵測到 GPU。
kubectl get nodes -o=custom-columns=NAME:.metadata.name,GPUs:.status.capacity.'nvidia\.com/gpu'預期輸出:
NAME GPUs 10.0.10.x 1 -
修正要在 GPU 節點上排定的 CoreDNS。OKE GPU 節點具有
nvidia.com/gpu=present:NoSchedule樣式。在只有 GPU 節點的叢集中,系統 Pod (例如 CoreDNS) 無法在不容許此提示的情況下排定。若無 DNS,Pod 便無法解析外部主機名稱以下載模型。kubectl patch deployment coredns -n kube-system --type='json' \ -p='[{"op": "add", "path": "/spec/template/spec/tolerations/-", "value": {"key": "nvidia.com/gpu", "operator": "Exists", "effect": "NoSchedule"}}]' kubectl patch deployment kube-dns-autoscaler -n kube-system --type='json' \ -p='[{"op": "add", "path": "/spec/template/spec/tolerations/-", "value": {"key": "nvidia.com/gpu", "operator": "Exists", "effect": "NoSchedule"}}]'確認 CoreDNS 正在執行中。
kubectl get pods -n kube-system | grep coredns注意:如果您的叢集具有系統工作負載的專用 CPU 節點集區,則不需要此步驟。只有當 GPU 節點是叢集中的唯一節點時,才需要此修正程式。
oci ce node-pool list --compartment-id "${OCI_COMPARTMENT_ID}" --cluster-id "${CLUSTER_ID}" \ --query 'data[].{name:name,state:"lifecycle-state",shape:"node-shape",size:"node-config-details".size}' --output table
工作 6:安裝 NVIDIA 裝置外掛程式
安裝 NVIDIA 裝置 Plugin,讓 Kubernetes 能夠偵測 GPU 並排定工作負載。
-
套用 NVIDIA 裝置 Plugin DaemonSet。
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.1/nvidia-device-plugin.yml -
等待外掛程式 Pod 準備就緒。
kubectl wait --for=condition=Ready pods -l name=nvidia-device-plugin-ds -n kube-system --timeout=300s注意:部分 OKE GPU 節點映像檔包含預先安裝的 NVIDIA 裝置 Plugin (
nvidia-gpu-device-plugin)。如果映像檔已經包括在內,套用上游 DaemonSet 會建立一個不會導致衝突的第二個執行處理。自動化命令檔 (entry_point.sh deploy-vllm) 一律會安裝它,以確保無論節點映像檔版本為何,GPU 偵測都能運作。 -
確認 GPU 可由 Kubernetes 配置。
kubectl get nodes -o=custom-columns=NAME:.metadata.name,GPUs:.status.allocatable.'nvidia\.com/gpu'預期輸出:
NAME GPUs 10.0.10.x 1 -
修正 CoreDNS 以容忍 GPU 節點 Taint。在 GPU 節點為唯一工作節點的叢集中,無法排定 CoreDNS Pod,因為 OKE GPU 節點含有
nvidia.com/gpu=present:NoSchedule污點。若無 DNS,Pod 便無法解析影像註冊或模型下載 URL。kubectl patch deployment coredns -n kube-system --type='json' -p='[ {"op": "add", "path": "/spec/template/spec/tolerations/-", "value": {"key": "nvidia.com/gpu", "operator": "Exists", "effect": "NoSchedule"}} ]' kubectl rollout status deployment/coredns -n kube-system --timeout=60s注意:只有當 GPU 節點是叢集中的唯一工作節點時,才需要執行此步驟。如果您有系統工作負載的專用 CPU 節點集區,CoreDNS 預設會在該處排定此修正程式,而且此修正程式不需要。
作業 7:設定儲存
套用 OCI 區塊磁碟區 StorageClass 以提供模型加權的永久儲存。
-
套用 StorageClass 定義。
kubectl apply -f oci-block-storage-sc.yaml此檔案定義兩個效能層:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: oci-block-storage-enc provisioner: blockvolume.csi.oraclecloud.com parameters: vpusPerGB: "10" reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: trueStorageClass 效能 使用案例 oci-block-storage-enc平衡 ( vpusPerGB: 10)大部分模型的預設、符合成本效益 oci-block-storage-hp高效能 ( vpusPerGB: 20)更快速地載入大型模型 -
確認 StorageClasses 可用。
kubectl get storageclass
注意:對於需要跨多個 Pod 共用儲存體的多節點部署,請使用 OCI File Storage Service (NFS) 搭配
ReadWriteMany存取模式,而不是 Block Volumes。
作業 8:展開 GPU 節點檔案系統
無論您指定的開機磁碟區大小為何,OCI 開機磁碟區都有固定的 ~47 GB 分割區。僅 vLLM 容器映像檔約為 10 GB,而模型權重需要額外的空間。您必須先擴充檔案系統,再部署 vLLM,以避免 DiskPressure 收回。
備註:這是 OCI 特定需求。開機磁碟區佈建為 200 GB,但作業系統預設只使用約 47 GB 的分割區。剩餘空間必須手動宣告。
-
驗證 GPU 節點上目前的檔案系統大小。
GPU_NODE=$(kubectl get nodes -l app=gpu -o jsonpath='{.items[0].metadata.name}') kubectl run check-disk --rm -i --restart=Never \ --image=busybox:latest \ --overrides="{\"spec\":{\"nodeName\":\"${GPU_NODE}\",\"tolerations\":[{\"operator\":\"Exists\"}],\"containers\":[{\"name\":\"check\",\"image\":\"busybox:latest\",\"command\":[\"sh\",\"-c\",\"chroot /host df -h / | tail -1\"],\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"name\":\"host\",\"mountPath\":\"/host\"}]}],\"volumes\":[{\"name\":\"host\",\"hostPath\":{\"path\":\"/\"}}]}}"輸出將顯示約 47 GB 總計,確認需要擴充。
-
在 GPU 節點上建立授權的 Pod,以執行擴充命令。
kubectl run expand-disk --restart=Never \ --image=busybox:latest \ --overrides="{\"spec\":{\"nodeName\":\"${GPU_NODE}\",\"tolerations\":[{\"operator\":\"Exists\"}],\"containers\":[{\"name\":\"expand\",\"image\":\"busybox:latest\",\"command\":[\"sleep\",\"600\"],\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"name\":\"host\",\"mountPath\":\"/host\"}]}],\"volumes\":[{\"name\":\"host\",\"hostPath\":{\"path\":\"/\"}}]}}"等待 Pod 啟動。
kubectl wait --for=condition=Ready pod/expand-disk --timeout=60s -
在單一
kubectl exec指令中執行全部四個擴充步驟。將它們一起執行,可避免kubectl exec在步驟之間傳回結束碼 137 (SIGKILL) 的風險,這些步驟在主機上的重磁碟 I/O 期間可能會發生。kubectl exec expand-disk -- chroot /host bash -c ' set -x growpart /dev/sda 3 || echo "growpart: partition may already be expanded" sleep 3 pvresize /dev/sda3 lvextend -l +100%FREE /dev/ocivolume/root || echo "lvextend: may already be extended" xfs_growfs / echo "EXPANSION_COMPLETE" df -h / '步驟 命令 目的 1 growpart /dev/sda 3展開分割區 3 以使用滿磁碟 2 pvresize /dev/sda3調整 LVM 實體磁碟區大小 3 lvextend -l +100%FREE /dev/ocivolume/root擴充邏輯磁碟區 4 xfs_growfs /增加 XFS 檔案系統以填滿音量 注意:這四個作業都是等冪的。如果執行傳回結束代碼 137,您可以安全地重新執行整個區塊。在輸出中尋找
EXPANSION_COMPLETE以確認成功。 -
重新啟動 kubelet,讓節點報告更新的可配置儲存,然後驗證並清除。
kubectl exec expand-disk -- nsenter -t 1 -m -p -- systemctl restart kubelet 2>/dev/null \ || echo "Warning: kubelet restart returned non-zero (non-critical)" kubectl exec expand-disk -- chroot /host df -h / kubectl delete pod expand-disk --force注意:
nsenter命令會輸入主機的 PID 命名空間,以存取 systemd。一般chroot /host systemctl restart kubelet無法從 chroot 內連線至 systemd 匯流排,因此失敗。預期的輸出應顯示約 189 GB 的總計。
任務 9:部署 vLLM 生產堆疊
使用 Helm 安裝 vLLM 推論堆疊。
-
新增 vLLM Helm 儲存區域。
helm repo add vllm https://vllm-project.github.io/production-stack helm repo update -
複查 Helm 值檔案。
production_stack_specification.yaml會設定 OCI 的模型、資源和儲存。servingEngineSpec: runtimeClassName: "" modelSpec: - name: "gpt-oss" repository: "vllm/vllm-openai" tag: "latest" modelURL: "openai/gpt-oss-20b" replicaCount: 1 requestCPU: 4 requestMemory: "24Gi" requestGPU: 1 # No HF token needed - Apache 2.0 licensed OpenAI open source model pvcStorage: "100Gi" pvcAccessMode: - ReadWriteOnce storageClass: "oci-block-storage-enc" nodeSelector: app: gpu tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" extraArgs: - "--max-model-len=8192" - "--gpu-memory-utilization=0.90"備註:
openai/gpt-oss-20b模型是專家混合 (MoE) 模型,具有 20B 總參數和 3.6B 個正向傳遞作用中參數。它是根據 Apache 2.0 授權發行的,因此不需要 Hugging Face 權杖。vllm/vllm-openai容器映像檔提供與 OpenAI 相容的 API 伺服器,可讓從屬端針對自行代管的端點使用標準 OpenAI SDK 呼叫。 -
部署堆疊。請不要在此處使用
--wait,因為路由器 Pod 在下一個步驟修正之前將會是 CrashLoop。helm upgrade -i \ vllm vllm/vllm-stack \ -f production_stack_specification.yaml等待 vLLM 引擎 Pod 啟動 (路由器將會在下一步進行修正)。
kubectl wait --for=condition=Ready pods -l model=gpt-oss --timeout=600s注意:引擎 Pod 在第一次啟動時下載模型加權,因此需要幾分鐘的時間才能變成「就緒」。如果 Pod 停留在
ContainerCreating中,容器映像檔 (~10 GB) 仍會被提取。使用kubectl describe pod <pod-name>檢查進度。 -
修正路由器部署。路由器需要 GPU 容忍度 (因此,當 GPU 節點是唯一具有容量的節點時,便可進行排程) 並增加記憶體限制 (預設的 500 Mi 可能會導致 OOMKill)。
kubectl patch deployment vllm-deployment-router --type='json' -p='[ {"op": "add", "path": "/spec/template/spec/tolerations", "value": [{"key": "nvidia.com/gpu", "operator": "Exists", "effect": "NoSchedule"}]}, {"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/memory", "value": "512Mi"}, {"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/memory", "value": "1Gi"} ]'注意:由於 OKE GPU 節點具有可防止非 GPU 工作負載排程的
nvidia.com/gpu=present:NoSchedule提示符號,因此需要 GPU 允差。由於路由器不使用 GPU,而需要在某個地方執行,因此這項容忍能力可允許在 GPU 節點上進行排程。在具有專用 CPU 節點集區的叢集中,不需要此允差。 -
確認已部署 Helm 版本。
helm list
-
驗證 Pod 是否在執行中。
kubectl get pods預期輸出:
NAME READY STATUS RESTARTS AGE vllm-deployment-router-xxxxxxxxxx-xxxxx 1/1 Running 0 5m vllm-gpt-oss-deployment-vllm-xxxxxxxxxx-xxxxx 1/1 Running 0 5mkubectl get pods
-
檢查 Pod 日誌中的模型載入進度。
kubectl logs -f deployment/vllm-gpt-oss-deployment-vllm等到您看到一則訊息,指出模型已載入,且伺服器已準備好接受要求。
工作 10:測試推論端點
驗證部署是否提供推論要求。vLLM Production Stack 會透過路由器服務公開與 OpenAI 相容的 API,因此任何 OpenAI SDK 從屬端或 curl 命令都可以與其互動。
下圖顯示推論要求生命週期:從從屬端要求到路由器的引擎選擇邏輯,到 vLLM 引擎的預先填入和解碼階段,再回溯作為串流回應。

-
列出可用的模型以確認部署狀況良好。
kubectl get svc vllm-router-service路由器服務為所有部署的模型提供 API 閘道。由於叢集使用專用端點,因此您可以透過
kubectl port-forward存取服務。 -
從本機機器啟動連接埠轉送至路由器服務。開啟新終端機 (將 SSH 通道保持在另一個通道中執行) 並執行:
kubectl port-forward svc/vllm-router-service 8080:80這會將您機器上的
localhost:8080對應至叢集內路由器服務的連接埠 80。安全注意事項:
kubectl port-forward會在本機連結,不會公開服務。透過堡壘主機通道使用專用叢集時,這是測試的最安全方式。注意:連接埠轉送命令會在前景執行。測試時保持開啟此終端機 。按 Ctrl+C 即可在完成時停止。
-
在另一個終端機中,透過查詢模型端點來驗證模型是否可用。
curl -s http://localhost:8080/v1/models | python3 -m json.tool預期輸出:
{ "object": "list", "data": [ { "id": "openai/gpt-oss-20b", "object": "model", "created": 1234567890, "owned_by": "vllm" } ] } -
傳送文字完成要求。
curl -s http://localhost:8080/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-oss-20b", "prompt": "Oracle Cloud Infrastructure is", "max_tokens": 50 }' | python3 -m json.tool預期的輸出 (縮寫):
{ "id": "cmpl-xxxxxxxxxxxx", "object": "text_completion", "model": "openai/gpt-oss-20b", "choices": [ { "index": 0, "text": " a cloud computing platform that provides ...", "finish_reason": "length" } ], "usage": { "prompt_tokens": 5, "completion_tokens": 50, "total_tokens": 55 } } -
傳送線上交談完成要求。此格式與 OpenAI Python SDK 使用的格式相同,也是以程式設計方式與 LLM 互動的最常見方式。
curl -s http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-oss-20b", "messages": [{"role": "user", "content": "What is Oracle Cloud Infrastructure in one sentence?"}], "max_tokens": 100 }' | python3 -m json.tool預期的輸出 (縮寫):
{ "id": "chatcmpl-xxxxxxxxxxxx", "object": "chat.completion", "model": "openai/gpt-oss-20b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Oracle Cloud Infrastructure (OCI) is Oracle's enterprise-grade cloud platform that provides a full range of services for building, deploying, and managing applications and workloads..." }, "finish_reason": "length" } ], "usage": { "prompt_tokens": 71, "completion_tokens": 100, "total_tokens": 171 } }這兩個回應都包括模型在
choices陣列中產生的文字、記號使用狀況統計資料,以及stop(模型自然完成) 或length的finish_reason(輸出在max_tokens被截斷)。注意: API 要求中的模型名稱是與 Helm 值中
modelURL欄位相符的完整模型路徑 (openai/gpt-oss-20b)。任何與 OpenAI 相容的從屬端都可以透過將base_url設為http://localhost:8080/v1來使用此端點。
-
評估簡短要求的端對端延遲。
time curl -s http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"openai/gpt-oss-20b","messages":[{"role":"user","content":"What is Kubernetes?"}],"max_tokens":50}' > /dev/null在單一 A10 GPU 上,預期短時間內完成了 1-3 秒的端對端。第一個記號 (TTFT) 的時間通常為 50-200ms,視提示長度而定。若要提高傳輸量,請增加 Helm 值中的
replicaCount,以便在路由器後新增更多引擎複本。
工作 11:透過 OCI 負載平衡器公開 (選擇性)
讓推論端點可透過 OCI 負載平衡器從外部存取。
安全注意事項:預設會將推論 API 公用網際網路公開。在不使用 TLS、認證 (API 金鑰 /JWT/mTLS) 和 IP 允許清單或 WAF 控制的情況下,請勿在生產環境中啟用此功能。如果必須公開,請在其前面加上輸入控制器或 API 閘道,以強制執行認證和速率限制,或使用內部負載平衡器。
-
將路由器服務修正為使用 LoadBalancer 類型。
kubectl patch svc vllm-router-service \ -p '{"spec": {"type": "LoadBalancer"}}'注意:如果想要使用內部負載平衡器,請將 OCI 註解新增至服務 (範例如下)。這會將端點專用保留在 VCN 中。
kubectl annotate svc vllm-router-service \ "service.beta.kubernetes.io/oci-load-balancer-internal"="true" -
等待指派外部 IP。
kubectl get svc vllm-router-service -w負載平衡器佈建之後預期輸出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) vllm-router-service LoadBalancer 10.96.x.x 129.xxx.xxx.xx 80:xxxxx/TCPkubectl get svc
-
測試外部端點。
curl http://<EXTERNAL-IP>/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-oss-20b", "prompt": "Hello from OCI!", "max_tokens": 50 }'
作業 12:設定多重 GPU Tensor 平行機制 (進階)
在裸機資源配置的多個 GPU 上部署大型模型。
Tensor 平行程度可將模型分割為單一節點上的多個 GPU。當模型的記憶體需求超過單一 GPU 時,這是必要的。例如,Meta Llama 3.1 70B 需要大約 140 GB 的 GPU 記憶體,該記憶體超出任何單一 GPU 的容量,但可容納 8x A100 80 GB 或 8x H100 GPU。
-
使用 Hugging Face 權杖建立 Kubernetes 加密密碼。限定模型 (例如 Llama 3.1 70B) 需要認證。
kubectl create secret generic hf-token-secret \ --from-literal=token=YOUR_HUGGINGFACE_TOKEN -
使用多重 GPU 組態更新
production_stack_specification.yaml。servingEngineSpec: modelSpec: - name: "llama70b" repository: "vllm/vllm-openai" tag: "latest" modelURL: "meta-llama/Llama-3.1-70B-Instruct" replicaCount: 1 tensorParallelSize: 8 requestCPU: 32 requestMemory: "256Gi" requestGPU: 8 hf_token: secretName: "hf-token-secret" secretKey: "token" pvcStorage: "500Gi" pvcAccessMode: - ReadWriteOnce storageClass: "oci-block-storage-enc" nodeSelector: node.kubernetes.io/instance-type: "BM.GPU.H100.8" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" extraArgs: - "--max-model-len=8192" - "--gpu-memory-utilization=0.95" - "--tensor-parallel-size=8" -
使用更新的值進行部署。如同工作 9,請勿使用
--wait。路由器將 CrashLoop 直到修正為止。helm upgrade -i \ vllm vllm/vllm-stack \ -f production_stack_specification.yaml kubectl wait --for=condition=Ready pods -l model=llama70b --timeout=900s然後修補路由器 (和任務 9 相同,步驟 4) 並驗證:
kubectl patch deployment vllm-deployment-router --type='json' -p='[ {"op": "add", "path": "/spec/template/spec/tolerations", "value": [{"key": "nvidia.com/gpu", "operator": "Exists", "effect": "NoSchedule"}]}, {"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/memory", "value": "512Mi"}, {"op": "replace", "path": "/spec/template/spec/containers/0/resources/limits/memory", "value": "1Gi"} ]' -
確定 Pod 正在執行,而且所有 GPU 都在使用中。
kubectl get pods kubectl logs -f deployment/vllm-llama70b-deployment-vllm
注意:請先確定 OKE 叢集具有具有適當裸機 GPU 資源配置的節點集區 (例如
BM.GPU.H100.8),再部署多重 GPU 組態。
工作 13:對模型使用 OCI 物件儲存 (進階)
從 OCI Object Storage 載入模型權重,而不是從 Hugging Face 下載。這對於專用模型、OCI 內的下載速度較快,或沒有外部網際網路存取的環境非常有用。
-
將您的模型加權上傳至 OCI Object Storage 貯體。瀏覽至 OCI 主控台中的儲存體 > 物件儲存體,如果還沒有儲存桶,請建立儲存桶。
-
為您的儲存桶建立預先認證要求 (PAR) URL。在 OCI 主控台中,選取您的儲存桶,按一下預先認證的要求,然後建立具有讀取存取權的新要求。
-
更新
production_stack_specification.yaml以使用 PAR URL。servingEngineSpec: modelSpec: - name: "custom-model" repository: "iad.ocir.io/YOUR_TENANCY/vllm-custom:latest" modelURL: "/models/custom-model" env: - name: BUCKET_PAR_URL value: "https://objectstorage.us-ashburn-1.oraclecloud.com/p/xxx/n/namespace/b/bucket/o" - name: MODEL_NAME value: "custom-model" -
使用更新的值進行部署 (不含
--wait)。請參閱「任務 9」以瞭解原因。helm upgrade -i \ vllm vllm/vllm-stack \ -f production_stack_specification.yaml kubectl wait --for=condition=Ready pods -l model=custom-model --timeout=600s -
檢查 Pod 日誌,以驗證物件儲存的模型負載。
kubectl logs -f deployment/vllm-custom-model-deployment-vllm
作業 14:清除資源
移除所有已部署的資源,以避免持續收費。
-
使用清除命令檔移除 Kubernetes 資源。
cd production-stack/deployment_on_cloud/oci ./clean_up.sh這會解除安裝 Helm 版本、刪除所有 PersistentVolumeClaims、PersistentVolumes 和自訂 vLLM 資源。
-
刪除 OKE 叢集和所有 OCI 網路資源。
./entry_point.sh cleanup這會依下列順序刪除下列資源:
- GPU 節點集區
- OKE 叢集
- 堡壘主機 (如果已建立)
- 子網路 (API、工作節點、負載平衡器、堡壘主機)
- 安全清單
- 服務閘道、NAT 閘道及網際網路閘道
- 路由表
- VCN
-
確認所有資源都已在 OCI 主控台的「開發人員服務 > Kubernetes 叢集」和「網路 > 虛擬雲端網路」底下移除。
./entry_point.sh cleanup
注意:請確定已刪除所有資源,以避免持續收費。即使閒置,GPU 執行個體和區塊磁碟區也會產生成本。
新功能
此教學課程已部署功能推論堆疊。對於生產環境工作負載,請考慮下列增強功能:
- 監控: vLLM 會在每個引擎 Pod 上的
/metrics公開 Prometheus 指標。連接 Prometheus + Grafana 堆疊,以追蹤時間至第一個記號、每秒記號、KV 快取使用率和要求佇列深度。 - 自動調整:使用自訂度量設定 Kubernetes 水平 Pod 自動調整工具 (透過 DCGM 要求佇列深度或 GPU 使用率),以在負載下自動調整引擎複本。
- 安全性強化:將
BASTION_CLIENT_CIDR限制在您的 IP 範圍、新增 Kubernetes 網路原則以隔離推論命名空間,以及將模型證明資料儲存在 OCI Vault 中,而非 Kubernetes 加密密碼。 - 高可用性:跨多個可用性網域分攤 GPU 節點,並在 Helm 值中增加
replicaCount,讓路由器可以在引擎複本之間進行容錯移轉。 - 成本最佳化:不使用時,請使用
./entry_point.sh cleanup。對於開發 / 測試工作負載,請考量先佔式 GPU 執行處理。監控 GPU 使用率,以調整節點集區的大小。 - 基礎架構即程式碼:使用 OCI Terraform 提供者或 OCI 資源管理程式為可重複且由版本控制的基礎架構編碼此部署。
相關連結
確認
- 作者 - Federico Kamelhar (代理 AI 資深首席架構師)
其他學習資源
在 docs.oracle.com/learn 上探索其他實驗室,或在 Oracle Learning YouTube 頻道上存取更多免費學習內容。此外,請造訪 education.oracle.com/learning-explorer 以成為 Oracle Learning Explorer。
如需產品文件,請造訪 Oracle Help Center 。
Deploy OpenAI vLLM Production Stack on Oracle Kubernetes Engine (OKE)
G50928-01