在 Kubernetes 上部署 llama3

有何m不可發表於2024-07-17

轉自:https://zhuanlan.zhihu.com/p/695534674

Ollama 與 OpenWebUI 介紹

Ollama 是一個執行大模型的工具,可以看成是大模型領域的 Docker,可以下載所需的大模型並暴露 API。

OpenWebUI 是一個大模型的 Web UI 互動工具,支援 Ollama,即呼叫 Ollama 暴露的 API 實現與大模型互動:

在 Kubernetes 上部署 llama3

部署方案選型

OpenWebUI 的倉庫中自帶 Ollawma + OpenWebUI 的部署方式,主要是 kustomizehelm 這兩種方式,參考 open-webui 倉庫的 kubernetes 目錄

但我更推薦直接寫 YAML 進行部署,原因如下:

  1. Ollama + OpenWebUI 所需 YAML 相對較少,直接根據需要寫 YAML 更直接和靈活。
  2. 不需要研究 OpenWebUI 提供的 kustomizehelm 方式的用法。

選擇模型

Llama3 目前主要有 8b70b 兩個模型,分別對應 80 億和 700 億規模的引數模型,CPU 和 GPU 都支援,8b 是小模型,對配置要求不高,一般處於成本考慮,可以直接使用 CPU 執行,而 70b 則是大模型, CPU 肯定吃不消,GPU 的配置低也幾乎跑不起來,主要是視訊記憶體要大才行,經實測,24G 視訊記憶體跑起來會非常非常慢,32G 的也有點吃力,40G 的相對流暢(比如 Nvdia A100)。

準備 Namespace

準備一個 namespace,用於部署執行 llama3 所需的服務,這裡使用 llama namespace:

kubectl create ns llama

部署 Ollama

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ollama
  namespace: llama
spec:
  serviceName: "ollama"
  replicas: 1
  selector:
    matchLabels:
      app: ollama
  template:
    metadata:
      labels:
        app: ollama
    spec:
      containers:
        - name: ollama
          image: ollama/ollama:latest
          ports:
            - containerPort: 11434
          resources:
            requests:
              cpu: "2000m"
              memory: "2Gi"
              nvidia.com/gpu: "0" # 如果要用 Nvidia GPU,這裡宣告下 GPU 卡
            limits:
              cpu: "4000m"
              memory: "4Gi"
          volumeMounts:
            - name: ollama-volume
              mountPath: /root/.ollama
          tty: true
  volumeClaimTemplates:
    - metadata:
        name: ollama-volume
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 200Gi # 注意要確保磁碟容量能夠容納得下模型的體積
---
apiVersion: v1
kind: Service
metadata:
  name: ollama
  namespace: llama
  labels:
    app: ollama
spec:
  type: ClusterIP
  ports:
    - port: 11434
      protocol: TCP
      targetPort: 11434
  selector:
    app: ollama

部署 OpenWebUI

OpenWebUI 是大模型的 web 介面,支援 llama 系列的大模型,透過 API 與 ollama 通訊,官方映象地址是:ghcr.io/open-webui/open-webui,在國內拉取速度非常慢,如果你的環境有 DockerHub 加速,可以替換成 DockerHub 里長期自動同步的 mirror 映象:docker.io/imroc/open-webui

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: webui-pvc
  namespace: llama
  labels:
    app: webui
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 2Gi

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webui
  namespace: llama
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      labels:
        app: webui
    spec:
      containers:
        - name: webui
          image: imroc/open-webui:main # docker hub 中的 mirror 映象,長期自動同步,可放心使用
          env:
            - name: OLLAMA_BASE_URL
              value: http://ollama:11434 # ollama 的地址
          tty: true
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "500m"
              memory: "500Mi"
            limits:
              cpu: "1000m"
              memory: "1Gi"
          volumeMounts:
            - name: webui-volume
              mountPath: /app/backend/data
      volumes:
        - name: webui-volume
          persistentVolumeClaim:
            claimName: webui-pvc

---
apiVersion: v1
kind: Service
metadata:
  name: webui
  namespace: llama
  labels:
    app: webui
spec:
  type: ClusterIP
  ports:
    - port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: webui

開啟 OpenWebUI

你有很多方式可以將 OpenWebUI 暴露給叢集外訪問,比如 LoadBalancer 型別 ServiceIngress 等,也可以直接用 kubectl port-forward 的方式將 webui 暴露到本地:

kubectl -n llama port-forward service/webui 8080:8080

瀏覽器開啟:http://localhost:8080,首次開啟需要建立賬號,第一個建立的賬號為管理員賬號。

在 Kubernetes 上部署 llama3

下載模型

方法一:透過 OpenWebUI 下載

進入 OpenWebUI 並登入後,在 設定-模型 裡,輸出需要下載的 llama3 模型並點選下載按鈕(除了基礎的模型,還有許多微調的模型,參考 llama3 可用模型列表)。

在 Kubernetes 上部署 llama3

接下來就是等待下載完成:

在 Kubernetes 上部署 llama3

注意:如果頁面關閉,下載會中斷,可重新開啟頁面並重新輸入要下載的模型進行下載,會自動斷點續傳。

方法二:執行 ollama pull 下載

進入 ollama 的 pod:

kubectl -n llama exec -it ollama-0 bash

執行 ollama pull 下載需要的模型,這裡以下載 70b 模型為例:

ollama pull llama3:70b

等待下載完成。

注意: 如果 kubectl 的連線中斷,下載也會中斷,可重新執行命令斷點續傳。
你也可以使用 nohup ollama pull llama3:70b & 來下載,透過 tail -f nohup.out 檢視下載進度,這樣可以保證即使 kubectl 中斷或退出也會繼續下載。

