ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

银河麒麟V10 SP1离线部署Milvus:Docker与向量数据库踩坑全指南

银河麒麟V10 SP1离线部署Milvus:Docker与向量数据库踩坑全指南 1. 写在前面这个部署场景到底难在哪前段时间接手了一个典型得不能再典型的信创迁移任务一台刚交付的银河麒麟V10 SP1服务器需要把原本跑在另一套环境里的Milvus向量数据库搬上去给上层的大模型知识库做向量检索。机器在机房没有外网手头的软件物料全靠U盘往里带。乍一听就是“Docker Milvus”网上教程一抓一大把。但真到现场你会发现事情远不止“装个docker、跑个compose”那么简单。首先是麒麟V10 SP1这个系统本身就有很多和Ubuntu、CentOS不太一样的怪脾气比如内核模块、cgroup挂载、iptables后端、安全模块每个都可能在一个你完全想不到的环节把服务干趴。其次是Milvus不是个单容器应用它要etcd存元数据、要MinIO存数据文件三个容器串起来中间任何一个起不来都是白干。最后是离线所有依赖都得提前想清楚少带一个deb包、一个镜像tar整个流程就得停摆。这篇文章把我这次在银河麒麟V10 SP1上完成Milvus离线部署的完整过程和踩坑记录整理出来。如果你是做信创迁移的运维、需要把向量检索能力落到国产化底座上的后端开发或者正在为某个内网环境部署Docker而发愁这篇应该能帮你把最让人头疼的“不确定”变成“确定”。部署思路、物料清单、具体命令、失败排查一次讲全。如果你正卡在类似的环境里盯着黑底的终端不知道下一步该按什么那这篇文章至少能告诉你哪些步骤可以放心大胆做哪些地方要小心翼翼绕开。2. 部署前先别急着动手三件事做扎实2.1 先看清楚跑的是什么芯片和内核这个真的不只是仪式感。银河麒麟V10 SP1有x86_64和aarch64两个大方向下面还可能对应海光、兆芯、鲲鹏、飞腾、龙芯等不同CPU。不同架构直接决定了你要下载哪一套Docker二进制、哪一套镜像tar包。拿错一个当场白跑一趟。上机第一件事就是先把下面这几条命令全部跑一遍输出记下来cat /etc/os-release uname -r uname -m lscpu | grep -E Architecture|Model name cat /proc/cpuinfo | grep -i model name | head -1我在那台机器上看到的信息大致是系统是Kylin V10 SP1内核版本4.19.90系列CPU架构aarch64。看到aarch64之后我立刻就把之前准备的x86_64物料清单划掉了一半换成ARM64版本。内核版本也要记清楚后面选Docker版本、判断overlay2存储驱动能不能用都跟它有关。别嫌这一步烦很多部署问题到最后复盘时发现根源就是最开始没确认清楚架构。2.2 离线物料清单少一个都卡住离线部署最怕的不是操作难而是东西没带全。我一般在出发之前会列一个物料清单逐项打勾。这次用到的完整物料如下序号物料名称用途版本/来源说明1docker-20.10.24.tgzDocker核心二进制官方Linux静态包x86_64/aarch64按架构各备一套2docker-compose可执行文件编排Milvus三个容器可直接下载Linux版本也可放到docker cli-plugins下3Milvus主镜像tar包milvusdb/milvus按官方release的docker-compose.yml配套tag4etcd镜像tar包quay.io/coreos/etcdMilvus元数据存储5MinIO镜像tar包minio/minioMilvus数据对象存储6pymilvus预编译包可选客户端连通性验证按客户端机器Python版本下载wheel7iptables相关deb包备用给Docker的NAT链使用仅当系统缺少iptables命令时用这里我必须多说一句Docker 20.10.x是我在麒麟V10 SP1上用得最稳的版本。不是说新版本不行而是在4.19这种内核上20.10的兼容性最好网络、cgroup、存储驱动这些方面几乎没有意外的坑。新版Docker需要更高的内核特性离线环境一旦出问题你又没法随手更新内核会非常被动。2.3 为什么选择Docker而不是裸机装Milvus在信创环境里有人可能会想既然离线部署这么麻烦直接下载Milvus的二进制包在裸机上跑不行吗技术上说当然可以但我强烈不建议。Milvus的依赖链比较长元数据要etcd数据要对象存储还要处理各种动态库的版本。裸机部署意味着你要手动解决所有依赖而且要自己维护进程守护、日志轮转、开机自启。Docker容器把etcd、MinIO、Milvus各自隔离compose一键编排进程守护和自启交给容器运行时后续升级迁移也方便得多。对运维来说这种方式更可控。更重要的一点是Milvus官方对Docker方式的文档支持最完善社区里出问题时九成答案都是围绕Docker/Compose场景给出的。在信创这类“没有太多前车之鉴”的环境里选择跟官方和社区站同一边本身就是降低风险。3. 银河麒麟V10-SP1上离线装Docker的全过程3.1 解压二进制并部署先把U盘里的docker-20.10.24.tgz拷贝到服务器我习惯放在/opt/install/目录下mkdir -p /opt/install cd /opt/install tar -xzf docker-20.10.24.tgz cp docker/* /usr/bin/这一步非常简单就是把那些二进制直接放到PATH路径下。有一点要提醒如果你对服务器文件布局有洁癖不希望系统/usr/bin目录太乱也可以把二进制放到/opt/docker/bin然后在/etc/profile.d/里加一条PATH导出。但对于信创环境里的服务器我个人建议还是放到/usr/bin理由很简单后面写systemd unit、做安全基线检查时路径越标准越不容易出幺蛾子。放好后执行一次版本检查确认二进制权限可执行docker --version dockerd --version此时Docker命令已经可以用了但dockerd还没有注册成系统服务reboot后不会自启。我们需要手动写一个systemd unit。3.2 配置systemd服务与daemon.json创建/usr/lib/systemd/system/docker.service内容如下。这是Docker官方提供的unit模板我根据麒麟环境做了两点小调整去掉了一些非必要参数确保在SP1上能稳定拉起[Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/kill -s HUP $MAINPID LimitNOFILEinfinity LimitNPROCinfinity LimitCOREinfinity TasksMaxinfinity OOMScoreAdjust-999 TimeoutStartSec0 [Install] WantedBymulti-user.target然后再建/etc/docker/daemon.json这一步很多人会忽略但恰恰是后面少踩坑的关键{ exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2, iptables: true, ip-forward: true, data-root: /var/lib/docker }exec-opts指定cgroup驱动为systemd是为了让Docker与系统管理方式一致避免容器在systemd环境下出现资源统计和回收的混乱。日志驱动和上限是我在信创项目里必配的因为系统盘普遍不大而Milvus跑起来后日志增长速度比想象中快不限制的话几个月就能把磁盘撑满。storage-driver先指定overlay2如果后面启动失败我们再处理。data-root保持默认也可以根据挂载规划改到大容量数据盘。3.3 启动Docker并做基础验证执行以下命令启动systemctl daemon-reload systemctl enable docker systemctl start docker systemctl status docker如果一切正常状态会显示active (running)。再执行docker info重点看两个字段docker info | grep -i storage driver docker info | grep -i cgroup看到Storage Driver: overlay2和Cgroup Driver: systemd说明Docker已经正常接入了系统的cgroup和存储。如果这时候报错先别慌第5章专门整理了SP1环境的排查办法可以先跳到那看一下。为了保险启动完Docker后建议再做一轮更细的检查确认docker.sock权限正常、iptables的NAT表里有Docker创建的链、procfs和sysfs在容器内可正常挂载。这一轮检查不用花多少时间但能为后面Milvus三个容器顺利启动打下底。4. 离线导入Milvus全套镜像并编排启动4.1 在有网机器上拉取并打包镜像在有网络的机器最好和服务器同架构上先创建一个目录然后从Milvus官方GitHub Release页面下载对应版本的docker-compose.yml。为什么强调“官方页面下载”因为里面的镜像tag是和该版本严格配套的比从网上随便搜一篇博客复制出来的配置要可靠得多。我用的是Milvus 2.4.9版本对应配置里的镜像如下milvusdb/milvus:v2.4.9 quay.io/coreos/etcd:v3.5.5 minio/minio:RELEASE.2023-03-20T20-16-18Z在联网机器上逐个拉取docker pull milvusdb/milvus:v2.4.9 docker pull quay.io/coreos/etcd:v3.5.5 docker pull minio/minio:RELEASE.2023-03-20T20-16-18Z然后打tar包。我习惯用gzip压缩体积能小不少拷U盘时省时间docker save milvusdb/milvus:v2.4.9 | gzip milvus.tar.gz docker save quay.io/coreos/etcd:v3.5.5 | gzip etcd.tar.gz docker save minio/minio:RELEASE.2023-03-20T20-16-18Z | gzip minio.tar.gz这里有一个非常实用的建议分别打多个tar包不要三个镜像合并成一个。别看合并后文件数量少了但load失败时排查麻烦而且其中一个镜像损坏会导致你全部重新传输。分开打包哪个有问题就单独补哪个。4.2 编写Standalone版docker-compose.yml到目标服务器上创建/opt/milvus目录把刚才得到的docker-compose.yml放进去。这个文件里的核心内容我摘出来说明一下。etcd服务etcd: container_name: milvus-etcd image: quay.io/coreos/etcd:v3.5.5 environment: - ETCD_AUTO_COMPACTION_MODErevision - ETCD_AUTO_COMPACTION_RETENTION1000 - ETCD_QUOTA_BACKEND_BYTES4294967296 - ETCD_SNAPSHOT_COUNT50000 volumes: - /opt/milvus/volumes/etcd:/etcd command: etcd -advertise-client-urlshttp://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcdMinIO服务minio: container_name: milvus-minio image: minio/minio:RELEASE.2023-03-20T20-16-18Z environment: MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin ports: - 9001:9001 - 9000:9000 volumes: - /opt/milvus/volumes/minio:/minio_data command: minio server /minio_data --console-address :9001 healthcheck: test: [CMD, curl, -f, http://localhost:9000/minio/health/live] interval: 30s timeout: 20s retries: 3Milvus主服务standalone: container_name: milvus-standalone image: milvusdb/milvus:v2.4.9 command: [milvus, run, standalone] security_opt: - seccomp:unconfined environment: ETCD_ENDPOINTS: etcd:2379 MINIO_ADDRESS: minio:9000 volumes: - /opt/milvus/volumes/milvus:/var/lib/milvus ports: - 19530:19530 - 9091:9091 depends_on: - etcd - minio注意security_opt里的seccomp:unconfined这是我加上去的。因为部分信创内核的seccomp策略比较严格Milvus容器在创建某些线程或执行madvise相关系统调用时可能会被拦截导致启动失败。加了这个选项可以避开这类问题。另外如果你后期打算用外部已有MinIO或者对象存储也简单把这几个环境变量的地址换成外部地址即可。不过外部存储方式建议以官方文档为准这里先不展开。4.3 上传、导入镜像并启动服务启动前先确认数据目录存在。虽然Compose对bind mount有自动创建的兜底但为了避免目录属主异常我习惯先手动建好mkdir -p /opt/milvus/volumes/etcd mkdir -p /opt/milvus/volumes/minio mkdir -p /opt/milvus/volumes/milvus将三个tar.gz通过U盘或scp传到服务器/opt/milvus目录下然后依次loadcd /opt/milvus docker load -i milvus.tar.gz docker load -i etcd.tar.gz docker load -i minio.tar.gzload完成后用docker images确认三个镜像的tag都和compose文件里一致。这一步最容易被忽略的坑是有些人拉镜像时又顺便打了一个latest的tag以为无所谓结果compose里写的是具体版本号启动时它就会尝试去拉取这个tag。离线环境下connection refused卡在那边半天不知道怎么回事。所以我的习惯是load完立刻做一次镜像清单和compose文件里image字段的逐行对比眼过一遍或者用脚本比对都行。确认无误后在compose文件所在目录启动docker-compose up -d如果你用的Docker版本比较新命令行把docker-compose换成docker compose中间有空格也行。启动后观察状态docker ps正常情况下应该有三个容器都是Up状态。如果某个容器反复重启用一条命令看日志docker logs 容器名 --tail 1004.4 Milvus启动后的连通性验证服务起来不代表真能连上上次在一台环境上docker ps看三个容器全是活着的结果创建collection时直接报etcd连接超时。所以我现在习惯容器起来后一定要从客户端角度实际验证一遍。只要客户端机器能访问19530端口就用pymilvus做一次连接和建collection测试。如果是纯离线客户端提前下载好对应版本的pymilvus wheel带过去用pip install本地文件即可不用依赖pip源。在有pymilvus的客户端机器上执行pip install pymilvus2.4.9然后运行下面的Python脚本from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType connections.connect(host127.0.0.1, port19530) print(connect ok) fields [ FieldSchema(nameid, dtypeDataType.INT64, is_primaryTrue), FieldSchema(nameembedding, dtypeDataType.FLOAT_VECTOR, dim8) ] schema CollectionSchema(fieldsfields) col Collection(nametest_collection, schemaschema) print(create collection ok)如果能看到connect ok和create collection okMilvus就真正常工作了。这个验证很值得做因为光看容器Up端口能通不代表元数据和对象存储链路都正常。我之前遇到过一次MinIO配置错误导致collection创建后马上报错就是靠这个脚本提前暴露问题的。5. SP1专属避坑指南建议直接收藏5.1 overlay2用不了怎么办麒麟V10 SP1上一类很典型的报错是启动dockerd时存储驱动初始化失败日志里出现类似于failed to mount overlay: operation not permitted或error creating overlay mount to ...的信息。原因多半是内核的overlay模块没有被加载。先用这条命令确认cat /proc/filesystems | grep overlay如果没有输出说明内核里overlay支持没启用需要手动加载模块modprobe overlay lsmod | grep overlay加载成功后再启动Docker。如果modprobe也报错报No such device或Operation not permitted那么大概率是内核配置层面把overlay关了。这种事你在CentOS上几乎遇不到但在信创系统里是真实存在的。实在不行的话退一步把daemon.json里的storage-driver改成vfsDocker也能用但性能会下降几十倍只建议临时验证用。改完记得重启Docker然后用下面的命令确认docker info | grep Storage Driver5.2 cgroup挂载问题手动挂载并不丢人我在另一台飞腾的机器上曾经遇到dockerd直接起不来报错内容里有Devices cgroup isnt mounted或者failed to mount cgroup。原因是系统里cgroup v1的devices子系统没有被正确挂载。排查命令mount | grep cgroup ls /sys/fs/cgroup/如果看到/sys/fs/cgroup下没有devices目录手动补上mkdir -p /sys/fs/cgroup/devices mount -t cgroup -o devices none /sys/fs/cgroup/devices然后重新启动Docker。想让这个挂载在重启后依然生效需要把它写进/etc/fstabnone /sys/fs/cgroup/devices cgroup devices 0 0需要说明的是麒麟V10 SP1默认一般走cgroup v1手动挂载前先确认系统当前使用的是v1还是v2。改fstab前更要谨慎建议先备份原文件避免重启后系统异常。5.3 网络相关的三连坑iptables、防火墙和端口Docker创建网络时要往iptables的NAT表里写规则。麒麟V10 SP1上最常遇到的问题是iptables命令本身存在但后端是nftablesDocker写入规则时报错比如iptables: No chain/target/match by that name。可以先查询iptables -t nat -L -n | head如果报错试试切换到legacy模式update-alternatives --config iptables选带legacy的那个选项然后重启Docker。如果连iptables命令都没有那就得把提前准备的iptables deb包装上。防火墙也很关键。Milvus默认端口是19530资源监控端口9091MinIO控制台9001。启动前先确认firewalld状态systemctl status firewalld如果开着放行对应端口firewall-cmd --permanent --add-port19530/tcp firewall-cmd --permanent --add-port9091/tcp firewall-cmd --reload最后别忘了看下有没有其他服务占用了这些端口。用ss查一下ss -lntp | grep -E 19530|9091|9000|9001|2379端口冲突在信创环境里比较常见我有一次就被一个内部监控Agent占着9000端口和MinIO冲突排查了很久才发现。5.4 aarch64架构的“镜像错位”问题arm64机器上去执行一个x86_64的镜像会报exec format error。这句话很多人在x86环境里根本没见过因为镜像架构和平台不对时通常是直接失败。在离线环境里如果碰巧有人给了你一套x86的tar包load成功但运行报exec format就是这个问题。排查很直接docker image inspect 镜像名:tag --format {{.Architecture}}如果架构不是amd64/arm64的对应值说明镜像拿错了。分别检查三个镜像的架构一个都不能漏。等你在现场卡了半小时才会明白为什么我在第2章反复强调先确认uname -m。5.5 磁盘空间与时间同步两个容易忽略的隐性问题Milvus启动后向量数据和MinIO文件都会落到本地磁盘。如果/opt或/var/lib/docker所在分区空间不够容器启动到一半就会失败日志里通常只有一段玄学的I/O错误。动手前先看看磁盘余量df -h至少留出向量数据规模的2到3倍余量。我之前遇到过一次数据盘只给50G的尴尬情况vector索引跑到一半就满了扩容比部署麻烦得多。时间同步是另一个容易被忽略的点。信创环境如果服务器长时间离线系统时间可能会偏差很大。容器间通信、etcd的选举和租约都对时间敏感时间错乱会导致etcd集群不停选主或Milvus节点反复重连。部署前顺手把时间校正一下date # 如果偏差大用ntpdate或者chronyc手动调整离线环境下不一定有可用的NTP服务器但至少要保证时区设置和生产环境一致别让时区原因造成后续排障时日志时间对不上。6. 常见问题速查表与最后的实操体会我把这次以及以往项目中跟SP1环境相关的典型问题整理成一个速查表方便你到现场直接对照现象排查方向处理办法dockerd起不来报cgroup问题查看/sys/fs/cgroup下是否有devices手动挂载cgroup devices写入fstabdockerd起不来报overlay问题cat /proc/filesystems查overlaymodprobe overlay实在不行降级为vfs存储驱动docker ps正常但容器启动失败docker logs看具体日志按日志关键字处理重点看etcd/minio连接容器报exec format errordocker image inspect查看架构换对应架构的镜像外部连不上19530检查防火墙、端口监听firewall-cmd放行端口或确认端口没被占用iptables报No chain/target/match确认iptables后端是否为nftablesupdate-alternatives切到legacy模式Milvus容器起来但创建collection报错检查etcd和MinIO是否健康docker ps看状态docker logs跟进日志增长过快磁盘被写满检查daemon.json日志配置开启json-file日志轮转设置max-size/max-file最后再分享一个我个人的习惯在信创环境做这种离线部署每操作完一个阶段我都会把当时的命令输出截图或者保存成文本统一存放在一个部署记录目录里。因为信创项目的验收和审计经常要求追溯过程这些原始输出比任何口头汇报都有说服力。我在这次银河麒麟V10 SP1的部署接近尾声时也是靠这些记录快速和同事对齐了环境信息。Milvus在这台机器上稳定跑了几天之后我又接到下一个任务给同一套环境里的应用做升级。经历过这次离线Docker部署后面的事反而顺了因为最不确定的部分已经摸透。信创迁移本来就是一件件把“不确定”变成“确定”的过程希望这篇SP1专属避坑指南能让你少走一段弯路。
返回列表