GDC 氣隙隔離方案的開放權重 LLM 使用者指南

本部署指南提供詳細說明,介紹如何在 Google Distributed Cloud (GDC) 實體隔離環境中,使用開放原始碼軟體 (OSS) 執行最先進的大型語言模型 (LLM)。具體來說,本指南會介紹執行最新版 Gemma、DeepSeek 和 Llama 模型的所有必要步驟,同時說明提供其他公開 LLM 服務的常見程序。我們將運用容器化服務後端 (例如 vLLM 和 Ollama),涵蓋各種功能、不同層級的設定,以及簡便的部署方式。

內容摘要

本指南詳細說明如何在 Google Distributed Cloud (GDC) 實體隔離環境中,部署及運作開放原始碼大型語言模型 (LLM)。

核心目標和基礎架構

  • 用途:詳細說明如何使用 vLLM 和 Ollama 等最佳化後端,執行最先進的 LLM,包括 Gemma 3 (多模態)、DeepSeek-R1 和 Llama (3.1/3.2)。
  • 最低版本:GDC 實體隔離軟體版本 1.15.x*。
  • 硬體需求:至少需要 1 個 NVIDIA A100 GPU。 建議使用高效能儲存空間 (500GiB 以上的 PVC),將模型權重載入時間從 30 分鐘縮短至 5 分鐘以下。

部署元件

元件 說明
LLM 後端 vLLM (使用 PagedAttention 提供高處理量服務) 和 Ollama (簡化本機管理作業並支援多模態)
模型 公開發布的 LLM,包括 Gemma、DeepSeek 和 Llama 系列
加速器 視模型 VRAM 占用空間而定,支援完整的 NVIDIA A100 GPU 或 多執行個體 GPU (MIG) 切片
GDC 服務 使用 GDC Container Service、Load Balancer (ELB/ILB)、Harbor Container Registry

重要作業程序

  • 模型管理:LLM 後端會根據用量管理模型的載入和卸載作業。vLLM 會將模型固定在記憶體中,確保延遲時間一致且較短,而 Ollama 則允許動態載入模型,但閒置 30 分鐘後會自動卸載模型。
  • 自訂:使用者可以從網際網路提取偏好的 LLM、建構新的 Docker 映像檔,並上傳至本機 Harbor 登錄檔,藉此使用偏好的 LLM。

必要條件

版本

  • GDC 氣隙版本 1.15.1 以上。

元件

  • 建立使用者叢集時,資源 (CPU、記憶體、GPU) 充足。
  • 至少須有 1 個 NVIDIA A100 GPU。
  • 可存取且可用的 Harbor 執行個體。
  • kubectl 和 gdcloud CLI 已設定為存取使用者叢集。
  • 已安裝 Docker 用戶端,並設定為推送至 Harbor。
  • 已授予必要的 IAM 權限 (例如「命名空間管理員」、「叢集開發人員」)。
  • 如果使用封閉式模型,請設定 Hugging Face 帳戶並完成驗證。

所需容量

資源 容量
CPU 8 個 vCPU
RAM 記憶體 32 GiB
臨時儲存空間 16 Gi
GPU 1 個 NVIDIA A100 GPU
永久磁碟區 *500GiB 以上

服務後端需要這些硬體資源,才能透過 GPU 加速執行 LLM。舉例來說,一個 a2-ultragpu-1g-gdc 機器類型就足以提供資源。

高階圖表

開放權重 LLM 服務的高階圖表。

這張圖顯示使用者正在使用 vLLM 和 Ollama 這兩個 LLM 後端公開的 API,從 Gemma、Llama 和 DeepSeek 等開放原始碼模型取得推論回應。視模型大小 (以數十億個參數為單位) 而定,每個 LLM 可能需要完整或部分 GPU 才能執行。

LLM 部署作業的服務和安全邊界圖表

這項解決方案會使用 GDC 氣隙軟體堆疊中已包含的下列服務:

  • GDC 容器服務:執行所有程序,並使用 HPA 調整程序規模。
  • GDC 負載平衡器:使用 Kubernetes 服務,為這個解決方案中的所有後端提供服務,並讓客戶網路存取 LLM,這稱為 ELB,代表外部負載平衡器。反之,客戶也可以選擇只允許從使用者叢集內部連線至 LLM,這在只有內部代理程式在解決方案內要求推論時可能很有用,這稱為 ILB,代表內部負載平衡器。
  • GDC CI/CD:使用 Harbor Container Registry 儲存 LLM 後端和模型權重。
  • GDC Observability Stack:收集及搜尋後端記錄,並提供資訊主頁。

就安全性而言,存取 LLM 部署作業的權限取決於哪些使用者可以連線至負載平衡器服務,該服務會公開 LLM 服務後端,這些後端會以 Pod 形式在 Kubernetes 專案 / 命名空間中執行。

服務和安全邊界架構圖。

部署作業

必要條件

在連線至 GDC 氣隙環境的工作站上,安裝下列工具:

  1. docker
  2. kubectl
  3. gdcloud CLI

這份文件包含部署 LLM 所需的所有原始碼和設定檔。

建立密鑰,從 Harbor 提取映像檔

如要在 GDC 實體隔離方案中為容器工作負載設定映像檔提取密碼,您需要建立 Kubernetes docker-registry Secret,其中包含存取私人 Harbor 專案的憑證。然後在部署規格中參照這個密碼。

如要以程式輔助方式存取私人 Harbor 專案中的映像檔,請使用 Harbor 機器人帳戶。

請按照下列步驟設定映像檔提取密鑰:

