..

使用Docker在8GB内存的VPS上部署 Ollama + 小参数LLM

简介

Ollama 是一个平台,专注于运行大型语言模型(LLMs)并简化其管理和部署流程。它支持多种语言模型,如 Llama 3.1、Phi 3、Mistral 和 Gemma 2,可以帮助用户定制和创建自己的模型。Ollama 提供了跨平台支持,包括 macOS、Linux 和 Windows(预览版)。

可以访问 Ollama 的官方网站 来了解更多信息。

小参数量模型资源需求对比

让ChatGPT 4o列举一下常用小参数LLM模型的资源需求:

模型 参数数量 内存需求 适用场景
GPT-2 (117M) 117M ~2.5GB 通用 NLP 任务
DistilGPT-2 82M ~2GB 通用 NLP 任务
ALBERT 12M-18M ~1.5GB 低资源 NLP 任务
MiniLM 22M-33M ~2GB 低延迟 NLP 任务
BERT-base 110M ~2.5GB 通用 NLP 任务
BERT-small 4M-11M ~1GB 低资源 NLP 任务
ELECTRA-small 14M ~1.5GB 高效训练和推理

GPT推荐的都是什么?算了,这些Ollama也不一定支持,我们还是去Ollama官网Library找找看吧。

VPS配置

使用如下命令查看硬盘、CPU、内存等信息,本VPS没有GPU,只能使用CPU Only模式。

df -h
lscpu
cat /proc/cpuinfo
free -h
cat /proc/meminfo

参数直接扔给ChatGPT 4o,分析结果如下:

根据提供的硬件信息,分析是否可以在您的 VPS 上运行 Ollama 和 TinyLlama 模型:

硬件信息摘要

CPU:
 4 个 CPU 核心
 AMD EPYC 7642 48-Core Processor
 2.3 GHz

内存:
 总内存: 7.6 GiB
 可用内存: 5.5 GiB
 Swap: 255 MiB

硬盘:
 总大小: 59G
 可用大小: 31G

分析

CPU
您的 VPS 具有 4 个 CPU 核心,这是一个良好的基础,足以处理一些轻量级的机器学习模型和推理任务。虽然没有 GPU 可能会影响某些深度学习任务的效率,但使用 CPU 仍然是可行的,特别是对于小型模型如 TinyLlama。

内存
TinyLlama 模型在不同量化级别下的内存需求如下:
 TinyLlama: 3.4GB
 TinyLlama:Q6_K: 3.4GB
 TinyLlama:Q8_0: 3.67GB

您的系统总内存为 7.6 GiB,可用内存为 5.5 GiB,这足以运行 TinyLlama 模型。然而,您需要确保在运行模型时其他进程不会消耗过多的内存。此外,建议增加 swap 空间,以防止内存不足的情况。

硬盘
您的硬盘有 31G 的可用空间,这是足够的,因为模型和相关依赖项不会占用太多磁盘空间。TinyLlama 模型大约在 0.5G 到 2G 之间,这对您的可用空间影响不大。

结论
基于以上分析,您的 VPS 应该能够运行 Ollama 和 TinyLlama 模型,前提是适当地管理资源和优化配置。

部署 Ollama

CPU Only

docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama

加载小参数量LLM

docker exec -it ollama ollama run tinyllama

这时候,我们可以通过终端和TinyLlama进行交互了。

接下来我们换Phi 3 Mini试试(仅下载phi3不开启终端)。

docker exec -it ollama ollama pull phi3

删除tinyllama模型:

docker exec -it ollama ollama rm tinyllama

用Open Webui管理Ollama

考虑到直接使用终端不那么方便,我们可以使用Open Webui来管理Ollama。

docker run -d -p 8380:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main

这时候我们可以通过 http://{VPS_IP}:8380 访问Open Webui,进行Ollama的管理。

使用Webui对话测试

尝试打个招呼:

尝试打个招呼

分析下docker命令:

分析下docker命令

解释代码:

解释代码

调试

如果在部署过程中遇到问题,可以通过以下命令查看容器日志:

docker logs ollama
docker logs open-webui

查看容器消耗的资源:

docker stats ollama
docker stats open-webui

资源消耗

如图所示是Ollama的资源消耗情况, 终端展示:

资源消耗情况

