1.8GB 内存也能跑大模型!Ollama Docker 部署完整指南

144 阅读10分钟

想在服务器上部署私有 AI 模型,但内存不够用?本文教你用 Docker + Swap 优化,让低配服务器也能流畅运行 Ollama 大模型。

背景

为什么选择 Docker 部署?

因为直接使用命令会报错,无法运行ollama。

image.png

1. 简介

1.1 为什么使用 Docker 部署?

优势说明
环境隔离不污染宿主机环境,依赖问题少
一键部署容器化部署,跨平台一致性好
易于管理重启、更新、迁移方便
资源控制可限制内存、CPU 使用
适合生产稳定可靠,推荐生产环境使用

1.2 硬件要求

模型规模内存要求推荐配置
0.5B-3B2-4GB最低 2GB 可用内存
7B-14B8-16GB最低 8GB 可用内存
30B+32GB+最低 32GB 可用内存

1.3 低配服务器(<2GB 内存)

如果你的服务器内存不足(如 1GB-2GB),运行大模型会遇到以下错误:

Error: 500 Internal Server Error: llama runner process has terminated: signal: killed

什么是 Swap?

Swap 是 Linux 系统中的一块硬盘空间,当作"备用内存"使用。当物理内存(RAM)不够用时,系统会把暂时不用的数据从内存搬到 Swap 中,腾出物理内存给需要运行的程序。

┌─────────────────────────────────────────────────┐
│  物理内存 (RAM)     =  你的办公桌(快速但小)    │
│  Swap (虚拟内存)    =  旁边的储物柜(慢但大)    │
│                                                 │
│  当办公桌放满东西时:                            │
│  把不常用的文件 → 放到储物柜 (Swap)             │
│  腾出空间 → 放置正在处理的文件                  │
└─────────────────────────────────────────────────┘

Swap 的作用

作用说明
防止系统崩溃内存不足时,用 Swap 补充,避免进程被杀死
运行大程序允许运行超出物理内存的程序(如大语言模型)
内存回收把不活跃的内存页面移到 Swap,释放物理内存

为什么需要 Swap?

你的服务器配置:
- 物理内存:1.8GB
- 想运行:3b 模型(需要 ~4GB 内存)

没有 Swap:
1.8GB < 4GB → 程序被杀死 ❌

有 5GB Swap:
1.8GB + 5GB = 6.8GB > 4GB → 可以运行 ✅

注意:使用 Swap 会牺牲性能(硬盘速度约为内存的 1/100),但总比程序崩溃好。

添加 Swap 虚拟内存

# 创建 4GB swap 文件
dd if=/dev/zero of=/swapfile bs=1M count=4096
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 永久生效
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# 验证
free -h

不同内存配置的模型推荐

服务器内存推荐模型Swap 需求
1GBqwen2.5-coder:0.5b建议 2GB
2GBqwen2.5-coder:0.5b / 1.5b建议 3GB
4GBqwen2.5-coder:3b不需要
8GB+qwen2.5-coder:7b不需要

Swap 性能判断

Swap 使用量状态建议
0-500MB正常无需处理
500MB-1GB一般注意性能
1GB-2GB较慢考虑换小模型
>2GB很慢必须换小模型

内存监控命令

# 查看当前内存和 Swap 状态
free -h

# 实时监控内存(每 1 秒刷新)
watch -n 1 free -h

# 查看 Docker 容器资源使用
docker stats ollama

# 查看容器内存限制
docker inspect ollama | grep -i memory

# 查看系统内存配置
cat /proc/sys/vm/overcommit_memory
# 0 = 启发式过度分配(默认)
# 1 = 始终允许过度分配
# 2 = 严格控制,不允许过度分配

运行模型时实时监控

开启两个终端窗口:

终端 1:运行模型

docker exec -it ollama ollama run qwen2.5-coder:0.5b

终端 2:实时监控

watch -n 1 'free -h && echo "---" && docker stats ollama --no-stream'

常见问题排查