建立 Harbor 機器人帳戶:

  • 前往 Harbor 執行個體 UI。
  • 前往 Harbor 專案。
  • 選取「機器人帳戶」分頁標籤。
  • 按一下「+ NEW ROBOT ACCOUNT」(新增機器人帳戶)。
  • 為該權杖命名 (例如 oss-llm-puller),並授予必要權限 (至少要有「pull」存取權),直到權杖到期為止。
  • 請妥善保管機器人帳戶名稱 (例如 robot$oss-llm-puller) 和系統提供的密碼權杖。

向 Harbor 驗證 Docker:

在安裝 Docker 的機器上,透過網路存取 Harbor 登錄檔,然後使用機器人帳戶憑證登入:

export INSTANCE_URL="your-harbor-instance-url"
# for example, harbor1-project1.org1.zone1.google.gdc.com

export ROBOT_NAME="your-robot-account-name"
# for example, robot\$oss-llm-puller (note how we escape the $ character)

export ROBOT_SECRET="your-robot-account-secret"

docker login ${INSTANCE_URL} --username ${ROBOT_NAME} --password ${ROBOT_SECRET}

# Sample output:

WARNING! Using --password via the CLI is insecure. Use --password-stdin.

WARNING! Your credentials are stored unencrypted in '$HOME/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded

如範例輸出內容所示,這個指令會使用驗證詳細資料更新本機 Docker 設定檔 ($HOME/.docker/config.json)。config.json 檔案如下所示:

{
    "auths": {
        "harbor1-project1.org1.zone1.google.gdc.com": {
            "auth": "...omitted..."
        }
    }
}

如果您過去曾使用 Docker 用戶端登入其他登錄檔,您會在「auths」中看到更多項目。

建立 Kubernetes 映像檔提取密鑰:

使用 kubectl 在專案命名空間中建立 docker-registry 類型的密鑰,並使用上一步更新的 Docker 設定檔:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS certificate}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

export SECRET_NAME="oss-llm-pull-secret" # You can choose another name
export NAMESPACE="your-project-namespace"
# Assuming default Docker config path. Adjust if necessary.
export DOCKER_CONFIG_PATH="$HOME/.docker/config.json"

kubectl create secret docker-registry ${SECRET_NAME} \
      --from-file=.dockerconfigjson=${DOCKER_CONFIG_PATH} \
      -n ${NAMESPACE}

您稍後會在 LLM 後端容器規格中,透過加入 imagePullSecrets 欄位來參照這項密鑰。

完成這些步驟後,Kubernetes 叢集就會使用提供的憑證,從 GDC 無網路環境中的私人 Harbor 登錄檔提取容器映像檔。產品說明文件也包含這些步驟。

設定 LLM 部署作業

您可以選擇下列兩種 LLM 後端:

  • vLLM
  • Ollama

您可以選擇其中一個,或同時部署兩個後端。每個後端都可以執行一或多個 LLM,例如:

  • Gemma 3
  • DeepSeek
  • Llama
  • 其他 LLM

第 1 節會說明如何部署 vLLM,第 2 節則會說明如何安裝 Ollama。

1. 將 vLLM 部署為 LLM 後端

取得 vLLM Docker 映像檔

一般來說,vLLM 用於提供從 Hugging Face 下載的模型,我們將在本 LLM 部署作業中說明。部分模型設有存取限制,也就是說,使用者必須明確要求或同意存取 Hugging Face Hub 上的檔案和內容,才能下載或使用這些模型。

按照說明文件所述,使用 Docker 登入 Harbor 執行個體。在可連上網際網路的電腦上,提取 vLLM Docker 映像檔,然後轉移至 Harbor 專案:

# Pull and Tag vLLM (v0.13.0 recommended for stability)
docker pull vllm/vllm-openai:v0.13.0
docker tag vllm/vllm-openai:v0.13.0 HARBOR_URL/PROJECT/vllm-openai:v0.13.0
docker push HARBOR_URL/PROJECT/vllm-openai:v0.13.0

更改下列內容:

  • HARBOR_URL:Harbor 執行個體網址。
  • PROJECT:Harbor 專案名稱。

本部署指南使用的 vLLM 版本為:v0.13.0

將 LLM 模型權重儲存在 PVC 中

開啟新的終端機,然後建立資料夾,用來儲存 vLLM 部署作業的檔案:

mkdir vllm-deployment
cd vllm-deployment

接著,請建立 YAML 檔案 (例如 model-pvc.yaml),使用標準 Kubernetes 基本類型宣告 Persistent Volume Claim (PVC):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: model-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 500Gi
  storageClassName: standard-rwo
  volumeMode: Filesystem

連線至 GDC 氣隙叢集,並套用 PVC:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS cert}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

# Apply the PVC manifest
kubectl apply -f model-pvc.yaml

從 Hugging Face 下載模型權重:

# Log in to Hugging Face
hf auth login

# Download weights for Gemma 3 (for example, 4B instruction-tuned)
hf download google/gemma-3-4b-it

輸出內容範例:

Fetching 9 files: 100%| 9/9 [00:00<00:00, 19.34it/s]
Downloading (…)7f58a/.gitattributes: 100%| 1.62k/1.62k [00:00<00:00, 7.82MB/s]
Downloading (…)del-00002-of-00002.safetensors: 100%| 3.75G/3.75G [00:46<00:00, 81.3MB/s]
Downloading (…)del-00001-of-00002.safetensors: 100%| 4.90G/4.90G [00:54<00:00, 90.1MB/s]
Downloading (…)-3-4b-it/README.md: 100%| 23.3k/23.3k [00:00<00:00, 48.0MB/s]
Downloading (…)8a/model.safetensors.index.json: 100%| 26.3k/26.3k [00:00<00:00, 39.5MB/s]
Downloading (…)f58a/config.json: 100%| 908/908 [00:00<00:00, 4.41MB/s]
Downloading (…)generation_config.json: 100%| 210/210 [00:00<00:00, 936kB/s]
Downloading (…)tokenizer.json: 100%| 33.1M/33.1M [00:01<00:00, 17.6MB/s]
/Users/rashjab/.cache/huggingface/hub/models--google--gemma-3-4b-it/snapshots/952ec8ffca3adadfd00c6d71b40280ebdbb7f58a

