恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Docker部署Milvus完整复盘:standalone_embed.sh脚本与etcd/MinIO组件详解
首页
资讯中心
/
Docker部署Milvus完整复盘:standalone_embed.sh脚本与etcd/MinIO组件详解
Docker部署Milvus完整复盘:standalone_embed.sh脚本与etcd/MinIO组件详解
发布时间:2026/10/11 11:32:42
最近在搞向量检索最后选了Milvus部署方式用的是官方提供的standalone_embed.sh脚本。这个脚本最省心的地方是它会用 Docker 把 etcd 和 MinIO 一起自动拉起来不用手动去编排这三个依赖组件。这篇就把整个 Docker 部署 Milvus 的过程复盘一遍脚本到底做了什么、etcd 和 MinIO 在 Milvus 里各自扮演什么角色、怎么验证部署是真正可用的以及我实际跑下来踩过的坑。适合第一次接触 Milvus、想在本地快速搭一套向量检索服务跑通全流程的同学也适合已经用了起来、但一直对自动安装的依赖组件不太清楚的读者对照着看。1. 先想明白为什么需要这个脚本Milvus组件分工与编排收益1.1 Milvus不是“一个”数据库检索、元数据、对象存储各管一摊很多第一次接触 Milvus 的人会有个误区以为它跟 MySQL 类似一个进程一个端口就完事了。实际上 Milvus 2.x 是典型的存储计算分离架构哪怕单机部署也至少由三部分组成Milvus 主服务、etcd、对象存储默认的对象存储实现就是 MinIO。Milvus 主服务负责向量索引构建、ANN 检索、请求路由这些计算类的工作etcd 保存的是元数据包括集合 Schema、分片信息、索引任务状态、文件元信息可以理解成一本小账本MinIO 保存的是真正的数据文件比如原始向量的 binlog、构建好的索引文件、删除操作的 delta 日志。打一个比方MinIO 是仓库里的货架etcd 是记录货架上货品位置的账本Milvus 是调度员。调度员处理用户请求时先查账本再去货架上取货这个过程缺一不可。所以standalone_embed.sh要做的事情就很清晰了它不是一个简单的“启动 Milvus”命令而是把账本服务 etcd、货架服务 MinIO、调度员 Milvus 这三个容器一次性编排起来并让它们在同一网络里互相发现、协作。理解了这层关系后面看脚本和配置文件的时候就不会一头雾水。1.2 手动编排 vs 官方脚本自动嵌入到底省了什么如果不用这个脚本手动部署 Milvus 的路径大概是先拉 etcd 镜像配好成员参数和advertise-client-urls再拉 MinIO 镜像配置访问密钥创建存储桶然后准备milvus.yaml把ETCD_ENDPOINTS、MINIO_ADDRESS、MINIO_BUCKET_NAME这些参数一个一个指对最后才启动 Milvus 容器还得保证容器网络互通。这三件套里任何一组参数不对Milvus 启动日志都不好看经常只给你一个模棱两可的连接超时或者NoSuchBucket排查起来全靠猜。官方脚本把这一大堆步骤收敛成了执行一个 bash 文件。脚本会检查当前目录有没有docker-compose.yml和milvus.yaml没有就从对应版本下载然后直接docker compose up -d。所有版本组合、环境变量、健康检查、数据卷声明都已经在 compose 文件里帮你配好减少的是三个组件之间相互配置的工作量也减少了版本不匹配的风险。脚本的局限也在于它只适合单机场景真要上分布式集群还是得用 Milvus Operator 或者自己拆开编排这点后面我会专门展开。2. standalone_embed.sh 获取、执行与内部逻辑拆解2.1 获取脚本本身官方渠道和几个前提条件获取脚本最简单的方式是直接到 Milvus 官方文档的 single-node 部署页面页面里会给当前稳定版本对应的脚本下载链接。也可以从 GitHub release 页面找到同名文件。我自己用的版本是 v2.3.3下载形式大致是下面这样mkdir -p ~/milvus-deploy cd ~/milvus-deploy curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/v2.3.3/scripts/standalone_embed.sh -o standalone_embed.sh chmod x standalone_embed.sh如果 GitHub 的 raw 地址访问起来不稳定直接从 release 页面手动下载脚本文件放到目录里效果是一样的。执行脚本之前有几件事要提前确认Docker 版本不低于 20.10Docker Compose V2 插件可用也就是能执行docker compose而不是只有老版的docker-compose磁盘剩余空间建议预留 30GB 以上三个镜像加起来体积不小数据写起来之后 MinIO 目录还会持续变大内存至少 4GB我实际测试时 etcd、MinIO、Milvus 三个容器稳定运行大概占 2GB 左右如果还要构建较大的索引4GB 只是起步值。端口也要提前看一眼。Milvus 对外暴露的是 19530gRPC和 9091metricsMinIO 控制台是 9001etcd 的 2379 默认不暴露到宿主机。可以用下面这条命令检查占用情况ss -lntp | grep -E 19530|9091|9001|2379有输出就说明端口被占。真遇到这种情况不要急着杀进程先确认占用来源等部署完再折腾会更麻烦。具体的端口规划可以参考下表。端口组件用途默认是否暴露到宿主机19530MilvusgRPC 客户端请求是9091MilvusPrometheus metrics是2379etcd客户端请求仅容器网络9000MinIOS3 API仅容器网络9001MinIOWeb 控制台是2.2 脚本执行之后实际发生了什么先说结论standalone_embed.sh做的事情不复杂但它是可重复执行的。脚本启动后会先检查当前目录有没有docker-compose.yml没有就从对应 release 下载再检查milvus.yaml没有也下载最后执行docker compose up -d。核心逻辑可以概括成下面这段伪代码if [ ! -f docker-compose.yml ]; then download docker-compose.yml from release fi if [ ! -f milvus.yaml ]; then download milvus.yaml from release fi docker compose up -d所以如果你在同一个目录跑第二次脚本它不会重复下载配置文件也不会重新创建服务只会检查并启动不在运行状态的服务。这个幂等性很关键很多人第一次看到脚本每次都执行up -d以为会重复部署其实不会。首次执行时Docker 会按顺序拉取 etcd、MinIO、Milvus 三个镜像。镜像体积都不小尤其milvusdb/milvus那个加起来下载时间可能很长这部分取决于网络环境属正常现象不要看到长时间没有输出就按 CtrlC。拉完后 Compose 会创建一个默认网络三个容器在同一个网络里直接用服务名访问所以 Milvus 容器配置里写的是etcd:2379和minio:9000而不是 localhost。这些主机名就是 Compose 网络内的服务名解析结果。执行完成后用docker compose ps确认状态。正常情况下过一两分钟etcd 和 MinIO 会变成 healthyMilvus 会变成 Up。如果你的 Milvus 日志里一开始有连接 etcd 失败的报错先别慌往下看多半只是 etcd 还没通过健康检查Milvus 组件内部有重试机制等依赖组件健康后会自动恢复。2.3 嵌入的etcd与MinIO配置细节从生成的docker-compose.yml里能看到这几个服务的真实配置。etcd 用的是quay.io/coreos/etcd镜像启动命令大致是command: etcd -advertise-client-urlshttp://etcd:2379 \ -listen-client-urls http://0.0.0.0:2379 --data-dir /etcdadvertise-client-urls里的etcd就是 Compose 网络内的服务名容器之间访问就用这个名字。数据目录挂载到了当前目录下的volumes/etcd这是 etcd 持久化数据的存放位置理解这一点对后面做数据恢复很重要。MinIO 的配置也类似命令是minio server /minio_data --console-address :9001管理控制台会映射到宿主机的 9001 端口。这里有个很多人没注意到的细节MinIO 默认的 S3 API 端口 9000 并没有映射到宿主机因为只需要 Milvus 容器在 Compose 网络内访问它。如果你希望外部程序直接读取 MinIO 里的文件可以自己在 compose 文件里加一个端口映射比如19000:9000但不建议改掉原有的 9000 映射关系。Milvus 容器则通过环境变量把依赖组件的地址传进去environment: ETCD_ENDPOINTS: etcd:2379 MINIO_ADDRESS: minio:9000milvus.yaml里的对象存储配置定义了bucketName、rootPath这些细节。Milvus 启动时会自动创建存储桶所以不需要你提前去 MinIO 控制台建桶。等你看明白这三个容器之间的关系再回去读 compose 文件和milvus.yaml整条链路就非常直观了。3. Docker部署Milvus实操从脚本启动到数据读写验证3.1 环境准备与目录规划把部署目录当项目目录管理我强烈建议单独建一个目录来放 Milvus 部署文件不要图省事在 home 目录或者临时目录里执行脚本。因为脚本会在当前目录生成docker-compose.yml、milvus.yaml和一个volumes文件夹所有持久化数据都在volumes下面哪天要备份或者迁移整个目录拷走就完事。我的习惯是建一个独立目录mkdir -p /opt/milvus/standalone cd /opt/milvus/standalone环境检查通常就三条命令docker --version docker compose version free -h然后确认端口没被占。这里多说一句如果你看到 19530 端口已经在监听很可能是之前装过其他版本的 Milvus 或相关客户端进程用ss -lntp | grep 19530找到进程号确认是废弃进程再处理。如果确有必要改端口改的是docker-compose.yml里的 ports 映射以及客户端连接时的端口milvus.yaml不需要动。3.2 执行脚本、观察启动过程、确认健康状态准备工作做完后接着执行bash standalone_embed.sh脚本本身的输出很短大概率只有下载配置的进度和docker compose up的日志。真正的信息在容器日志里。我一般会开三个终端分别跟踪docker compose logs -f etcd docker compose logs -f minio docker compose logs -f milvus也可以只看整体状态watch -n 5 docker compose ps第一次启动时容器状态变化大致是etcd 从 starting 到 healthyMinIO 从 starting 到 healthyMilvus 一直显示 Up但日志里可能有重试连接的提示。要确认 Milvus 真正就绪最可靠的办法是看 milvus 容器日志里出现服务启动成功的字样通常是 grpc server 启动、query node ready 这类信息。我的经验是等到 etcd 和 MinIO 都 healthy 之后Milvus 才会开始正常干活如果你开了监控9091 端口的/metrics能拉到数据也就说明主服务真的活了。如果几分钟后 etcd 或者 MinIO 还是 starting不要盲目反复重启先用docker compose logs看对应容器的具体报错。最典型的两个原因是数据卷目录权限不对和端口冲突。卷目录权限问题在 Linux 上很常见容器内的 etcd 和 MinIO 进程跑在特定用户下对挂载目录的属主和权限有要求目录权限不对就起不来。3.3 用pymilvus做一次完整的读写验证部署完不能只看到三个容器 Up 就认为大功告成我每次都会用 pymilvus 实际写入一批向量再搜索一遍确认数据真正走通了 MinIO 和 etcd。先安装客户端pip install pymilvus然后写一段最小验证脚本from pymilvus import ( connections, FieldSchema, CollectionSchema, DataType, Collection, utility ) connections.connect(host127.0.0.1, port19530) print(utility.list_collections()) collection_name text_emb_demo if utility.has_collection(collection_name): utility.drop_collection(collection_name) fields [ FieldSchema(nameid, dtypeDataType.INT64, is_primaryTrue), FieldSchema(namevector, dtypeDataType.FLOAT_VECTOR, dim128), ] schema CollectionSchema(fields, descriptiondemo collection) collection Collection(namecollection_name, schemaschema) import random rows 1000 ids [i for i in range(rows)] vectors [[random.random() for _ in range(128)] for _ in range(rows)] collection.insert([ids, vectors]) collection.flush() print(entity count:, collection.num_entities) collection.create_index(vector, { index_type: HNSW, metric_type: L2, params: {M: 8, efConstruction: 200} }) collection.load() query [[random.random() for _ in range(128)]] results collection.search(query, vector, limit5) for hits in results: for hit in hits: print(hit.id, hit.distance)这段脚本能跑通说明 Milvus、etcd、MinIO 三个组件的链路是全通的。执行完可以再从另一个角度验证 MinIO浏览器打开http://localhost:9001账号minioadmin密码minioadmin进入默认存储桶应该能看到files目录下面有insert_log和index_files两个子目录里面躺着的就是刚才插入的 1000 条向量数据和索引文件。再看 etcd进入容器查一下 keydocker exec -it milvus-etcd etcdctl get --prefix --keys-only能看到一堆以collection-id、field-id开头的 key这些就是集合和字段的元数据。做到这一步你对“数据文件在 MinIO、元数据在 etcd”这句话会有非常直接的体感。4. 部署与使用中的常见问题排查实录4.1 etcd连接失败与数据目录异常先说最常见的Milvus 容器日志里不断出现 etcd 相关的connection refused或request timeout。第一步先用docker compose ps确认 etcd 到底是 healthy 还是 starting。如果是 starting基本可以确定 etcd 自身启动有问题去看 etcd 日志。常见原因之一是挂载的数据目录权限不对etcd 容器内以指定用户写数据但宿主机目录属主是 root解决办法是把目录属主改成对应用户或者直接调整目录权限。这里注意如果volumes/etcd里面已经有数据动权限操作要小心没有重要数据就直接清空目录让 etcd 重建最省事。还有一个场景我也碰到过机器异常断电或者docker compose stop强行停止之后etcd 数据目录可能损坏日志里出现failed to commit或者 snapshot 相关的错误。这种情况没有太多修复余地先把三个容器都停掉备份现有volumes/etcd目录然后删掉目录内容再启动。代价是 etcd 里的元数据会丢集合定义、索引元信息都要重新建但 MinIO 里的数据文件还在。测试环境无所谓生产环境就得靠 etcd 定期快照来兜底。4.2 MinIO的常见坑地址、密钥与存储桶MinIO 的问题更多样。Milvus 日志里如果出现S3 operation failed: NoSuchBucket先别急着去建桶Milvus 会自动建桶之所以报NoSuchBucket多半是它访问 MinIO 的 S3 API 时根本没连上。检查milvus.yaml里的 minio 配置address 应该指向minio:9000而不是 localhostaccessKeyID和secretAccessKey要与docker-compose.yml里 MinIO 的环境变量一致默认是minioadmin/minioadmin。很多人就是把 address 写成了localhost:9000这在容器网络里完全行不通Milvus 容器里的 localhost 指向的是容器自身。另一个常见坑是 MinIO 控制台打不开。控制台映射的是 9001 端口不是 9000直接访问http://localhost:9001就行。如果你在 compose 文件里改过MINIO_ACCESS_KEY和MINIO_SECRET_KEY登录时要换成自己改的milvus.yaml里的密钥也要同步改一致否则 Milvus 读写 MinIO 会一直报鉴权错误而且 MinIO 容器日志里不会给出直接原因排查起来非常费劲。注意没有备份的情况下永远不要对 Milvus 这套部署执行docker compose down -v它会连数据卷带文件一起删掉MinIO 里的数据和 etcd 的元数据会一次性全没。4.3 容器重启与数据持久化的正确姿势Compose 文件里三个服务都声明了 volumes映射到当前目录下的volumes文件夹所以默认情况下docker compose down不会丢数据只要你不加-v。我见过不少把数据整没的案例基本都是执行了docker compose down -v或者docker system prune -a顺手把卷清掉了。重启操作顺序也有讲究。日常维护推荐docker compose restart它只是重启容器不会重建如果你改了docker-compose.yml或milvus.yaml再执行docker compose up -dCompose 会自动比较配置并按需重建。要彻底停掉再拉起来用docker compose down再 up 也没问题数据都在只是 Milvus 的索引和 segment 信息需要从 MinIO 和 etcd 恢复冷启动时间会略长。数据备份建议按层次来做。etcd 做快照docker exec milvus-etcd etcdctl snapshot save /tmp/etcd-snapshot.dbMinIO 可以直接同步文件用mc mirror或者对象存储的跨区域复制都行。关键在于备份时要把 etcd 快照和 MinIO 数据放在同一个时间点两者一致才能恢复整个 Milvus 状态。备份前最好把 Milvus 容器停掉让文件处于静默状态否则容易出现元数据和数据文件不一致的问题。4.4 版本升级与配置管理的坑standalone_embed.sh脚本里的版本号是你下载时那个版本的之后新版本发布脚本不会自动更新你的 compose 文件和镜像。升级 Milvus 不是改一个镜像 tag 那么简单元数据格式和存储格式都在演进盲目拉新镜像很容易因为数据格式不兼容导致启动失败。稳妥的做法是先备份再看官方文档有没有跨版本升级说明确认从当前版本能升到目标版本再动手。配置文件我强烈建议纳入版本管理。初始化一次git init git add docker-compose.yml milvus.yaml standalone_embed.sh git commit -m milvus standalone baseline以后再改动就能随时 diff 和回滚。另外要提醒的是脚本里支持一个环境变量DOCKER_VOLUME_DIRECTORY它可以改变 volumes 目录的位置。如果之前设置过这个变量新部署时会发现数据写到了另一个目录排查起来会怀疑人生。我的建议是只用默认值别去折腾这个变量。5. 从standalone到生产什么时候需要拆开部署5.1 资源规划与性能观察standalone_embed.sh最合适的场景是开发测试、原型验证和小规模数据量。容器资源上限不好直接限定因为 Docker 默认不限制资源三个容器会互相抢内存。如果发现机器内存吃紧可以在 compose 文件里给 etcd 和 MinIO 加mem_limit比如 etcd 512m、MinIO 1gMilvus 则要看构建多大的索引建议至少 1.5g 起步。磁盘 IO 的影响比内存更明显MinIO 的文件读写和 Milvus 建索引都是重 IO 操作机械盘上体感会非常慢有条件尽量用 SSD。性能观察用好两个入口就够了Milvus 的 9091 端口暴露了 Prometheus metricsetcd 也有/metrics接口MinIO 内置了控制台监控。这些指标能定位到每个组件自己的瓶颈比如 etcd 的 kv 事务延迟、MinIO 的读写延迟、Milvus 的索引构建时长。遇到请求变慢先去对应组件看指标而不是拍脑袋乱调参数。5.2 哪些信号告诉你该拆开部署了当向量数据量上来之后standalone 这种把三个组件挤在一台机器的方式会成为瓶颈。判断标准看几个信号Milvus 的索引构建时间越来越长并且和 MinIO 读写互相拖累etcd 因为资源不足出现日志延迟引发请求抖动磁盘容量和 IO 出现明显压力。这几个信号出现任何一个都说明单机已经不适合硬撑了。拆开部署的第一步可以考虑把 MinIO 换成云上对象存储。只要改milvus.yaml里的 minio 配置区域把 address 指向 S3 兼容的 endpointbucketName 改成云上的 bucket密钥换成云账号的就行Milvus 会自动走 S3 协议。这样 Milvus 和 etcd 留在本机数据文件放到云端容量问题交给云端解决。再往下走etcd 要独立集群Milvus 的各 coordinator 和 worker 节点也要分开调度这套东西再用 docker compose 已经不太够应该考虑 Milvus Operator 或者其他编排平台。但不管怎么演进standalone_embed.sh带给你的组件认知都不会白费它把 Milvus、etcd、MinIO 的关系浓缩在一份 compose 文件里拆开部署只是把这三件事放到不同机器上执行。最后说一点个人体会。我刚接触 Milvus 的时候也是先用这个脚本快速跑通后来为了排查一个数据不一致问题把 MinIO 里的文件位置和 etcd 里的 key 一条条对照着看才真正理解这套架构。对还没部署过的人我的建议是别急着跳过自动化的东西直接上生产方案先用官方脚本把组件关系跑一遍很多概念会清晰得多。遇到问题回到这篇的排查部分大多数情况都能对号入座。