问题:模型运行时被杀死

# 1. 检查容器内存限制
docker inspect ollama | grep -i memory

# 2. 如果有内存限制,重新创建容器
docker rm -f ollama
docker run -d \
  -p 11434:11434 \
  --name ollama \
  --restart always \
  --memory-swap=-1 \
  ollama/ollama:latest

# 3. 启用内存过度分配
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
echo 'vm.overcommit_memory = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# 4. 重启容器
docker restart ollama

问题:Swap 使用过高导致卡顿

# 查看当前 Swap 使用
free -h

# 如果 Swap 使用 > 1GB,建议切换到更小的模型
docker exec -it ollama ollama run qwen2.5-coder:0.5b

2. 安装 Docker

2.1 Ubuntu/Debian

# 一键安装 Docker
curl -fsSL https://get.docker.com | sh

# 将当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER

# 重新登录或执行以下命令使组权限生效
newgrp docker

# 验证安装
docker --version

2.2 CentOS/RHEL

# 安装 Docker
sudo yum install -y docker

# 启动 Docker 服务
sudo systemctl start docker
sudo systemctl enable docker

# 将当前用户加入 docker 组
sudo usermod -aG docker $user

# 验证安装
docker --version

2.3 验证 Docker 安装

# 运行测试容器
docker run hello-world

# 查看 Docker 版本
docker --version
docker info

3. 部署 Ollama 容器

3.1 拉取镜像

# 拉取最新版 Ollama 镜像
docker pull ollama/ollama:latest

# 或指定版本
docker pull ollama/ollama:0.5.7

3.2 启动容器

CPU 模式(默认):

docker run -d \
  -p 11434:11434 \
  --name ollama \
  --restart always \
  ollama/ollama:latest

GPU 模式(需要 NVIDIA GPU):

# 首先安装 NVIDIA Container Toolkit
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker

# 启动带 GPU 的容器
docker run -d \
  --gpus all \
  -p 11434:11434 \
  --name ollama \
  --restart always \
  ollama/ollama:latest

3.3 验证容器运行

# 查看容器状态
docker ps

# 查看容器日志
docker logs -f ollama

# 测试 API
curl http://localhost:11434/api/tags

4. 模型管理

4.1 拉取模型

# 拉取 qwen2.5-coder:3b
docker exec -it ollama ollama pull qwen2.5-coder:3b

# 拉取其他模型
docker exec -it ollama ollama pull qwen2.5:7b
docker exec -it ollama ollama pull deepseek-r1:7b

4.2 查看已安装模型

docker exec -it ollama ollama list

4.3 运行模型(交互式)

docker exec -it ollama ollama run qwen2.5-coder:3b

4.4 删除模型

docker exec -it ollama ollama rm qwen2.5-coder:3b

4.5 推荐模型

模型用途内存需求
qwen2.5-coder:0.5b代码生成(轻量)~1GB
qwen2.5-coder:3b代码生成(推荐)~4GB
qwen2.5-coder:7b代码生成(专业)~8GB
qwen2.5:3b通用对话~4GB
qwen2.5:7b通用对话(推荐)~8GB

5. API 调用

5.1 基础调用格式

# 生成文本
curl http://localhost:11434/api/generate -d '{
  "model": "qwen2.5-coder:3b",
  "prompt": "用python写一个快速排序",
  "stream": false
}'

# 对话模式
curl http://localhost:11434/api/chat -d '{
  "model": "qwen2.5-coder:3b",
  "messages": [
    {"role": "user", "content": "你好"}
  ],
  "stream": false
}'

5.2 参数说明

参数类型说明默认值
modelstring模型名称-
promptstring输入文本-
streamboolean是否流式输出true
temperaturenumber温度(0-1),越高越随机0.8
num_ctxnumber上下文长度2048

5.3 Python 调用示例

import requests

API_URL = "http://localhost:11434/api/generate"