图形监控:

图形监控

很明显,在推理的时候CPU和内存占用率会上升:

CPU和内存占用率

进阶:Ollama API + 授权

通过上述docker命令安装的Ollama默认是开放远程API访问的,测试如下:

  • List Local Models
curl -X GET http://{VPS_IP}:11434/api/tags

返回值:

{
	"models": [{
		"name": "phi3:latest",
		"model": "phi3:latest",
		"modified_at": "2024-08-08T06:06:59.799084299Z",
		"size": 2176178913,
		"digest": "4f222292793889a9a40a020799cfd28d53f3e01af25d48e06c5e708610fc47e9",
		"details": {
			"parent_model": "",
			"format": "gguf",
			"family": "phi3",
			"families": ["phi3"],
			"parameter_size": "3.8B",
			"quantization_level": "Q4_0"
		}
	}]
}
  • Generate a completion
curl -X POST http://{VPS_IP}:11434/api/generate -d '{
  "model": "phi3",
  "prompt": "hi"
}'

返回值:

{"model":"phi3","created_at":"2024-08-08T07:42:15.076509049Z","response":"hello","done":false}
{"model":"phi3","created_at":"2024-08-08T07:42:15.162735993Z","response":" there","done":false}
{"model":"phi3","created_at":"2024-08-08T07:42:15.245395284Z","response":"!","done":false}
{"model":"phi3","created_at":"2024-08-08T07:42:15.330822219Z","response":" How","done":false}
省略...

两种常用方式可以避免自己的Ollama被滥用,至于通过系统防火墙限制等不在我们的讨论范围内。

  1. 限制Ollama只能本地访问,可以通过修改docker run命令。

  2. 使用Nginx反向代理,转发请求并加入认证,以及关于Ollama为什么没有认证系统,可以在Ollama Github的issue中查看相关讨论。

我们使用Ollama Proxy Server来增加个简单的验证。

首先我们删除原来的Ollama容器:

docker container stop ollama
docker container rm ollama

然后创建绑定“本地”端口的新容器。

docker run -d -v ollama:/root/.ollama -p 127.0.0.1:11434:11434 --name ollama ollama/ollama
docker exec -it ollama ollama pull phi3

查看容器是否正常运行:

docker container ls | grep ollama
23b092ad82f3   ollama/ollama                        "/bin/ollama serve"      20 seconds ago   Up 20 seconds           127.0.0.1:11434->11434/tcp                  ollama

安装Ollama Proxy Server,代理Ollama的请求。按照Ollama Proxy Server的项目说明,Git Clone项目到Ollama所在的VPS,修改config.ini和authorized_users.txt然后构建并运行Docker镜像。

cat config.ini
[DefaultServer]
url = http://host.docker.internal:11434
queue_size = 5
cd ollama_proxy_server
docker build -t ollama_proxy_server:latest .
docker run -d --name ollama-proxy-server -p 8381:8080 --add-host=host.docker.internal:host-gateway ollama_proxy_server:latest

接下来我们尝试下通过Open Webui访问Ollama,发现无法访问!通过Ollama Proxy Server访问也是如此,那么查看下容器日志:

docker logs open-webui
ERROR [apps.ollama.main] Connection error: Cannot connect to host host.docker.internal:11434 ssl:default [Connection refused]

日志显示Open Webui和Ollama之间不通,容器间通信异常是很常见的问题,我们查看下之前open-webui的docker命令,注意host.docker.internal:host-gateway,我们看下host-gateway的值,host-gateway正常是容器网关的IP地址。

docker inspect -f '{{.NetworkSettings.Networks.bridge.Gateway}}' open-webui
172.17.0.1

再看下容器的hosts
docker exec -it open-webui /bin/bash
root@4ff3c3b6eb8f:/app/backend# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.1	host.docker.internal
172.17.0.5	4ff3c3b6eb8f

再查看下容器内部IP:

docker ps -q | xargs -n 1 docker inspect --format '{{.Name}}{{range $k,$v := .NetworkSettings.Networks}} - {{$k}}: {{$v.IPAddress}}{{end}}'
/ollama - bridge: 172.17.0.4
/ollama-proxy-server - bridge: 172.17.0.6
/open-webui - bridge: 172.17.0.5