如範例輸出內容所示,磁碟上的模型占磁碟容量為 8.64 GB,符合我們先前定義的 500 GiB PVC。請務必確保載入至永久磁碟區 (PV) 的任何模型都是如此。舉例來說,使用 500 GiB PVC 載入 15 GB 模型,可達到 1,500 IOPS,大幅縮短權重載入時間,從約 30 分鐘縮短至 5 分鐘以下。

將模型檔案複製到 PV 的磁碟區,即可填入 PV。這通常包括:

  • 建立暫時的「輔助」Pod,掛接 PV。
  • 使用 kubectl cp 將模型檔案從工作站複製到輔助 Pod 的已掛接磁碟區。
  • 輔助 Pod 範例:

helper-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: model-uploader
spec:
  containers:
  - name: uploader
    image: HARBOR_URL/PROJECT/busybox:latest
    command: ["sleep", "3600"]
    volumeMounts:
    - name: model-data
      mountPath: /data
  imagePullSecrets:
  - name: oss-llm-pull-secret
  volumes:
  - name: model-data
    persistentVolumeClaim:
      claimName: model-pvc

更改下列內容:

  • HARBOR_URL:Harbor 執行個體網址。
  • PROJECT:Harbor 專案名稱。
  • oss-llm-pull-secret:如果您選擇了其他映像檔提取密鑰名稱。
  • model-pvc:您為 PVC 指定的名稱。

推送輔助 Docker 映像檔 (busybox):

docker pull busybox:latest
docker tag busybox HARBOR_URL/PROJECT/busybox:latest
docker push HARBOR_URL/PROJECT/busybox:latest

更改下列內容:

  • HARBOR_URL:Harbor 執行個體網址。
  • PROJECT:Harbor 專案名稱。

套用 helper-pod.yaml 檔案,並將模型權重複製到 PV:

kubectl apply -f helper-pod.yaml

# Wait for the pod to be Running
kubectl cp ~/.cache/huggingface/hub/ NAMESPACE/model-uploader:/data/

# After copying, delete the helper pod
kubectl delete pod model-uploader

部署 vLLM 後端

建立 vLLM 的部署檔案,以執行模型伺服器。以下範例會部署 gemma-3-4b-it 模型。

vllm-gemma-3-4b-it-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gemma-3-4b-it
  labels:
    app: gemma-3-4b-it
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gemma-3-4b-it
  template:
    metadata:
      labels:
        app: gemma-3-4b-it
    spec:
      volumes:
      - name: cache-volume
        persistentVolumeClaim:
          claimName: model-pvc # change with the name you gave initially to your PVC
      # vLLM needs to access the host's shared memory for tensor parallel inference.
      - name: shm
        emptyDir:
          medium: Memory
          sizeLimit: "16Gi"
      containers:
      - name: gemma-3-4b-it
        image: HARBOR_URL/PROJECT/vllm-openai:v0.13.0
        command: ["python3"]
        args: [
          "-m",
          "vllm.entrypoints.openai.api_server",
          "--model",
          "google/gemma-3-4b-it", # Use the repo ID
          "--max-model-len",
          "32768",
          "--enforce-eager"
        ]
        env:
        - name: HF_HUB_OFFLINE
          value: "1"
        - name: HF_HOME
          value: "/model" # Tells vLLM to look for models in /model/hub
        # --- PERFORMANCE & STABILITY OPTIMIZATIONS ---
        - name: NCCL_P2P_DISABLE
          value: "1" # Prevents initialization hangs on P2P checks
        - name: NCCL_IB_DISABLE
          value: "1" # Prevents initialization hangs on InfiniBand checks
        # --- FIPS BYPASS ---
        - name: BORINGSSL_FIPS
          value: "0"
        - name: OPENSSL_FIPS
          value: "0"
        - name: OPENSSL_CONF
          value: "/dev/null"
        - name: FIPS_SIG
          value: "off"
        ports:
        - containerPort: 8000
        securityContext:
          privileged: true
          runAsUser: 0
        resources:
          limits:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
            cpu: "8"       # Increased to handle model weight verification
            memory: "64Gi"  # Increased to ensure headroom for weight loading
          requests:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
            cpu: "8"
            memory: "32Gi"
        volumeMounts:
        - name: cache-volume
          mountPath: /model
        - name: shm
          mountPath: /dev/shm
      imagePullSecrets:
      - name: oss-llm-pull-secret

更改下列內容:

  • HARBOR_URL:Harbor 執行個體網址。
  • PROJECT:Harbor 專案名稱。
  • oss-llm-pull-secret:您在建立映像檔提取密鑰時指定的名稱。
  • claimName:您在初始 PVC 建立作業中指定的名稱。

接著,建立 Kubernetes Service 檔案,公開 vLLM 後端 API:

vllm-gemma-3-4b-it-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: gemma-3-4b-it
  namespace: NAMESPACE
spec:
  ports:
  - name: http-gemma-3-4b-it
    port: 80
    protocol: TCP
    targetPort: 8000
  selector:
    app: gemma-3-4b-it
  sessionAffinity: None
  type: LoadBalancer

套用部署和服務設定:

kubectl apply -f vllm-gemma-3-4b-it-deployment.yaml
kubectl apply -f vllm-gemma-3-4b-it-service.yaml