def call_ollama(prompt: str, model: str = "qwen2.5-coder:3b"):
    response = requests.post(API_URL, json={
        "model": model,
        "prompt": prompt,
        "stream": False
    })
    return response.json()["response"]

# 使用
result = call_ollama("用python写一个快速排序")
print(result)

5.4 JavaScript 调用示例

浏览器环境(原生 Fetch)

// 非流式响应
async function callOllama(prompt) {
  const response = await fetch("http://localhost:11434/api/generate", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "qwen2.5-coder:3b",
      prompt: prompt,
      stream: false
    })
  });

  const data = await response.json();
  return data.response;
}

// 使用
callOllama("用python写一个快速排序").then(console.log);

流式响应(浏览器)

async function chatWithOllama(prompt) {
  const response = await fetch("http://localhost:11434/v1/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: "qwen2.5-coder:3b",
      messages: [{ role: "user", content: prompt }],
      stream: true
    })
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let result = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value);
    const lines = chunk.split("\n").filter(line => line.trim());

    for (const line of lines) {
      if (line.startsWith("data: ")) {
        const data = line.slice(6);
        if (data === "[DONE]") continue;
        try {
          const json = JSON.parse(data);
          const content = json.choices?.[0]?.delta?.content;
          if (content) {
            result += content;
            console.log(content);  // 实时输出
          }
        } catch (e) {
          // 忽略解析错误
        }
      }
    }
  }
  return result;
}

// 使用
chatWithOllama("用python写一个快速排序");

Node.js 环境

const axios = require("axios");

async function callOllama(prompt) {
  const response = await axios.post(
    "http://localhost:11434/api/generate",
    {
      model: "qwen2.5-coder:3b",
      prompt: prompt,
      stream: false
    }
  );

  return response.data.response;
}

// 使用
callOllama("用python写一个快速排序").then(console.log);

带认证的调用

// 如果设置了 API 密钥
async function callOllamaWithAuth(prompt) {
  const response = await fetch("http://localhost:11434/api/generate", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer your_api_key_here"
    },
    body: JSON.stringify({
      model: "qwen2.5-coder:3b",
      prompt: prompt,
      stream: false
    })
  });

  const data = await response.json();
  return data.response;
}

5.5 OpenAI 兼容格式(JavaScript)

// 使用 OpenAI SDK 调用 Ollama
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: "http://localhost:11434/v1",
  apiKey: "ollama"  // 不需要真实 key
});

async function chat(prompt) {
  const response = await client.chat.completions.create({
    model: "qwen2.5-coder:3b",
    messages: [{ role: "user", content: prompt }]
  });

  return response.choices[0].message.content;
}

// 使用
chat("用python写一个快速排序").then(console.log);

5.6 外网调用示例

// 如果配置了外网访问(需要 HTTPS + API Key)
async function callOllamaRemote(prompt) {
  const response = await fetch("https://your-domain.com/api/generate", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer your_secure_password"
    },
    body: JSON.stringify({
      model: "qwen2.5-coder:3b",
      prompt: prompt,
      stream: false
    })
  });

  const data = await response.json();
  return data.response;
}

6. 容器管理

6.1 查看容器状态

# 查看运行中的容器
docker ps

# 查看所有容器(包括停止的)
docker ps -a

# 查看容器详细信息
docker inspect ollama

6.2 日志管理

# 查看实时日志
docker logs -f ollama

# 查看最近 100 行日志
docker logs --tail 100 ollama

# 查看带时间戳的日志
docker logs -t ollama

6.3 启停重启

# 停止容器
docker stop ollama

# 启动容器
docker start ollama

# 重启容器
docker restart ollama

# 删除容器(需先停止)
docker rm -f ollama

6.4 进入容器

# 进入容器 shell
docker exec -it ollama bash

# 在容器中执行命令
docker exec -it ollama ollama list

7. 进阶配置

7.1 持久化模型存储

默认情况下,模型存储在容器内部,删除容器后模型会丢失。使用挂载卷持久化:

# 删除旧容器
docker rm -f ollama

