Qdrant 是面向自行部署 AI 系统的开源向量数据库,可用于语义搜索与 RAG 检索。Rocky Linux 10 和 AlmaLinux 10 基于 RHEL 10,适合希望保持系统稳定并启用 SELinux enforcing 的团队。本文提供两条安装路径:使用上游镜像的 Docker CE,以及无守护进程、适合 RHEL 生态的 rootless Podman。
原文全部命令在新克隆的 Rocky Linux 10.1 云镜像上测试,SELinux 始终为 enforcing。AlmaLinux 10 共享 RHEL 10 软件包生态,可采用相同步骤。文章重点说明两个实际问题:云镜像内核与 Docker 所需模块不匹配,以及 rootless Podman 绑定挂载同时需要处理用户命名空间所有权和 SELinux 标签。配套代码位于 c4geeks/qdrant 的 install-rocky 目录;参数含义以 Qdrant 官方文档为准。
开始前的准备
- Rocky Linux 10 或 AlmaLinux 10,至少 2 GB 内存,并为存储卷预留数 GB 磁盘。
- 具有
sudo权限的普通用户。云镜像中的rocky用户通常已加入wheel组。 - 可以访问 Qdrant 发行版、Docker CE 软件源和发行版镜像站。
- 空闲 TCP 端口 6333(REST、Web UI)与 6334(gRPC)。
- 保持 SELinux enforcing,后续步骤不会要求关闭它。
更新软件包索引并安装辅助工具:
sudo dnf -y install dnf-plugins-core curl jq
方法一:使用 Docker CE
Docker CE 可直接运行上游 Qdrant 镜像。原文测试时 Docker 已提供 RHEL 10 支持,Rocky 和 Alma 可使用对应软件源。
第一步:添加软件源并安装
添加官方 RHEL 软件源,安装引擎与 Compose 插件:
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf -y install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
docker --version
原文环境安装了 Docker 29.x 和 kernel-modules-extra-matched-* 软件包。记下模块包版本,下一步需要与内核对应:

第二步:启动 Docker 前处理内核不匹配
部分 Rocky 10、Alma 10 云镜像中的运行内核,早于 Docker 安装的匹配模块所需版本。立即启动守护进程时,可能出现:
sudo dockerd 2>&1 | tail -3
# Error initializing network controller: failed to register "bridge" driver:
# iptables --wait -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER:
# Warning: Extension addrtype revision 0 not supported, missing kernel module?
安装与模块匹配的新内核,然后重启:
uname -r
# 6.12.0-124.8.1.el10_1.x86_64 (old kernel still running)
rpm -qa | grep kernel-modules-extra
# kernel-modules-extra-matched-6.12.0-124.56.1.el10_1.x86_64 (newer modules)
sudo dnf -y install kernel kernel-core kernel-modules kernel-modules-core
sudo shutdown -r now
重启后确认运行内核已经更新,再启动 Docker:
uname -r
# 6.12.0-124.56.1.el10_1.x86_64
sudo systemctl enable --now docker
sudo docker run --rm hello-world
错误与恢复过程如下:

如果忽略此项,容易在 Docker 日志上花费大量排查时间;早期教程未必涉及较新的匹配模块软件包。
第三步:使用正确的 SELinux 挂载标签
读取最新 Qdrant 标签,创建存储目录并启动容器。卷参数末尾的 :z 表示重新标记宿主机目录,使容器在 enforcing 模式下能够访问它:
export QDRANT_VERSION=$(curl -s https://api.github.com/repos/qdrant/qdrant/releases/latest | jq -r .tag_name)
echo $QDRANT_VERSION # v1.18.1 at the time of writing
sudo mkdir -p /var/lib/qdrant/storage
sudo docker run -d \
--name qdrant \
--restart unless-stopped \
-p 6333:6333 -p 6334:6334 \
-v /var/lib/qdrant/storage:/qdrant/storage:z \
qdrant/qdrant:${QDRANT_VERSION} # https://github.com/qdrant/qdrant/releases
验证容器、健康检查和目录的 SELinux 上下文:
getenforce # Enforcing
curl -sf http://localhost:6333/healthz # healthz check passed
ls -lZ /var/lib/qdrant/storage # system_u:object_r:var_lib_t:s0
完整过程如下:

需要注意,原文测试中的 Docker CE 容器进程使用 spc_t(超级特权容器)SELinux 类型,对绑定挂载的限制较少。该环境中,容器写入文件在重新标记后显示为 var_lib_t,进程本身也未因 SELinux 被阻止访问多数路径。这是该测试环境的观察,不能据此假定 Docker 提供了与下文 Podman 相同的隔离。
方法二:Rootless Podman
Podman 来自 Rocky 与 Alma 基础软件源,不依赖常驻守护进程。rootless 模式以普通用户运行容器,并使用 container_t 类型施加 SELinux 限制,因而会暴露一些 Docker 环境未阻止的绑定挂载错误。Podman 与 Buildah 的基础概念可结合本机发行版文档学习。
第一步:安装 Podman
直接使用 dnf 安装。原文编写时基础软件源提供 Podman 5.6.0:
sudo dnf -y install podman
podman --version
# podman version 5.6.0
第二步:观察首次 rootless 启动的权限错误
Podman 要求明确的完整镜像名称,因此使用 docker.io/qdrant/qdrant:<tag>。先以普通绑定挂载启动,观察错误:
mkdir -p /tmp/qdrant-podman-test
podman run -d --name qdrant-podman \
-p 7333:6333 \
-v /tmp/qdrant-podman-test:/qdrant/storage \
docker.io/qdrant/qdrant:v1.18.1
podman ps -a --filter name=qdrant
# qdrant-podman Exited (1) 4 seconds ago
podman logs qdrant-podman | tail -1
# Error: Service internal error: Failed to write file:
# Permission denied (os error 13) at path "/qdrant/./storage/..."
容器内 Qdrant 进程的非 root UID,与宿主机目录所有者并不相同。rootless Podman 通过 subordinate UID 范围映射用户,因此容器内 UID 1000 不等同于宿主机 UID 1000,进程会因访问被拒绝而退出:

第三步:使用 :z,U 修复挂载
:z 处理 SELinux 标签,:U 将目录所有权调整为容器用户命名空间映射后的 UID。示例将两者结合使用;其中 :U 会实际改变宿主机目录所有权,应只对专用数据目录使用:
podman rm -f qdrant-podman
rm -rf /tmp/qdrant-podman-test
mkdir -p /tmp/qdrant-podman-test
podman run -d --name qdrant-podman \
-p 7333:6333 \
-v /tmp/qdrant-podman-test:/qdrant/storage:z,U \
docker.io/qdrant/qdrant:v1.18.1
curl -sf http://localhost:7333/healthz
# healthz check passed
ls -lZ /tmp/qdrant-podman-test
# system_u:object_r:container_file_t:s0 (correct SELinux label)
# rocky rocky (correct UID after :U chown)
修复前后对比如下:

长期运行时,可在 ~/.config/containers/systemd/qdrant.container 创建 Quadlet 单元,由用户级 systemd 负责重启与日志。原文配套仓库提供了对应模板。
配置防火墙并恢复 Docker 网络规则
原文 Rocky 10 云镜像默认没有 firewalld。若安全策略要求,安装并配置它。默认 public 区域适合公网 VPS 或堡垒机这类环境:
sudo dnf -y install firewalld
sudo systemctl enable --now firewalld
firewall-cmd --get-default-zone # public
sudo firewall-cmd --permanent --add-port=6333/tcp
sudo firewall-cmd --permanent --add-port=6334/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports
原文环境在执行 firewall-cmd --reload 后,Docker 创建的 nftables 规则被清除,导致容器不可达。重新启动 Docker,让其重建网络规则:
sudo systemctl restart docker
curl -sf http://localhost:6333/healthz
完整配置过程如下:

只允许可信子网时,通过 --source 限定来源:
sudo firewall-cmd --permanent --remove-port=6333/tcp
sudo firewall-cmd --permanent --add-rich-rule=\
'rule family="ipv4" source address="10.0.0.0/8" port port="6333" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo systemctl restart docker
端到端验证:创建集合并搜索
创建 demo 集合,写入三个带载荷的数据点,再执行相似度查询:
curl -s -X PUT http://localhost:6333/collections/demo \
-H "Content-Type: application/json" \
-d '{"vectors":{"size":4,"distance":"Cosine"}}' | jq .
curl -s -X PUT http://localhost:6333/collections/demo/points \
-H "Content-Type: application/json" \
-d '{
"points": [
{"id":1, "vector":[0.1,0.2,0.3,0.4], "payload":{"city":"Nairobi"}},
{"id":2, "vector":[0.2,0.3,0.4,0.5], "payload":{"city":"Berlin"}},
{"id":3, "vector":[0.9,0.8,0.7,0.6], "payload":{"city":"Tokyo"}}
]
}' | jq .
curl -s -X POST http://localhost:6333/collections/demo/points/search \
-H "Content-Type: application/json" \
-d '{"vector":[0.15,0.25,0.35,0.45],"limit":3,"with_payload":true}' \
| jq .
Berlin 与 Nairobi 的向量接近查询,应排在前面;Tokyo 方向相反,排名靠后。得到相同顺序,说明数据写入、索引和查询均已工作:

打开 Web UI
在浏览器中访问服务器 6333 端口的 /dashboard。Collections 面板应列出刚创建的 demo:

升级 Qdrant
更换镜像标签并重建容器即可升级。存储卷保留,因此集合和快照不会因删除容器而丢失:
export QDRANT_VERSION=$(curl -s https://api.github.com/repos/qdrant/qdrant/releases/latest | jq -r .tag_name)
sudo docker pull qdrant/qdrant:${QDRANT_VERSION} # https://github.com/qdrant/qdrant/releases
sudo docker stop qdrant && sudo docker rm qdrant
sudo docker run -d --name qdrant --restart unless-stopped \
-p 6333:6333 -p 6334:6334 \
-v /var/lib/qdrant/storage:/qdrant/storage:z \
qdrant/qdrant:${QDRANT_VERSION}
rootless Podman 使用 podman pull 后重建容器,并继续保留相同的 :z,U 挂载参数。
故障排查
addrtype revision 0 not supported
这是前述内核与模块不匹配问题。安装 kernel kernel-core kernel-modules kernel-modules-core,重启后再启动 Docker。
short-name resolution enforced but cannot prompt without a TTY
Podman 需要完整镜像名称。将 qdrant/qdrant:tag 改为 docker.io/qdrant/qdrant:tag。
本机可访问,其他主机无法访问
先用 firewall-cmd --list-ports 检查防火墙。若刚执行过 firewall-cmd --reload,再重启 Docker,使其重新写入桥接网络所需的 nftables 规则。