驗證及測試 vLLM 部署作業

  1. 檢查廣告連播狀態:

    kubectl get pods
    

    等待 Pod 進入 Running 狀態。

  2. 檢查服務:

    kubectl get service
    

    輸出內容範例:

    # NAME          TYPE         CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
    # gemma-3-4b-it LoadBalancer 10.201.136.62  136.125.37.198   80:30109/TCP   3d1h
    

    記下先前輸出內容中的 vLLM 服務 EXTERNAL-IP (例如 136.125.37.198)。你也可以使用以下方式列印:

    kubectl get service gemma-3-4b-it \
    -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
    
  3. 查看記錄:

    kubectl logs YOUR_VLLM_POD
    

    尋找指出伺服器已啟動且模型已載入的訊息 (例如 INFO: Application startup complete.)。由於沒有 Hugging Face 下載作業,如果檔案位於 PVC 中,且持續性磁碟區容量較高,應該很快就能完成。

  4. 使用 curl 測試推論:

    確認 vLLM Pod 正在執行,且您擁有 Service 的外部 IP 位址後,即可使用 curl 傳送推論要求。由於 vLLM 提供與 OpenAI 相容的 API,因此您可以使用 /v1/chat/completions 端點:

    curl http://EXTERNAL_IP/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "google/gemma-3-4b-it",
        "messages": [
          {"role": "user", "content": "What is Google Distributed Cloud air-gapped?"}
        ],
        "max_tokens": 100
      }'
    

    將 EXTERNAL_IP 替換為 vLLM 服務的外部 IP 位址。

2. 將 Ollama 部署為 LLM 後端

Ollama 是熱門的架構,可在本機和容器化環境中執行開放原始碼 LLM。可處理權重下載、量化和 GPU 加速,簡化模型執行作業。包括用於生成補全內容、對話回覆和嵌入的內建 REST API。

與其他服務引擎不同,Ollama 會動態管理模型執行作業:

  • 動態模型載入:收到特定模型的要求時,Ollama 會視需要將權重載入記憶體 (GPU VRAM 或系統 RAM)。
  • 閒置時卸載:如果模型 30 分鐘內未收到任何推論要求 (可透過 OLLAMA_KEEP_ALIVE 設定),Ollama 會將模型從記憶體卸載,釋出硬體資源供其他工作負載使用。
  • 每個執行個體只能有一個有效模型:Ollama 每個伺服器執行個體一次只能處理一個有效模型的要求。如果平行呼叫多個模型,Ollama 會將要求排入佇列,並依序交換模型,這可能會導致延遲。如要同時提供多個模型,而不必切換,請為每個模型部署個別的 Ollama 執行個體。

下載模型權重並建立 Docker 映像檔

與可直接從 PersistentVolume 載入權重的 vLLM 不同,Ollama 通常會將模型儲存在內部目錄格式 (~/.ollama/models)。

在與外界隔絕的環境中,執行階段容器無法從公開網際網路下載模型,因此您必須在建構階段,將模型權重預先封裝到容器映像檔本身。這種做法可確保容器完全獨立,部署後即可立即提供服務,不需外部網路存取權。

建立 Ollama 部署作業的資料夾:

mkdir ollama-gemma3
cd ollama-gemma3

建立 Dockerfile,並加入以下內容:

# Use a standard Linux base image
FROM ubuntu