我们都知道,host.docker.internal 是一个特殊的主机名,它用于在 Docker 容器内部访问宿主机(即运行 Docker 容器的主机)上的服务,其实问题的核心在于容器间的网络连接和 127.0.0.1 的特殊性。

关键点分析

  • 127.0.0.1 的含义

    • 在任何计算机系统中,127.0.0.1 指的是本地回环地址,通常只用于指代“自己”。在一个容器中绑定到 127.0.0.1,它意味着服务只在这个容器内部的回环地址上可用,并且不能被其他容器或外部主机访问。
  • -p 127.0.1:11434:11434 的问题

    • ollama 容器中指定 -p 127.0.1:11434:11434 时,它将 11434 端口绑定到主机的 127.0.1 地址。这意味着该服务只能在主机本身的 127.0.1 上访问,即只有主机本身可以访问,而其他容器无法直接通过 host.docker.internal 来访问这个服务,因为从 Docker 容器的角度看,127.0.0.1 仍然是指自身。

问题的根本

在于 127.0.0.1 是一个本地回环地址,只能在本地使用,而不能被外部访问。

要解决这种问题其实很简单,docker compose就是我们经常用来管理多个容器的。我们创建一个docker-compose.yml文件,将Ollama、Open Webui和Ollama Proxy Server等通过容器内部网路互联;同时创建了一个Dockerfile修改了下ollama镜像增加了curl用于健康检查,并且定义了内部网络ol-internal和外部网络ol-external。

首先进入Ollama Proxy Server项目目录,修改config.ini文件,将url改为http://ollama:11434。

cat config.ini
[DefaultServer]
url = http://ollama:11434
queue_size = 5

然后重新打包下Ollama Proxy Server镜像。

docker build -t ollama_proxy_server:latest .

也可以把上述也一起整合进docker compose文件中,我这里是分开的。下面Dockerfile和docker-compose.yml文件如下:

FROM ollama/ollama
RUN apt-get update && apt-get install -y curl
version: '3.8'

services:
  ollama:
    build: .
    container_name: ollama
    volumes:
      - ollama:/root/.ollama
    expose:
      - "11434"
    networks:
      - ol-internal
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11434"]
      interval: 10s
      timeout: 5s
      retries: 3

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    volumes:
      - open-webui:/app/backend/data
    ports:
      - "8380:8080"
    environment:
      - OLLAMA_BASE_URL=http://ollama:11434
    depends_on:
      ollama:
        condition: service_healthy

    networks:
      - ol-internal
      - ol-external

  ollama-proxy-server:
    image: ollama_proxy_server:latest
    container_name: ollama-proxy-server
    ports:
      - "8381:8080"
    depends_on:
      ollama:
        condition: service_healthy
    networks:
      - ol-internal
      - ol-external

volumes:
  ollama:
  open-webui:

networks:
  ol-internal:
    name: ol-internal
  ol-external:
    name: ol-external

最后再用Curl验证下,也可以通过Postman等工具。

直接访问Ollama Rest API:

curl -X GET http://{VPS_IP}:11434/api/tags

返回值:

curl: (7) Failed connect to {VPS_IP}:11434; No route to host

访问Ollama Proxy Server:

curl -X GET -H "Authorization: Bearer {username}:{secret}" http://{VPS_IP}:8381/api/tags

curl -X POST -H "Authorization: Bearer {username}:{secret}" http://{VPS_IP}:8381/api/generate -d '{"model":"phi3","prompt": "hi"}'

返回值:

{
	"models": [{
		"name": "phi3:latest",
		"model": "phi3:latest",
		"modified_at": "2024-08-09T06:13:03.416308442Z",
		"size": 2176178913,
		"digest": "4f222292793889a9a40a020799cfd28d53f3e01af25d48e06c5e708610fc47e9",
		"details": {
			"parent_model": "",
			"format": "gguf",
			"family": "phi3",
			"families": ["phi3"],
			"parameter_size": "3.8B",
			"quantization_level": "Q4_0"
		}
	}]
}

总结

我们可以通过Docker很方便的在内存不大的服务器上部署Ollama和TinyLlama、Phi3等小参数量LLM,并通过Open Webui管理和使用Ollama,通过远程API访问Ollama,通过Ollama Proxy Server增加简单的认证。

相关资料