方案三:使用 init container 自動下載模型

如果不想每次在新的地方部署需要手動下載模型,可以修改 Ollama 的部署 YAML,加個 initContainer 來實現自動下載模型(自動檢測所需模型是否存在,不存在才自動下載):

initContainers:
  - name: pull
    image: ollama/ollama:latest
    tty: true
    stdin: true
    command:
      - bash
      - -c
      - |
        model="llama3:8b" # 替換需要使用的模型,模型庫列表: https://ollama.com/library/llama3
        ollama serve &
        sleep 5 # 等待 ollama server 就緒,就緒後才能執行 ollama cli 工具的命令
        result=`ollama list | grep $model`
        if [ "$result" == "" ]; then
          echo "downloading model $model"
          ollama pull $model
        else
          echo "model $model already been downloaded"
        fi
    volumeMounts:
      - name: ollama-volume
        mountPath: /root/.ollama

開始對話

開啟 OpenWebUI 頁面,選擇模型,然後就可以在對話方塊中開始對話了。

在 Kubernetes 上部署 llama3

小技巧

GPU 排程策略

對於像 70b 這樣的模型,需要較好的 GPU 才能跑起來,如果叢集內有多種 GPU 節點,需要加下排程策略,避免分配到較差的 GPU。

比如要排程到顯示卡型號為 Nvdia Tesla V100 的節點,可以給節點打上 label:

kubectl label node gpu=v100

然後配置下排程策略:

      nodeSelector:
        gpu: v100

省錢小妙招

  • 如果使用雲廠商託管的 Kubernetes 叢集,且不需要大模型高可用,可以購買競價例項(Spot),會便宜很多。
  • 如果只在部分時間段使用,可以使用定時伸縮,在不需要的時間段將 Ollama 和 OpenWebUI 的副本數自動縮到 0 以停止計費,比如 使用 KEDA 的 Cron 觸發器實現定時伸縮

常見問題

節點無公網導致模型下載失敗

ollama 所在機器需要能夠訪問公網,因為 ollama 下載模型需要使用公網,否則會下載失敗,無法啟動,可透過檢視 init container 的日誌確認:

$ kubectl logs -c pull ollama-0
time=2024-04-26T07:29:45.487Z level=INFO source=images.go:817 msg="total blobs: 5"
time=2024-04-26T07:29:45.487Z level=INFO source=images.go:824 msg="total unused blobs removed: 0"
time=2024-04-26T07:29:45.487Z level=INFO source=routes.go:1143 msg="Listening on [::]:11434 (version 0.1.32)"
time=2024-04-26T07:29:45.488Z level=INFO source=payload.go:28 msg="extracting embedded files" dir=/tmp/ollama188207103/runners
time=2024-04-26T07:29:48.896Z level=INFO source=payload.go:41 msg="Dynamic LLM libraries [cuda_v11 rocm_v60002 cpu cpu_avx cpu_avx2]"
time=2024-04-26T07:29:48.896Z level=INFO source=gpu.go:121 msg="Detecting GPU type"
time=2024-04-26T07:29:48.896Z level=INFO source=gpu.go:268 msg="Searching for GPU management library libcudart.so*"
time=2024-04-26T07:29:48.897Z level=INFO source=gpu.go:314 msg="Discovered GPU libraries: [/tmp/ollama188207103/runners/cuda_v11/libcudart.so.11.0]"
time=2024-04-26T07:29:48.910Z level=INFO source=gpu.go:126 msg="Nvidia GPU detected via cudart"
time=2024-04-26T07:29:48.911Z level=INFO source=cpu_common.go:11 msg="CPU has AVX2"
time=2024-04-26T07:29:49.089Z level=INFO source=gpu.go:202 msg="[cudart] CUDART CUDA Compute Capability detected: 6.1"
[GIN] 2024/04/26 - 07:29:50 | 200 |      45.692µs |       127.0.0.1 | HEAD     "/"
[GIN] 2024/04/26 - 07:29:50 | 200 |     378.364µs |       127.0.0.1 | GET      "/api/tags"
downloading model llama3:70b
[GIN] 2024/04/26 - 07:29:50 | 200 |      15.058µs |       127.0.0.1 | HEAD     "/"
pulling manifest ⠏ time=2024-04-26T07:30:20.512Z level=INFO source=images.go:1147 msg="request failed: Get \"https://registry.ollama.ai/v2/library/llama3/manifests/70b\": dial tcp 172.67.182.229:443: i/o timeout"
[GIN] 2024/04/26 - 07:30:20 | 200 | 30.012673354s |       127.0.0.1 | POST     "/api/pull"
pulling manifest
Error: pull model manifest: Get "https://registry.ollama.ai/v2/library/llama3/manifests/70b": dial tcp 172.67.182.229:443: i/o timeout

大模型的生成速度非常慢

70b 是 700 億引數的大模型,使用 CPU 執行不太現實,使用 GPU 也得視訊記憶體足夠大,實測用 24G 視訊記憶體的顯示卡執行速度也非常非常慢,如果沒有更好的 GPU,如何提升生成速度呢?

可以使用多張 GPU 卡並行,修改 ollama 的 YAML,在 requests 中宣告 GPU 的地方,多宣告一些 GPU 算卡:

resources:
  requests:
    nvidia.com/gpu: "4"

這樣,在模型跑起來的時候,幾張 GPU 算卡可以均攤視訊記憶體,而不至於跑滿:

在 Kubernetes 上部署 llama3

相關文章