# Install necessary dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    ca-certificates \
    zstd \
    && rm -rf /var/lib/apt/lists/*

# Install Ollama
# This uses Ollama's official installation script, which adds Ollama to /usr/local/bin
RUN curl -fsSL https://ollama.com/install.sh -o install.sh && \
    chmod +x install.sh && \
    ./install.sh && \
    rm install.sh

# Set environment variables for Ollama (optional, but a good practice)
# ENV OLLAMA_HOST="0.0.0.0"

# If you want to customize the model storage path within the container, set OLLAMA_MODELS, for example:
# ENV OLLAMA_MODELS="/usr/local/ollama/models"
# The default OLLAMA_MODELS is /root/.ollama
# Then, ensure you create and populate that directory.

# --- Download Gemma 3 model weights ---
# This step starts Ollama server in the background, pulls the model,
# and then kills the server to allow the Docker build to continue.
# This approach works around the Docker RUN command limitations for services.

RUN ollama serve & \
    # Give the Ollama server a moment to start up
    # Use --retry and --retry-connrefused to handle startup delays
    curl --retry 10 --retry-connrefused -s http://localhost:11434 || true && \
    # Pull the Gemma 3 model weights
    ollama pull gemma3:latest && \
    # Stop the background Ollama server process cleanly
    pkill ollama || true

# Expose Ollama's default port
EXPOSE 11434

# Command to run Ollama server when the container starts
CMD ["ollama", "serve"]

如要試用其他開放原始碼 LLM,例如 Llama 3.2 或 DeepSeek-R1 系列的模型,請修改先前 Dockerfile 中的 Ollama 指令:

ollama pull gemma3:latest

舉例來說,如要提取 Llama 3.2 (30 億個參數),請使用下列指令:

ollama pull llama3.2:3b

或者,如要使用 80 億參數的 DeepSeek-R1,請使用下列指令:

ollama pull deepseek-r1:8b

您也可以下載多個 LLM,並將其模型權重裝入容器。這樣一來,當您要求以不同預先載入的模型進行推論時,Ollama 就能在模型之間切換。舉例來說,您可以在 Docker 映像檔中同時加入 Gemma 和 Llama 模型。請注意,在無網路連線的環境中,Ollama 後端無法存取 Ollama 程式庫,因此無法隨時下載任何模型。

請務必先查看並同意各模型授權和使用條款,再於應用程式中執行模型。Ollama 的程式庫中有很多 LLM。建構 LLM 後端 Docker 映像檔時,只需要連上網際網路下載模型權重。

建構 Docker 映像檔並推送至 Harbor

按照說明文件所述,使用 Docker 登入 Harbor 執行個體。建構 Gemma 3 Docker 映像檔,並上傳至 Harbor 存放區:

docker build -t ollama-gemma3 .
docker tag ollama-gemma3 HARBOR_URL/PROJECT/ollama-gemma3:latest
docker push HARBOR_URL/PROJECT/ollama-gemma3:latest

更改下列內容:

  • HARBOR_URL:Harbor 執行個體網址。
  • PROJECT:Harbor 專案名稱。

本部署指南使用的 Ollama 版本:0.14.1

準備 Kubernetes 部署作業和服務

建立名為 ollama-gemma3.yaml 的檔案,定義 Ollama 後端部署作業及其負載平衡器設定,以便將其公開為服務:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ollama-gemma3
  namespace: osd-dev
  labels:
    app: ollama-gemma3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ollama-gemma3
  template:
    metadata:
      labels:
        app: ollama-gemma3
    spec:
      containers:
      - name: ollama-gemma3
        image: rashjab-mhs-rashjab-test2.gdc1.us-west6-a.staging.gpcdemolabs.com/rashjab-repo/ollama-gemma3:latest
        env:
        # This is the crucial fix: Tell Ollama to listen on all network interfaces
        - name: OLLAMA_HOST
          value: "0.0.0.0"
        imagePullPolicy: Always
        ports:
        - containerPort: 11434
        securityContext:
          privileged: true
          runAsUser: 0
        resources:
          limits:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
          requests:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
      imagePullSecrets:
      - name: oss-llm-pull-secret
---
apiVersion: v1
kind: Service
metadata:
  name: ollama-gemma3
  namespace: osd-dev
spec:
  type: LoadBalancer
  selector:
    app: ollama-gemma3
  ports:
  - name: ollama-gemma3-port
    port: 11434
    protocol: TCP
    targetPort: 11434

更改下列內容:

  • HARBOR_URL:Harbor 執行個體網址。
  • PROJECT:Harbor 專案名稱。
  • oss-llm-pull-secret:如果您選擇了其他映像檔提取密鑰名稱。

驗證 GPU 分配

GDC 實體隔離方案支援 NVIDIA 多重執行個體 GPU (MIG),您可以在公開文件中查看不同的 MIG 設定檔。 如果您要部署小型 LLM,建議檢查其大小 (以記憶體為單位),並據此分割 GPU。節點集區的分割區配置是在其 Cluster 自訂資源中定義。如要進一步瞭解如何套用 GPU 分割配置,請參閱「新增節點集區」。如果您是應用程式操作人員 (AO),請諮詢您的平台管理員 (PA),瞭解專案 / 叢集中已安裝和可用的加速器。如要進一步瞭解如何設定容器使用 GPU 資源,以及如何檢查 GPU 資源分配情形,請參閱這篇文章。

Gemma 3 4B 模型的預設精確度為 16 位元。根據 Google 發布的這份表格,使用 BF16 (16 位元) 精確度時,這個大型語言模型的 GPU 記憶體需求為 6.4 GB。

在先前的 ollama-gemma3.yaml 中,我們將 10 GB 的 GPU 配量 (NVIDIA A100) 連接到容器,因為這個 VRAM 記憶體容量足以載入 Gemma 3 4B 模型並運作執行,如下所示:

ollama-gemma3.yaml

... omitted ...

        resources:
          limits:
            nvidia.com/mig-1g.10gb-NVIDIA_A100_80GB_PCIE: 1
          requests:
            nvidia.com/mig-1g.10gb-NVIDIA_A100_80GB_PCIE: 1

... omitted ...

部署 Ollama 後端並公開為服務

連線至叢集,並將背景資訊設為專案命名空間:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS certificate}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

套用 Ollama 資訊清單:

kubectl apply -f ollama-gemma3.yaml

確認 Ollama Pod 正在執行,且相關聯的服務已就位:

kubectl get pods

輸出內容範例:

# NAME                             READY   STATUS    RESTARTS   AGE
# ollama-gemma3-6fc6fff74b-9qtpf   1/1     Running   0          1h
kubectl get service

輸出內容範例:

# NAME             TYPE          CLUSTER-IP    EXTERNAL-IP    PORT(S)          AGE
# ollama-gemma3   LoadBalancer  172.0.0.1     10.0.0.1       11434:31822/TCP  1d

記下先前輸出內容中的 Ollama 服務 EXTERNAL-IP (例如 10.0.0.1)。你也可以使用以下方式列印:

kubectl get service ollama-gemma3 \
-o jsonpath='{.status.loadBalancer.ingress[*].ip}'

檢查 Ollama Gemma 3 是否正常運作前,請先套用網路政策,例如:

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-ollama-ingress
  namespace: osd-dev
spec:
  subject:
    subjectType: UserWorkload
  policyType: Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0 # Allows traffic from any IP. Restrict this for production.
    ports:
    - protocol: TCP
      port: 11434

套用網路政策:

kubectl apply -f ollama-netpol.yaml

驗證及測試 Ollama 部署作業:

  1. 檢查 Ollama 是否正在執行:

    curl http://EXTERNAL_IP:11434
    

    預期回應:「Ollama is running」(Ollama 正在執行)

  2. 傳送完成要求:

    curl -X POST http://EXTERNAL_IP:11434/v1/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "gemma3:latest",
        "prompt": "Google Distributed Cloud air-gapped is a",
        "max_tokens": 128,
        "temperature": 0.90
      }'
    

要求推論

現在 LLM 後端 (vLLM 和 Ollama) 已部署完成,且可透過各自的 LoadBalancer 服務存取,您可以開始使用這些後端進行推論。

視用途而定,您有幾種做法:

  • 互動式網頁 UI:如要測試、製作原型,或為使用者提供類似 ChatGPT 的體驗,可以部署 Open WebUI 或類似的前端。
  • 指令列介面 (CLI):如要快速驗證、編寫指令碼或自動化,可以使用 curl 或自訂指令碼。
  • 應用程式整合:將內部應用程式、AI 代理程式或 IDE 外掛程式 (例如 VS Code/JetBrains 的 Continue) 直接連線至 vLLM (/v1) 或 Ollama (/v1) 提供的 OpenAI 相容端點。

1. 透過 UI 與 LLM 互動

如要提供類似 ChatGPT 的介面,與模型互動,請在叢集中部署 Open WebUI。

建立 Open WebUI Deployment

建立 open-webui-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-webui
  namespace: osd-dev
  labels:
    app: open-webui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: open-webui
  template:
    metadata:
      labels:
        app: open-webui
    spec:
      containers:
      - name: open-webui
        image: HARBOR_URL/PROJECT/open-webui:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: OPENAI_API_BASE_URL
          value: "http://gemma-3-4b-it/v1" # Point to your vLLM service
        - name: OPENAI_API_KEY
          value: "EMPTY"
        - name: WEBUI_AUTH
          value: "False"
      imagePullSecrets:
      - name: oss-llm-pull-secret
---
apiVersion: v1
kind: Service
metadata:
  name: open-webui
  namespace: osd-dev
spec:
  type: LoadBalancer
  selector:
    app: open-webui
  ports:
  - port: 80
    targetPort: 8080

套用網路政策

您必須允許電腦連上通訊埠 80 的 Open WebUI 服務。

更新 PNP 專案網路政策,加入 open-webui 服務,或套用廣泛的政策:

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-webui-ingress
  namespace: NAMESPACE
spec:
  subject:
    subjectType: UserWorkload
  policyType: Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0 # Allows traffic from any IP then restrict this for production
    ports:
    - protocol: TCP
      port: 8080

驗證

  1. 取得 WebUI IP:

    kubectl get service open-webui -n NAMESPACE
    
  2. 存取使用者介面:開啟瀏覽器並前往 http://WEB_UI_EXTERNAL_IP

  3. 設定:首次登入時,請建立管理員帳戶。在設定中,確認 OpenAI 連線指向 http://gemma-3-4b-it/v1

  4. 選取模型:在對話介面中,從模型下拉式選單選取 google/gemma-3-4b-it。

    開啟 WebUI 模型選取下拉式選單。

2. 使用 CLI 發出 HTTP 要求

  • curl:
curl -X POST http://OLLAMA_LOAD_BALANCER_IP:11434/v1/completions \
-H "Content-Type: application/json" \
-d '{
  "model": "gemma3:latest",
  "prompt": "Google Distributed Cloud air-gapped is a",
  "max_tokens": 128,
  "temperature": 0.90
}'

驗證與核對

確認所有容器和服務都正在執行:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS cert}
gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

# Pods

kubectl get pods # This command should return results like below

# NAME                                   READY   STATUS    RESTARTS   AGE
# vllm-6fc6fff74b-9qtpf                 1/1     Running   0          1h
# ollama-798fbf6ff6-9m7ln               1/1     Running   0          1h


# Services

kubectl get services # This command should return results like below

# NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)           AGE
# vllm-service              LoadBalancer   172.0.0.1        10.0.0.1       11434:31822/TCP   1h
# ollama-service        LoadBalancer   172.0.0.2        10.0.0.2       11434:30728/TCP   1h

移除步驟

  1. 移除所有 Kubernetes 資源:

    kubectl delete -f vllm-gemma-3-4b-it-deployment.yaml
    kubectl delete -f vllm-gemma-3-4b-it-service.yaml
    
  2. 從 Harbor 存放區手動刪除未使用的容器。

作業

vLLM 後端

vLLM 基礎知識

vLLM 專為高效能單一模型服務引擎而設計,單一伺服器程序不支援提供多個模型,單一啟動指令也不支援定義多個模型。如要提供多個模型 (例如聊天模型和個別的嵌入模型),您必須啟動個別的 vLLM 執行個體,每個執行個體都位於自己的 Pod 或容器中,並可選擇指派給不同的 GPU 或 GPU 區塊。與其他可能會動態交換模型的後端不同,vLLM 執行個體會在初始化時釘選模型和相關聯的 KV 快取記憶體,確保處理量一律維持高水準,延遲時間也一律很短。

您可以使用下列指令,在任何 vLLM Pod 上開啟終端機:

kubectl exec -it gemma-3-4b-random-string -n NAMESPACE -- /bin/bash

這會顯示載入的模型、引數和 PID:

ps aux | grep vllm

預期輸出內容大致如下:

root           1  0.1  0.8 9436960 1550504 ?     Ssl  Feb04   9:18 python3 -m vllm.entrypoints.openai.api_server --model google/gemma-3-4b-it --max-model-len 32768 --enforce-eager
root         504  0.0  0.0   3476  1596 pts/0    S+   02:48   0:00 grep --color=auto vllm

如要取得更簡潔的「Ollama 類似」檢視畫面,不要 grep 指令本身和系統 PID 的雜亂資訊,可以使用以下單行指令:

ps aux | grep [v]llm.entrypoints | awk -F'--model ' '{print $2}' | awk '{print $1}'

回覆範例:

google/gemma-3-4b-it

您可以使用標準 kubectl 指令,以及查詢內部 API 端點,監控 vLLM 部署作業的狀態。

檢查 Pod 記錄

開啟終端機,查看初始化和放送記錄:

kubectl logs -f gemma-3-4b-it-random_string -n NAMESPACE

確認伺服器已準備就緒:

(APIServer pid=1) INFO:     Started server process [1]
(APIServer pid=1) INFO:     Waiting for application startup.
(APIServer pid=1) INFO:     Application startup complete.

查詢內部狀態

由於 vLLM 提供與 OpenAI 相容的 API,您可以直接從叢集內的終端機 (例如使用 debug-sh Pod) 驗證已載入的模型和系統健康狀態。

您必須先啟動偵錯 Pod,操作說明如下:

啟動 Debug Pod

執行下列指令,在專案命名空間中啟動暫時性殼層。這項設定會使用 busybox 映像檔 (先前已推送至 Harbor 登錄檔),並透過 --overrides 標記插入必要憑證:

kubectl run --rm -it debug-sh \
  --image=HARBOR_URL/PROJECT/busybox:latest \
  --restart=Never -n osd-dev --overrides='{
    "spec": {
      "imagePullSecrets": [{"name": "oss-llm-pull-secret"}]
    }
  }' -- sh

重要參數:

  • --rm:退出時自動刪除 Pod,保留叢集資源。
  • --overrides:在實體隔離環境中,必須使用這個參數,才能讓 Pod 向私人 Harbor 登錄檔進行驗證。

查詢模型伺服器狀態

進入 Pod 後,使用 wget 公用程式查詢 vLLM API。由於 vLLM 服務會將內部通訊埠 8000 對應至通訊埠 80,因此您可以使用服務的 DNS 名稱:

  • 載入的模型清單:確認 vLLM 引擎已成功初始化,並載入 Gemma 3 權重。

    wget -qO- http://gemma-3-4b-it/v1/models
    

    成功回應:

    {"object":"list","data":[{"id":"google/gemma-3-4b-it"}]}
    
  • 檢查應用程式健康狀態:確認 API 伺服器已準備好處理要求。

    wget -qO- http://gemma-3-4b-it/health
    

    成功回應:

    OK
    

Ollama 基礎知識

Ollama 不支援同時將多個模型載入記憶體。此外,如果一段時間未使用 LLM (預設為 30 分鐘),Ollama 會從記憶體卸載目前的模型。

如先前所述,視需求和用途而定,解決方案會實作兩個以上的 Ollama 後端,讓多位開發人員或使用者能平行使用,不必讓單一 Ollama 執行個體頻繁載入和卸載模型,產生不必要的延遲。

您可以使用下列指令,在任何 Ollama Pod 開啟終端機:

kubectl exec -it ollama-chat-random_string -- sh
kubectl exec -it ollama-autocomplete-random_string -- sh

在 Pod 內,您可以使用 Ollama CLI 探索可用的模型,並查看載入的模型:

  • 在 ollama-chat Pod 中,您會找到一個模型:

    # ollama list
    NAME                     ID              SIZE      MODIFIED
    codegemma:7b-instruct    0c96700aaada    5.0 GB    2 hours ago
    
    # ollama ps
    NAME                     ID              SIZE     PROCESSOR    UNTIL
    codegemma:7b-instruct    0c96700aaada    10 GB    100% GPU     4 minutes from now
    
  • 在 ollama-autocomplete Pod 中,您會看到兩個模型:

    # ollama list
    NAME                     ID              SIZE      MODIFIED
    codegemma:2b             926331004170    1.6 GB    2 hours ago
    codegemma:7b-code        aee9a63c13b9    5.0 GB    2 hours ago
    
    # ollama ps
    NAME                 ID              SIZE      PROCESSOR    UNTIL
    codegemma:7b-code    aee9a63c13b9    7.1 GB    100% GPU     4 minutes from now
    
  • Ollama 卸載目前模型時,輸出內容會空白:

    # ollama ps
    NAME    ID    SIZE    PROCESSOR    UNTIL
    

請注意,當您傳送下一個程式碼輔助要求時,Ollama 會動態載入模型,無須任何手動介入。

GPU 容量的重要性

如果您配置 10 GB 的 GPU 記憶體,但模型記憶體用量 (略) 大於該值,您會發現部分 LLM 會載入 CPU,如下所示:

# ollama ps
NAME                     ID              SIZE     PROCESSOR         UNTIL
codegemma:7b-instruct    0c96700aaada    10 GB    6%/94% CPU/GPU    29 minutes from now

這並非最佳做法,且會導致回應延遲時間較長,因此請務必提供本指南建議的 GPU 大小。

大型語言模型

透過 vLLM 導入其他或偏好的 LLM

如要在 GDC air-gapped 上使用 vLLM 執行不同大小的 Gemma 或任何其他開放原始碼大型語言模型 (LLM),例如 DeepSeek-R1 或 Llama 3.1,您必須將新模型權重納入環境,並更新部署資訊清單,指向新資產。

根據為這個解決方案建立的作業程序,按照下列步驟載入其他模型:

  1. 下載新模型權重:

    在可存取網際網路的工作站上,使用 Hugging Face CLI 下載偏好模型的權重。

    • Gemma 3 (3-12b-it):
    hf download google/gemma-3-12b-it
    
    • DeepSeek-R1 (7B Distill):
    hf download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
    
    • Llama 3.1 (8B):
    hf download meta-llama/Meta-Llama-3.1-8B-Instruct
    

    注意:請務必先在 Hugging Face 上接受模型授權條款,再下載模型。

  2. 填入永久磁碟區 (PVC):

    更新現有的 model-pvc,或建立新的,確保有足夠 容量可容納新模型。使用輔助 Pod 方法,從工作站轉移權重。較大的外型規格需要更多磁碟空間。請確認您的永久磁碟區聲明 (PVC) 有足夠容量,可儲存新的權重。

    • Gemma 3 4B:約 15.2 GB。
    • Gemma 3 27B:約 54 GB 以上。
    • 建議:維持 500 GiB PVC 建議,確保高 IOPS (1,500),加快載入速度 (不論模型大小)。
    # Copy the new model's hub directory to the helper pod
    kubectl cp ~/.cache/huggingface/hub/ osd-dev/model-uploader:/data/
    
  3. 更新 vLLM Deployment 資訊清單:

    修改 vLLM 部署 YAML,參照新的模型 ID。與可動態交換模型的 Ollama 不同,vLLM 執行個體專用於單一模型,必須更新或重新部署才能變更模型。

    根據您使用的模型更新部署的 args 區段,以下以 deepseek 為例:

    args: [
      "-m", "vllm.entrypoints.openai.api_server",
      "--model", "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", # Update to new Repo ID
      "--max-model-len", "32768",
      "--enforce-eager" # Recommended for GDC stability
    ]
    
  4. 調整 GPU 和記憶體資源:

    模型越大,權重和 KV 快取所需的 VRAM 就越多。如果從 4B 模型改用 8B 或 14B 模型,請確保資源限制足夠,以免發生「記憶體不足」當機問題。

    • VRAM 占用空間:在 16 位元精確度下,80 億參數模型光是權重就需要約 16 GB,加上 vLLM PagedAttention 快取,還需要額外記憶體。
    • 建議:對於參數超過 70 億的模型,請使用完整的 A100 GPU (nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1),確保 KV 快取有足夠的空間,並發揮最佳效能。
  5. 驗證新模型:

    部署作業完成後,請使用內部 API 確認新模型是否已啟用:

    # Inside a debug-sh pod
    wget -qO- http://gemma-3-4b-it/v1/models
    

    成功回應:

    {"object":"list","data":[{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"}]}
    

透過 Ollama 導入其他 LLM

如要試用其他開放原始碼 LLM,例如 Llama 3.2 或 DeepSeek-R1 系列的模型,請修改先前 Dockerfile 中的 Ollama 指令:

ollama pull gemma3:latest

舉例來說,如要提取 Llama 3.2 (30 億個參數),請使用下列指令:

ollama pull llama3.2:3b

或者,如要使用 80 億參數的 DeepSeek-R1,請使用下列指令:

ollama pull deepseek-r1:8b

您也可以下載多個 LLM,並將其模型權重裝入容器。這樣一來,當您要求以不同預先載入的模型進行推論時,Ollama 就能在模型之間切換。舉例來說,您可以在 Docker 映像檔中同時加入 Gemma 和 Llama 模型。請注意,在無網路連線的環境中,Ollama 後端無法存取 Ollama 程式庫,因此無法隨時下載任何模型。

請務必先查看並同意各模型授權和使用條款,再於應用程式中執行模型。Ollama 的程式庫中有很多 LLM。建構 LLM 後端 Docker 映像檔時,只需要連上網際網路下載模型權重。

開啟 WebUI

檢查 Open WebUI Pod 是否處於執行狀態:

kubectl get pods -n NAMESPACE

預期輸出內容:

NAME                             READY   STATUS    RESTARTS   AGE
open-webui-69df4664d-przjl       1/1     Running   0          6d3h

檢查服務 IP:

kubectl get service -n NAMESPACE

預期輸出內容:

NAME          TYPE            CLUSTER-IP       EXTERNAL-IP      PORT(S)           AGE
open-webui     LoadBalancer   10.201.137.164   136.125.37.224   80:30492/TCP      6d3h

以下各節說明如何使用主要 UI 功能。

開啟 WebUI 使用者介面圖表。

使用 Ollama 後端擴充解決方案

垂直

  • 為成為瓶頸的 LLM 分配較大的 GPU 區塊,直到您使用完整的 GPU 為止。
  • 如要使用較大的 LLM (例如 405B 參數 LLM,而非 7B 參數 LLM) 提升回覆準確度,可能需要多個 GPU 才能順利執行。
  • 如果模型適用於多個 GPU,則會因 GPU 間的通訊而產生延遲。

水平

  • 視需要部署任意數量的 Ollama Pod,在特定 LLM 上達到目標處理量。
    • 如要達成這個目標,請在對應的 Ollama 部署 YAML 檔案中增加 replica 數量。
  • Kubernetes 服務 (LoadBalancer 類型) 會在端點 (即 Pod) 之間分配程式碼輔助要求,並透過公開的外部 IP 傳回各自的回應。
  • 請注意,Continue 外掛程式的每個功能只會指向一個 IP 位址。

開放權重 LLM 擴充架構圖。

如要在 GDC vLLM 後端中擴充 air-gapped 環境,可以採用類似 Ollama 的策略,著重於硬體資源分配和 Pod 複製。

使用 vLLM 後端擴充解決方案

垂直

  • 升級 GPU 分配:如果推論處理量 (權杖/秒) 成為瓶頸,請分配較大的 GPU 區塊,直到使用完整的 NVIDIA A100 GPU 為止。
  • 多 GPU 設定:對於無法容納在單一 80 GB A100 記憶體中的大型模型 (例如 700 億到 4050 億個參數),您必須使用張量平行處理技術,擴充至多個 GPU。
  • 延遲考量:請注意,跨越多個 GPU 的模型可能會因 GPU 間通訊 (例如 NCCL 同步) 而產生輕微的額外負擔。

水平

  • 透過副本提高輸送量:如要處理相同模型的大量並行使用者要求,請在 vLLM 部署 YAML 中增加 replicas 計數。
  • 專屬模型執行個體:vLLM 是設計為單一模型服務引擎,且會在初始化時釘選 KV 快取記憶體,因此您必須為要代管的每個不同 LLM 部署一組獨立的 Pod。
  • 負載平衡:GDC Kubernetes 服務 (類型 LoadBalancer) 會自動將傳入的推論要求,分配給與該服務相關聯的所有正常 vLLM Pod 端點。

疑難排解

錯誤 緩解措施
FIPS SELFTEST FAILURE 如果 BoringSSL 等程式庫缺少完整性簽章,就會發生這種情況。如要修正這個問題,請設定 BORINGSSL_FIPS=0,並使用官方 vLLM 映像檔
體重載入停滯 檢查小型 PVC 是否有 IOPS 節流。初始化效能模型時,需要 500 GiB 的磁碟區。
連線遭拒 確認 PNP 明確允許 targetPort (8000/8080)。GDC 防火牆不會自動授予 Load Balancer VIP 後端通訊埠的存取權。