# 重新创建,挂载本地目录
docker run -d \
  -p 11434:11434 \
  -v ollama_data:/root/.ollama \
  --name ollama \
  --restart always \
  ollama/ollama:latest

7.2 资源限制

# 限制内存使用为 4GB
docker run -d \
  -p 11434:11434 \
  --memory=4g \
  --name ollama \
  --restart always \
  ollama/ollama:latest

# 限制 CPU 使用
docker run -d \
  -p 11434:11434 \
  --cpus=2.0 \
  --name ollama \
  --restart always \
  ollama/ollama:latest

7.3 环境变量配置

docker run -d \
  -p 11434:11434 \
  -e OLLAMA_HOST=0.0.0.0:11434 \
  -e OLLAMA_NUM_PARALLEL=4 \
  -e OLLAMA_DEBUG=0 \
  -v ollama_data:/root/.ollama \
  --name ollama \
  --restart always \
  ollama/ollama:latest

7.4 使用 Docker Compose

创建 docker-compose.yml

version: '3.8'

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0:11434
      - OLLAMA_NUM_PARALLEL=4
    restart: always
    # GPU 配置(需要 nvidia-docker)
    # deploy:
    #   resources:
    #     reservations:
    #       devices:
    #         - driver: nvidia
    #           count: all
    #           capabilities: [gpu]

volumes:
  ollama_data:

启动:

docker-compose up -d

7.5 国内镜像加速

# 使用国内镜像源
docker pull registry.cn-hangzhou.aliyuncs.com/ollama/ollama:latest

# 或使用代理
docker pull ollama/ollama:latest

8. 故障排查

8.1 容器启动失败

# 查看容器日志
docker logs ollama

# 常见错误:GPU 配置问题
# 解决方案:删除容器,使用 CPU 模式重新创建
docker rm -f ollama
docker run -d -p 11434:11434 --name ollama --restart always ollama/ollama:latest

8.2 无法访问 API

# 检查容器是否运行
docker ps

# 检查端口是否正确映射
docker port ollama

# 测试容器内部 API
docker exec ollama curl http://localhost:11434/api/tags

# 检查防火墙
sudo ufw status  # Ubuntu
sudo firewall-cmd --list-all  # CentOS

8.3 模型加载慢

# 查看资源使用情况
docker stats ollama

# 检查磁盘 IO
docker exec ollama df -h

8.4 内存不足

# 查看容器资源使用
docker stats --no-stream

# 使用更小的模型
docker exec -it ollama ollama pull qwen2.5-coder:0.5b

# 或限制容器内存
docker update --memory=4g ollama

9. 生产部署建议

9.1 安全配置

# 绑定到本地地址
docker run -d \
  -p 127.0.0.1:11434:11434 \
  --name ollama \
  ollama/ollama:latest

# 使用反向代理(Nginx)配置 HTTPS

9.2 监控配置

# 使用 Prometheus + Grafana 监控
docker run -d \
  --name prometheus \
  -p 9090:9090 \
  prom/prometheus

# 配置 cAdvisor 监控容器
docker run -d \
  --name cadvisor \
  -p 8080:8080 \
  google/cadvisor:latest

9.3 高可用配置

# 使用负载均衡
# 部署多个 Ollama 实例,通过 Nginx 负载均衡

# 使用健康检查
docker run -d \
  --name ollama \
  --health-cmd="curl -f http://localhost:11434/api/tags || exit 1" \
  --health-interval=30s \
  --health-timeout=10s \
  --health-retries=3 \
  ollama/ollama:latest

10. 常用命令速查

# 拉取模型
docker exec -it ollama ollama pull qwen2.5-coder:3b

# 查看模型列表
docker exec -it ollama ollama list

# 运行模型
docker exec -it ollama ollama run qwen2.5-coder:3b

# 查看日志
docker logs -f ollama

# 重启容器
docker restart ollama

# 进入容器
docker exec -it ollama bash

# 删除容器
docker rm -f ollama

# 测试 API
curl http://localhost:11434/api/tags