这个系列原本的计划,是继续在 Docker 方案上往下写性能调优。结果在实际部署环境里,Docker 路线硬生生卡了大半天,最后换成了 Ollama 原生二进制直装,反而一路顺畅。这篇记录就是想复盘一下:为什么容器化部署在私有化环境里会受阻;二进制直装的关键步骤有哪些;以及跑起来之后那些官方文档不会告诉你的坑。如果你也正在给公司内网搭私有 AI 服务,这文章大概率能帮你省掉不少折腾时间。
我先说结论:Ollama 这种面向本地推理设计的程序,二进制直装的复杂度和维护成本,在受限环境里往往比 Docker 更低。它不是技术问题,是部署模型和环境基线之间的匹配问题。下面我把这次从 Docker 受阻到切二进制方案的完整过程拆开讲。
1. Docker 受阻的真实原因,不只是“拉不下来镜像”
1.1 容器运行时碰上了合规门槛
这次部署的目标环境比较特殊。那是一个已经有现行业务在跑的生产网段,安全基线里明确要求“非必要不新增容器运行时”。说白了,Docker daemon 本身要 root 常驻,还会引入镜像层、网络策略、特权模式等一系列安全面。安全团队看了一圈之后,要求先提交容器镜像和运行时漏洞清单,再走新的评估流程。
这个流程不是不能走,但时间不可控。而私有 AI 部署这个需求,往往带着“尽快跑通一个 Demo”“先内部试用几周”的业务节奏。两边一撞,问题就变成了:有没有一种方式,不动容器基线,也能把 Ollama 跑起来?
我当时的第一反应是检查这台机器上有没有别的运行时。结果发现目标服务器上连 Podman、containerd 这类替代品也没有,而且同样涉及新的安全评估。继续在这条路上耗,不如换个思路。
1.2 镜像仓库与 GPU 透传的组合问题
就算容器运行时问题能解决,Docker 部署还有第二关:镜像拉取和 GPU 透传。我们当时在目标网段尝试直连公网镜像仓库,现象很典型——超时、断连、多层下载到一半失败。后来审批了一个代理通道,镜像能拉了,又轮到 GPU。
容器里要让 Ollama 调用 NVIDIA 显卡,需要宿主机装驱动、装 nvidia-container-toolkit,并且驱动版本、toolkit 版本、容器运行时版本三者匹配。我们遇到的情况是宿主机驱动已经升到较新的 550 系列,而 toolkit 还是旧版本,容器里执行nvidia-smi始终列不出设备,排查了半天发现是版本兼容性导致的注入失效。
如果把这三个问题放在同一张表里看,就很清楚了:
| 问题环节 | Docker 方案的阻力 | 对进度的影响 |
|---|---|---|
| 容器运行时审批 | 安全基线不允许,需走豁免流程 | 数天甚至数周 |
| 镜像获取 | 公网仓库连接不稳定,代理审批复杂 | 半天到一天 |
| GPU 透传 | toolkit 与驱动版本强绑定,兼容性易出问题 | 数小时起 |
三个环节叠在一起,就是把“本来十分钟能启动的服务”变成了“一个需要多方配合的跨团队项目”。
1.3 二进制直装为什么反而更顺手
Ollama 本身的 Linux 二进制包设计得很轻。它不依赖一堆系统库,也不需要单独的守护进程管理器,一个可执行文件就能完成 serve、pull、run 等全部操作。没有镜像层、没有挂载点、没有容器网络,安全团队只需要审计一个二进制的来源和校验值。
这和很多人的直觉相反。大家默认“容器化 = 更规范”,但在私有化部署、尤其是生产网段这种对进程边界敏感的环境里,单个原生进程反而更容易被接纳。进程归属清晰、资源占用透明、停止和启动逻辑简单。对于部署者来说,也少了一层容器编排的复杂度——不需要维护 docker-compose、不需要管理容器日志,systemd 一套就能把运行状态管好。
2. 切换方案前先想清楚:目录设计与环境准备
2.1 程序文件、模型文件、运行账号三者分离
二进制直装最大的优势是目录结构由自己说了算。我在这次部署里直接沿用了 Linux 服务化的标准思路:程序、模型、日志各安其位。
我用了这组目录规划:
/usr/local/bin/ollama:Ollama 主程序/opt/ollama/models:模型文件仓库,专门放 GGUF 等大体积模型/opt/ollama:运行账号 ollama 的家目录,同时承载运行状态文件
把模型目录单独放在/opt/ollama/models是很有必要的。默认情况下 Ollama 会把模型塞在当前用户的家目录.ollama/models下面,如果你用 root 跑,模型就全堆在根分区。一旦后续模型拉多了,根分区空间会被打满,这是很多人在二进制部署时踩的第一个坑。我这次专门用独立账号和一个独立挂载点,把空间风险隔离出去。
2.2 硬件依赖确认
Ollama 虽然是个单文件程序,但它对硬件的依赖一点不少。动手之前,我先在目标服务器上确认了三件事:
- CPU 架构:这次是 x86_64 环境,直接选 linux-amd64 包
- NVIDIA 驱动状态:执行
nvidia-smi确认驱动能正常识别显卡 - 磁盘余量:当时只剩不到 30GB,考虑到要拉 8B 级模型,又把模型盘加到了至少 60GB 空闲
如果你的机器没有 NVIDIA 显卡,也可以跑 CPU 推理,但速度差距会很明显,8B 模型在纯 CPU 上生成一个 token 可能要几百毫秒甚至更久,交互体验会比较受限。有显卡的话,显存建议至少 8GB 起步,8B 级模型量化后大概需要 5-6GB 显存,留出余量才能跑得舒服。
2.3 软件获取方式
Ollama 官方提供了两个安装入口:一个是一键脚本,一个是手动下载 tar 安装包。一键脚本适合公网环境,它会自动检测系统架构并安装到常规路径。但这次部署环境对公网访问不友好,我最终选择的是离线方式:找一台能访问外网的机器下载安装包,通过内网通道传到目标服务器,然后手动解压配置。
下载链接可以直接从 Ollama 官网的下载页找到,文件名类似ollama-linux-amd64.tgz。这里我一直强调手动方式,因为它在受限环境里的可控性最高——下载什么、放在哪里、二进制校验值是多少,每一步都能留下记录,后续跟安全团队解释也方便。
3. 实操过程:从下载二进制到跑起第一个私有模型
3.1 下载与校验
拿到 tar 包之后,第一件事不是急着解压,而是算校验值。我执行了:
sha256sum ollama-linux-amd64.tgz然后把结果和官网发布的校验值做对比。这一步千万别省。私有化环境里信任链很重要,既然没有容器镜像签名那套机制,二进制校验就是最直接的信任依据。
顺便说一句,如果你是在公网环境,也可以直接用官方脚本:
curl -fsSL https://ollama.com/install.sh | sh脚本装完会把 ollama 放在/usr/local/bin/ollama。但在受限环境里,我还是倾向于手动放包。校验无误之后,我做了解压:
tar -xzf ollama-linux-amd64.tgz解压出来之后,把 ollama 可执行文件复制到/usr/local/bin/下面,同时把自带的动态库文件放到系统库路径或者 Ollama 自己能找到的位置。具体放置方式要按照包里目录结构来,这里不展开每个细节,但记得用ollama --version验证一下二进制能正常执行,再进入下一步。
3.2 创建专用账号与目录
老规矩,服务不能拿 root 跑。我创建了一个专用账号:
useradd -r -s /bin/false -m -d /opt/ollama ollama mkdir -p /opt/ollama/models chown -R ollama:ollama /opt/ollama解释一下这几个参数:-r表示系统账号,不用于登录;-s /bin/false禁止 shell 登录;-m -d /opt/ollama把家目录指定到/opt/ollama。这样一来 Ollama 的默认状态文件、临时文件都会落在业务规划好的目录里,而不是散落在多个地方。
这个账号设计对后面排查问题有很大帮助。因为所有文件归属清晰,遇到权限报错时看一眼属主就能定位,不需要去猜。
3.3 systemd 服务单元,直接管理进程生命周期
二进制方式跑 Ollama,让它开机自启、崩溃自动拉起,最顺手的方式是写一个 systemd unit 文件。我放在/etc/systemd/system/ollama.service,内容如下:
[Unit] Description=Ollama Service After=network-online.target [Service] User=ollama Group=ollama ExecStart=/usr/local/bin/ollama serve Restart=always RestartSec=3 Environment="OLLAMA_MODELS=/opt/ollama/models" Environment="OLLAMA_HOST=0.0.0.0:11434" [Install] WantedBy=multi-user.target这里面每项配置都有讲究。User=ollama保证进程丢弃 root 权限;Restart=always应对偶发崩溃;OLLAMA_MODELS把模型仓库指向独立目录;OLLAMA_HOST决定监听地址。默认情况下 Ollama 只监听127.0.0.1:11434,如果之后有其他服务器或者前端页面需要访问这台机器的 API,必须把监听地址改成0.0.0.0:11434,否则外部请求根本进不来。
然后启动并设置开机自启:
systemctl daemon-reload systemctl enable ollama systemctl start ollama启动完立刻确认状态:
systemctl status ollama如果看到active (running),说明服务已经起来了。注意ollama serve是前台进程,不要让 systemd 误判它已经结束,上面这样配置就没有这个问题。
3.4 拉取第一个私有模型
服务就绪之后,开始拉模型。我这里选了 qwen2.5:7b 作为示例,原因是它在中文场景下的表现比较可靠,模型体积也在可控范围内:
ollama pull qwen2.5:7b首次拉取会有比较明显的进度条,如果网络环境不太好,拉取中途可能需要重试。模型文件会写入OLLAMA_MODELS指定的目录。拉完之后执行:
ollama list查看已下载的模型列表,确认模型已经就位。
接着用交互模式跑一次对话,验证推理链路:
ollama run qwen2.5:7b输入一句话让它回答,如果输出正常,说明 GPU 推理、模型加载、文本生成这一整套链路已经打通。
3.5 API 层面验证,不只是“能用”
命令行验证通过之后,还要确认 API 接口对外开放正常,因为后续你可能要接前端页面或者其他内部系统。我用两个请求做检查:
curl http://127.0.0.1:11434/api/tags这个请求返回本机装载的所有模型列表,只要 JSON 里能看到 qwen2.5:7b 就说明服务正常。
再测一次生成请求:
curl http://127.0.0.1:11434/api/generate \ -d '{"model": "qwen2.5:7b", "prompt": "你好,请简单介绍一下你自己", "stream": false}'这个请求会完整走一遍推理流程,返回结果里包含response字段。如果从这里也正常输出文本,那就说明从进程管理、模型管理到 API 服务全部可用,可以放心接业务了。
4. 私有化部署里最容易踩的坑,我一次给你列全
4.1 服务起不来,先看这两个位置
二进制部署少了容器这层“黑盒”,排查问题反而直接很多。服务起不来的情况,我习惯先看两个位置:systemd 日志和端口监听状态。
journalctl -u ollama -f ss -lntp | grep 11434journalctl能告诉你具体的报错原因,比如目录权限不对、动态库找不到、端口被占用。而ss -lntp可以确认端口到底有没有监听。有一类问题是环境变量没生效,导致模型目录还是默认路径,这种时候/proc/<pid>/environ可以直接看到进程实际拿到的环境变量,对比一下 systemd 配置就很清楚了。
如果端口被占用,优先排查是不是之前测试时手动跑过一个ollama serve还在后台。把旧进程杀掉再systemctl restart ollama就好。还有一种情况是防火墙没有放行 11434 端口,这属于外部策略问题,不影响进程本身,但会造成外部请求超时。
4.2 模型拉取反复中断,怎么处理最稳
内网环境拉模型,中断是大概率事件。Ollama 的 pull 流程是分块下载的,断点续传能力比很多工具都好。遇到中断,直接重新执行一次ollama pull,大部分情况会从断点继续,而不是重新下载整个文件。
但有两种情况需要手动介入。一种是中断反复发生在同一个进度位置,很可能是磁盘空间不足,下载块无法落盘,这时候检查df -h看看模型目录所在分区是否写满。另一种是拉取完成后提示 manifest 错误,整体校验不过,这时候可以先把模型目录里对应的不完整目录删除,重新 pull 一次。
我这次就遇到过“显示 99% 但一直卡住不动”的情况,最后查出来是磁盘 inode 耗尽,小文件太多导致写不进去。清了一轮临时文件之后,重新 pull 就通畅了。这类问题只盯着模型文件大小是看不出来的,一定要关注磁盘 inode。
4.3 权限问题,专治各种想当然
如果你用 root 跑了第一次ollama run,之后再切到普通用户执行,大概率会碰到权限报错。原因是模型和运行状态文件放在了 root 的目录下面,普通用户没有访问权限。
我这次的规避办法是全程用专用账号跑,创建目录、部署二进制、写 systemd 配置的时候把属主都指到 ollama 用户。这样后面所有操作都走 systemd 服务,不涉及手工切换身份。
如果你已经踩了这个坑也没关系,处理起来不复杂:
chown -R ollama:ollama /opt/ollama chown ollama:ollama /usr/local/bin/ollama systemctl restart ollama把目录和二进制归属统一之后,再做一次权限校验。
4.4 GPU 识别不到,反复跑在 CPU 上
最隐蔽的一个坑:nvidia-smi能正常看到显卡,但 Ollama 一直在用 CPU 推理,速度慢得离谱。我在排这类问题时的经验是先看两件事。
第一,确认 Ollama 版本和驱动版本的兼容性。Ollama 自带 CUDA 运行时,对驱动版本有最低要求,新版本通常要求相对较新的驱动。驱动太旧,它会自动回退到 CPU 模式,且不会有明显报错。
第二,确认 CUDA 运行库能否被加载。Ollama 在启动时会加载自带或系统的 CUDA 相关库文件,如果系统缺依赖,日志里会有找不到.so文件的提示。这时候可以用ldd /usr/local/bin/ollama检查库依赖是否完整。
有一种判断是否真的用了 GPU 的方法:拉起模型后执行nvidia-smi看显存占用。如果看到多出几个 GB 的显存占用,说明确实是 GPU 推理;如果显存纹丝不动且 CPU 占用飙升,那就是回退到 CPU 了。
4.5 局域网内其他机器连不上 API
服务跑起来了,但同一内网的其他服务器访问http://<服务器IP>:11434超时。这个问题的排查顺序固定:先确认监听地址是不是0.0.0.0,再看防火墙。
OLLAMA_HOST=0.0.0.0:11434已经在 systemd 里配置了,但如果你修改后忘了systemctl daemon-reload,环境变量不会重新加载。踩过一次这个坑之后,我现在的习惯是改完 unit 立刻执行两步:
systemctl daemon-reload systemctl restart ollama防火墙方面,检查本机和网络侧的策略。本机可以用firewall-cmd或ufw放行 11434,如果网络侧还有安全组策略,也要一并确认。
4.6 删除模型后磁盘空间没有释放
这个问题比较容易“吓到人”。你以为rm -rf把模型目录删了就万事大吉,结果空间一点没少。原因是 Ollama 的模型采用分层存储,多个模型之间会共享一些公共层。手动删文件会留下大量孤儿层,而且可能导致其他模型损坏。
正确的做法是用 Ollama 自己的命令删除模型:
ollama rmi qwen2.5:7b它会识别模型的引用关系,把无用的层一并清理。我在总结这次经验的时候,特意把“模型删除必须走 rmi,不要直接 rm”写进了内部操作规范。下面把这些坑整理成一张速查表,方便你对照排查:
| 现象 | 优先排查项 | 常用命令 | 对应章节 |
|---|---|---|---|
| 服务无法启动 | systemd 日志、端口占用 | journalctl、ss | 4.1 |
| 模型拉取卡死 | 磁盘空间、inode、网络 | df、ollama pull | 4.2 |
| 权限报错 | 目录属主、账号一致性 | chown、systemctl | 4.3 |
| 速度极慢疑似 CPU | 驱动版本、CUDA 库、显存占用 | nvidia-smi、ldd | 4.4 |
| 外部连不上 API | 监听地址、防火墙、环境变量 | ss、curl | 4.5 |
| 删除模型空间没释放 | 分层存储、孤儿层 | ollama rmi | 4.6 |
5. 跑起来之后的实际调优与运维建议
5.1 并发请求处理的参数逻辑
二进制部署跑通之后,紧接着就是“能不能对外提供服务”的问题。Ollama 有个参数OLLAMA_NUM_PARALLEL,用来控制并行处理请求的数量。它默认行为和模型占用的显存有关,适当调高可以让多个请求同时进入模型处理,而不是排队等待。
但这个参数不是越大越好。并行请求会成倍增加显存占用,如果超出显存容量,就会发生内存换页,性能断崖式下降。我这次的机器有 24GB 显存,跑 7B 量化模型,实测把并行数调到 4 左右性价比最高,超过 4 之后延迟明显上升。
另一个值得关注的是OLLAMA_KEEP_ALIVE,它控制模型在内存或显存中的驻留时间。默认情况下模型会保留一段时间,避免频繁请求时反复加载。如果你的场景是低频调用,例如每天几次报表生成,可以把 keep-alive 调短一些,及时释放显存给其他任务;如果场景是高频率对话,就可以适当拉长驻留时间。
5.2 多卡机器的显存分配策略
有些服务器不止一张显卡。如果 Ollama 有多块卡可选,它默认的策略不一定会把模型放在你想让它放的卡上。在 systemd 环境变量里加上CUDA_VISIBLE_DEVICES可以精确指定可见的 GPU:
Environment="CUDA_VISIBLE_DEVICES=0"这样模型只会加载到编号 0 的显卡上,方便和其他业务做资源隔离。如果一块卡放不下一个模型,可以尝试让 Ollama 在多个 GPU 上切分模型,但这个要谨慎,跨卡推理的通信开销在某些场景下会抵消扩容收益。
还有一点容易忽略:Ollama 加载模型时,默认会按照可用显存做适配。如果你看到模型加载到一个意想不到的显存占用水平,可以通过ollama ps查看当前加载的模型及其显存占用情况。这是诊断显存问题的第一个入口。
5.3 升级、备份与回滚
二进制部署的升级非常简单——下载新版本二进制,替换掉旧的,重启服务。我通常会保留一份当前能用的旧二进制,命名为ollama.bak,以防新版本行为异常时快速回滚。三步搞定:
systemctl stop ollama cp /usr/local/bin/ollama /usr/local/bin/ollama.bak # 将新版本二进制放到 /usr/local/bin/ollama systemctl start ollama模型目录/opt/ollama/models是整个服务最核心的数据资产。备份的时候直接拷贝模型目录就好,不需要关心进程状态。如果要迁移到另一台机器,把模型目录整体复制过去,再装一个相同版本或更高版本的 Ollama,修改一下OLLAMA_MODELS指向,就能无缝接上。
日志方面,二进制部署不像容器可以扔到驱动平台,我建议在 systemd unit 里把输出重定向到一个固定位置,或者依托系统自带的 journald 做集中查看。日常巡检主要看三件事:服务是否活着、显存是否异常占用、磁盘余量是否充足。
这次的经历给我一个很深的感受:部署方案的选择,很多时候不是“哪个技术更先进”,而是“哪个方案和当前环境的约束更匹配”。Docker 本身没毛病,但在这个网络受限、安全基线严格的环境里,Ollama 原生二进制提供的是一条直接、可控、容易被安全团队接受的路径。如果你也遇到类似的环境限制,不妨先评估一下二进制直装的方案。它少了很多容器化带来的抽象层,但它也让你直面进程、目录、权限和服务管理。把这些基础能力用好,私有 AI 本地部署这件事,反而会变得心里特别有底。