本地搭建AI及实验平台
一条命令输出,硬件配置
echo "===== CPU ====="; lscpu | grep -E 'Model name|CPU\(s\)'; echo -e "\n===== 内存 ====="; free -h; echo -e "\n===== AMD显卡 ====="; lspci | grep -E "VGA|3D"; echo -e "\n===== 显卡完整信息 ====="; sudo lshw -C display; echo -e "\n===== 磁盘 ====="; df -h
===== CPU =====
CPU(s) scaling MHz: 49%
===== 内存 =====
total used free shared buff/cache available
内存: 15Gi 690Mi 14Gi 1.5Mi 560Mi 14Gi
交换: 4.0Gi 0B 4.0Gi
===== AMD显卡 =====
01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Polaris 20 XL [Radeon RX 580 2048SP] (rev e7)
===== 显卡完整信息 =====
*-display
description: VGA compatible controller
product: Polaris 20 XL [Radeon RX 580 2048SP]
vendor: Advanced Micro Devices, Inc. [AMD/ATI]
physical id: 0
bus info: pci@0000:01:00.0
version: e7
width: 64 bits
clock: 33MHz
capabilities: pm pciexpress msi vga_controller bus_master cap_list rom
configuration: driver=amdgpu latency=0
resources: irq:31 memory:e0000000-efffffff memory:f0000000-f01fffff ioport:e000(size=256) memory:f7e00000-f7e3ffff memory:c0000-dffff
===== 磁盘 =====
文件系统 大小 已用 可用 已用% 挂载点
tmpfs 1.6G 1.5M 1.6G 1% /run
/dev/sda2 116G 12G 99G 11% /
tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs 5.0M 12K 5.0M 1% /run/lock
efivarfs 128K 38K 86K 31% /sys/firmware/efi/efivars
/dev/sda1 1.1G 6.2M 1.1G 1% /boot/efi
tmpfs 1.6G 80K 1.6G 1% /run/user/1000
shitou@shitou-To-be-filled-by-O-E-M:~$
llama.cpp(不使用 Ollama)
RX580‑2048SP 不能用 ROCm,只能 Vulkan 后端,llama.cpp 是底层原生推理引擎,可控性更高,没有 ollama 那一层封装,可以直接跑 GGUF 千问模型。
第一步安装依赖
sudo apt install -y build-essential cmake git libvulkan-dev vulkan-tools mesa-vulkan-drivers glslang-tools spirv-headers
识别显卡
shitou@shitou-To-be-filled-by-O-E-M:~$ vulkaninfo --summary
WARNING: [../src/amd/vulkan/radv_physical_device.c:2153] Code 0 : Could not open device /dev/dri/renderD128: Permission denied (VK_ERROR_INCOMPATIBLE_DRIVER)
==========
VULKANINFO
==========
Vulkan Instance Version: 1.3.275
Instance Extensions: count = 24
-------------------------------
VK_EXT_acquire_drm_display : extension revision 1
VK_EXT_acquire_xlib_display : extension revision 1
VK_EXT_debug_report : extension revision 10
VK_EXT_debug_utils : extension revision 2
VK_EXT_direct_mode_display : extension revision 1
VK_EXT_display_surface_counter : extension revision 1
VK_EXT_headless_surface : extension revision 1
VK_EXT_surface_maintenance1 : extension revision 1
VK_EXT_swapchain_colorspace : extension revision 5
VK_KHR_device_group_creation : extension revision 1
VK_KHR_display : extension revision 23
VK_KHR_external_fence_capabilities : extension revision 1
VK_KHR_external_memory_capabilities : extension revision 1
VK_KHR_external_semaphore_capabilities : extension revision 1
VK_KHR_get_display_properties2 : extension revision 1
VK_KHR_get_physical_device_properties2 : extension revision 2
VK_KHR_get_surface_capabilities2 : extension revision 1
VK_KHR_portability_enumeration : extension revision 1
VK_KHR_surface : extension revision 25
VK_KHR_surface_protected_capabilities : extension revision 1
VK_KHR_wayland_surface : extension revision 6
VK_KHR_xcb_surface : extension revision 6
VK_KHR_xlib_surface : extension revision 6
VK_LUNARG_direct_driver_loading : extension revision 1
Instance Layers: count = 3
--------------------------
VK_LAYER_INTEL_nullhw INTEL NULL HW 1.1.73 version 1
VK_LAYER_MESA_device_select Linux device selection layer 1.4.303 version 1
VK_LAYER_MESA_overlay Mesa Overlay layer 1.4.303 version 1
Devices:
========
GPU0:
apiVersion = 1.4.318
driverVersion = 25.2.8
vendorID = 0x10005
deviceID = 0x0000
deviceType = PHYSICAL_DEVICE_TYPE_CPU
deviceName = llvmpipe (LLVM 20.1.2, 256 bits)
driverID = DRIVER_ID_MESA_LLVMPIPE
driverName = llvmpipe
driverInfo = Mesa 25.2.8-0ubuntu0.24.04.2 (LLVM 20.1.2)
conformanceVersion = 1.3.1.1
deviceUUID = 6d657361-3235-2e32-2e38-2d3075627500
driverUUID = 6c6c766d-7069-7065-5555-494400000000
========================================================================================================================================================================================
系统版本:Ubuntu 24.04.4 LTS
内存:16G 大内存(满足多套云组件、虚拟机、AI 推理运行)
磁盘规划:
系统盘 sda:119G,已用12%,剩余空间充足,用于存放系统、实验环境、镜像文件
显卡:AMD Radeon RX580 2048SP(amdgpu 驱动正常适配)
数据盘 sdb:465G 闲置裸盘,可直通虚拟机、单独做虚拟机数据盘,不占用系统盘空间
ip 确定
### 想切回全部 DHCP 自动获取(回滚)
重新编辑 `01-network-manager-all.yaml`:
```
network:
ethernets:
enp3s0:
dhcp4: yes
dhcp6: yes
version: 2
renderer: NetworkManager
```
设置为静态,
network:
ethernets:
enp3s0:
dhcp4: no
addresses:
- 192.168.31.29/24
routes:
- to: default
via: 192.168.31.1
nameservers:
addresses:
- 223.5.5.5
- 114.114.114.114
dhcp6: yes
version: 2
renderer: NetworkManager
shitou@shitou-To-be-filled-by-O-E-M:~$
,
搭建前准备
1 .先确认,是否支持虚拟化
by-O-E-M:~$
egrep -c '(vmx|svm)' /proc/cpuinfo
16
echo "=== 内存 ===" && free -h && echo "=== 显存(VRAM) ===" && cat /sys/clas s/drm/card*/device/mem_info_vram_total 2>/dev/null | awk '{printf "总量: %.1f GB\n", $1/1024/1024/10 24}' && cat /sys/class/drm/card*/device/mem_info_vram_used 2>/dev/null | awk '{printf "已用: %.0f MB \n", $1/1024/1024}' && echo "=== 显卡型号 ===" && lspci | grep -i -E "vga|3d|display" && echo "=== C PU ===" && lscpu | grep -E "Model name|Socket|Core|Thread"
16个核心已经支持,///
# 1. 停止OpenNebula全套服务
sudo systemctl stop opennebula opennebula-fireedge opennebula-gate opennebula-flow
# 2. 禁用OpenNebula开机自启
sudo systemctl disable opennebula opennebula-fireedge opennebula-gate opennebula-flow
# 3. 停止libvirt相关socket(关键,socket激活会自动拉起libvirtd)
sudo systemctl stop libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket
# 4. 停止libvirt主服务 + virtlogd/virtlockd
sudo systemctl stop libvirtd virtlogd virtlockd virtlogd.socket virtlockd.socket
# 5. 禁用libvirt全套socket
sudo systemctl disable libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket
# 6. 禁用libvirtd主服务
sudo systemctl disable libvirtd
# 7. 禁用virtlogd virtlockd
sudo systemctl disable virtlogd virtlockd virtlogd.socket virtlockd.socket
# 8. 停止并禁用Cockpit网页管理面板
sudo systemctl stop cockpit.socket
sudo systemctl disable cockpit.socket
# 9. 重置opennebula failed状态标记(消除红色failed提示)
sudo systemctl reset-failed opennebula
# 10. systemd重载配置,刷新单元状态
sudo systemctl daemon-reload
# ===================== 校验命令(执行完上面全部后跑) =====================
# 校验自启状态:全部输出 disabled 才算成功
systemctl is-enabled opennebula opennebula-fireedge opennebula-gate opennebula-flow libvirtd libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket cockpit.socket virtlogd virtlockd virtlogd.socket virtlockd.socket
# 校验运行状态:全部 inactive (dead)
systemctl status opennebula opennebula-fireedge opennebula-gate opennebula-flow libvirtd libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket cockpit.socket virtlogd virtlockd virtlogd.socket virtlockd.socket
重启之后,查看内存是否被其他程序占用
shitou@shitou:~$ systemctl is-enabled opennebula opennebula-fireedge opennebula-gate opennebula-flow libvirtd libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket cockpit.socket virtlogd virtlockd virtlogd.socket virtlockd.socket
disabled
disabled
disabled
disabled
disabled
disabled
disabled
disabled
disabled
disabled
disabled
disabled
disabled
shitou@shitou:~$ systemctl status opennebula opennebula-fireedge opennebula-gate opennebula-flow libvirtd libvirtd.socket libvirtd-ro.socket libvirtd-admin.socket cockpit.socket virtlogd virtlockd virtlogd.socket virtlockd.socket
○ opennebula.service - OpenNebula Cloud Controller Daemon
Loaded: loaded (/usr/lib/systemd/system/opennebula.service; disabled; pres>
Active: inactive (dead)
○ opennebula-fireedge.service - OpenNebula FireEdge Server
Loaded: loaded (/usr/lib/systemd/system/opennebula-fireedge.service; disab>
Active: inactive (dead)
○ opennebula-gate.service - OpenNebula Gate Service
Loaded: loaded (/usr/lib/systemd/system/opennebula-gate.service; disabled;>
Active: inactive (dead)
○ opennebula-flow.service - OpenNebula Flow Service
Loaded: loaded (/usr/lib/systemd/system/opennebula-flow.service; disabled;>
Active: inactive (dead)
○ libvirtd.service - libvirt legacy monolithic daemon
Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; disabled; preset>
Active: inactive (dead)
TriggeredBy: ○ libvirtd.socket
○ libvirtd-admin.socket
○ libvirtd-ro.socket
Docs: man:libvirtd(8)
shitou@shitou:~$ ps aux | grep -E 'libvirt|one-'
shitou 1710 0.0 0.0 9316 2400 pts/0 S+ 07:37 0:00 grep --color=auto -E libvirt|one-
shitou@shitou:~$ free -h
total used free shared buff/cache available
内存: 15Gi 644Mi 14Gi 1.8Mi 394Mi 14Gi
交换: 4.0Gi 0B 4.0Gi
shitou@shitou:~$
inux 的硬件设备是有权限管控的。/dev/dri/renderD128 是 RX580 的 Vulkan 渲染节点,默认普通用户不能直接访问。 账号加入 render 和 video 用户组,就是给 shitou 这个账号开通访问显卡硬件加速的权限,让 Vulkan、llama.cpp、Ollama 能用 RX580 做推理,而不是只能用 CPU 软跑。
之前执行 vulkaninfo --summary 有这条警告:
WARNING: Could not open device /dev/dri/renderD128: Permission denied
含义: 程序尝试打开显卡硬件渲染设备,权限不足,打不开。 于是 Vulkan 自动降级,启用 llvmpipe,也就是 CPU 软渲染。 👉 后果:RX580 显卡完全闲置,所有计算交给 CPU,跑大模型极慢,显卡显存完全用不上。
两个用户组各自作用
video 组:访问基础显卡设备
/dev/dri/card0,读取显卡信息。render 组:访问
/dev/dri/renderD128,Vulkan 硬件加速专用节点,跑 AI 推理核心就靠这个。
root 用户天生拥有全部权限,不需要加组;但我们平时不用 root 跑 AI 程序,所以要给普通账号授权。
为什么必须断开 SSH 重登,不是加完立刻生效?
Linux 用户组信息,是在登录会话创建的时候一次性加载。 你现在这个 SSH 窗口,登录的时候还没有 render、video 权限。哪怕后面执行命令把账号加入组,已经打开的会话不会自动刷新权限。
新 SSH 会话:登录时读取用户组 → 拥有 render/video 权限 → vulkan 可以正常调用 RX580
当前旧 SSH 会话:还是旧权限 → 依旧报权限拒绝
简单类比
就像门禁卡: 你提交资料办门禁(执行 usermod 加入组),资料审批好了,但是你手上这张旧卡还没重新刷卡刷新。 必须退出大楼(断开 SSH),重新刷卡进门(重连 SSH),门禁卡才拥有新权限。
重登之后要验证的目标
vulkaninfo --summarymkdir ~/my-llm && cd ~/my-llm
wget https://ghfast.top/https://github.com/ggml-org/llama.cpp/releases/downl oad/b10068/llama-b10068-bin-ubuntu-vulkan-x64.tar.gz
--2026-09-16 09:47:35-- https://ghfast.top/https://github.com/ggml-org/llama.cpp/releases/download/ b10068/llama-b10068-bin-ubuntu-vulkan-x64.tar.gz
正在解析主机 ghfast.top (ghfast.top)... 23.95.31.220
正在连接 ghfast.top (ghfast.top)|23.95.31.220|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 32028597 (31M) [application/octet-stream]
正在保存至: ‘llama-b10068-bin-ubuntu-vulkan-x64.tar.gz’
llama-b10068-bin-ubuntu-v 49%[=================> ] 15.22M --.-KB/s 用时 42m 40s
2026-09-16 10:30:18 (6.09 KB/s) - 在 15957142/32028597 字节处发生读取错误 (连接超时)。 重试中。
--2026-09-16 10:30:19-- (尝试次数: 2) https://ghfast.top/https://github.com/ggml-org/llama.cpp/relea ses/download/b10068/llama-b10068-bin-ubuntu-vulkan-x64.tar.gz
正在连接 ghfast.top (ghfast.top)|23.95.31.220|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 206 PARTIAL CONTENT
长度: 32028597 (31M),剩余 16071455 (15M) [application/octet-stream]
正在保存至: ‘llama-b10068-bin-ubuntu-vulkan-x64.tar.gz’
llama-b10068-bin-ubuntu- 85%[+++++++++++++++++===========> ] 26.00M 14.0KB/s 用时 16m 47s
2026-09-16 10:47:08 (11.0 KB/s) - 在 27261168 字节处连接关闭。 重试中。
--2026-09-16 10:47:10-- (尝试次数: 3) https://ghfast.top/https://github.com/ggml-org/llama.cpp/re leases/download/b10068/llama-b10068-bin-ubuntu-vulkan-x64.tar.gz
正在连接 ghfast.top (ghfast.top)|23.95.31.220|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 206 PARTIAL CONTENT
长度: 32028597 (31M),剩余 4767429 (4.5M) [application/octet-stream]
正在保存至: ‘llama-b10068-bin-ubuntu-vulkan-x64.tar.gz’
llama-b10068-bin-ubuntu- 96%[+++++++++++++++++++++++++++++===> ] 29.34M 219KB/s 用时 95s
2026-09-16 10:48:48 (35.9 KB/s) - 在 30766411 字节处连接关闭。 重试中。
--2026-09-16 10:48:51-- (尝试次数: 4) https://ghfast.top/https://github.com/ggml-org/llama.cpp/re leases/download/b10068/llama-b10068-bin-ubuntu-vulkan-x64.tar.gz
正在连接 ghfast.top (ghfast.top)|23.95.31.220|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 206 PARTIAL CONTENT
长度: 32028597 (31M),剩余 1262186 (1.2M) [application/octet-stream]
正在保存至: ‘llama-b10068-bin-ubuntu-vulkan-x64.tar.gz’
llama-b10068-bin-ubuntu- 100%[+++++++++++++++++++++++++++++++++=>] 30.54M 134KB/s 用时 9.2s
2026-09-16 10:49:07 (134 KB/s) - 已保存 ‘llama-b10068-bin-ubuntu-vulkan-x64.tar.gz’ [32028597/320285 97])
、、
临时关停 OpenNebula + libvirt/KVM 相关后台服务,释放内存;**保留配置,随时一键启动切回虚拟化环境**
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法