Milvus Docker Compose 部署指南

使用官方 milvusdb/milvus:v3.0.2 镜像通过 Docker Compose 一键部署向量数据库 Milvus,覆盖 Standalone 单机官方编排与手动编排分布式伪集群两种模式,包含数据卷持久化、环境变量注入、健康检查与「建集合→写向量→相似度检索」端到端业务验证

MilvusMilvus向量数据库Docker Compose伪集群NoSQL2026/10/03

Milvus Docker Compose 部署指南

目标:使用官方 milvusdb/milvus:v3.0.2 镜像,通过 Docker Compose 部署向量数据库 Milvus,覆盖官方 Standalone(单机)模式与手动编排的分布式伪集群模式,并完成「建集合 → 写向量 → 相似度检索」的端到端业务验证。本文档面向容器化部署场景,所有操作在具备 Docker Compose 的宿主机上执行,已在 Ubuntu 22.04 + Docker Compose v2 环境实测通过。

一、环境信息

项目值
操作系统Ubuntu 22.04(x86_64/amd64)
Docker29.x(含 Compose v2 插件)
Milvus 镜像milvusdb/milvus:v3.0.2
Milvus 版本3.0.2(milvus_build_info{version="3.0.2"})
etcd 镜像quay.io/coreos/etcd:v3.5.25
MinIO 镜像milvusdb/minio:RELEASE.2024-12-18T13-15-44Z
Pulsar 镜像apachepulsar/pulsar:2.11.0(伪集群模式)
SDK 端口19530(gRPC)
WebUI/健康检查端口9091
数据目录./volumes/{etcd,minio,milvus}

二、镜像选型说明

Milvus 官方镜像为 milvusdb/milvus,tag 与版本号一一对应,本文使用当前稳定版 3.0.2:

docker pull milvusdb/milvus:v3.0.2
docker pull quay.io/coreos/etcd:v3.5.25
docker pull milvusdb/minio:RELEASE.2024-12-18T13-15-44Z
docker images | grep -E 'milvus|etcd|minio'

⚠️ 注意:Milvus 官方自 v2.2 起不再维护集群模式的官方 docker-compose 文件,官方 compose 仅支持 Standalone(单机)模式;生产级分布式部署官方推荐 Kubernetes(Helm / Milvus Operator)。无 K8s 环境下可使用本文第四章的手动 compose 编排做分布式学习与测试。

三、前置条件

  • 宿主机已安装 Docker Engine 与 Docker Compose 插件。
  • 具备 root 或 docker 组权限。
  • 端口 19530(gRPC)、9091(WebUI)未被占用;伪集群模式额外占用 9000/9001(MinIO)、6650/8080(Pulsar)。
  • 至少 8GB+ 可用内存(Milvus 核心 + etcd + MinIO 常驻约 4~6GB)。
docker --version
docker compose version
# Docker version 29.x.x
# Docker Compose version v2.x

四、官方 Standalone 单机部署

4.1 下载官方 compose 文件

mkdir -p /opt/milvus-compose
cd /opt/milvus-compose
wget https://github.com/milvus-io/milvus/releases/download/v3.0.2/milvus-standalone-docker-compose.yaml -O docker-compose.yml

4.2 compose 文件内容

官方 Standalone 文件通过 3 个容器协作组成一个单机 Milvus:milvus-etcd(元数据存储)、milvus-minio(对象存储)、milvus-standalone(Milvus 核心服务),并带一个一次性 milvus-volume-init 数据目录属主迁移服务:

version: '3.5'

x-milvus-image: &milvus-image milvusdb/milvus:v3.0.2

services:
  # Remove the .milvus-volume-owner-* marker after restoring files owned by a
  # different user so this one-shot migration runs again.
  milvus-volume-init:
    image: *milvus-image
    user: "0:0"
    network_mode: none
    read_only: true
    restart: "no"
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        set -eu
        uid="$$(id -u milvus)"
        gid="$$(id -g milvus)"
        marker="/var/lib/milvus/.milvus-volume-owner-$${uid}-$${gid}"
        if [ ! -e "$${marker}" ]; then
          echo "Preparing /var/lib/milvus for $${uid}:$${gid}"
          chown -R "$${uid}:$${gid}" /var/lib/milvus
          touch "$${marker}"
          chown "$${uid}:$${gid}" "$${marker}"
        fi
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus

  etcd:
    container_name: milvus-etcd
    image: quay.io/coreos/etcd:v3.5.25
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_SNAPSHOT_COUNT=50000
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
    command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 30s
      timeout: 20s
      retries: 3

  minio:
    container_name: milvus-minio
    image: milvusdb/minio:RELEASE.2024-12-18T13-15-44Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 20s
      retries: 3

  standalone:
    container_name: milvus-standalone
    image: *milvus-image
    command: ["milvus", "run", "standalone"]
    security_opt:
    - seccomp:unconfined
    environment:
      MINIO_REGION: us-east-1
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
      interval: 30s
      start_period: 90s
      timeout: 20s
      retries: 3
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      milvus-volume-init:
        condition: service_completed_successfully
      etcd:
        condition: service_started
      minio:
        condition: service_started

networks:
  default:
    name: milvus

4.3 启动并验证

docker compose up -d
# Network milvus Creating ... 三个容器依次创建启动

docker compose ps
# NAME              STATUS
# milvus-etcd       Up (healthy)
# milvus-minio      Up (healthy)
# milvus-standalone Up (healthy)

curl http://127.0.0.1:9091/healthz
# OK

💡 说明:Standalone 模式下 Milvus 各协调器(rootcoord/datacoord/querycoord/indexcoord)以单进程形式合并在 standalone 内部运行,默认消息队列为嵌入式 RocksMQ(etcdctl get by-dev/config/mqtype 返回 rocksmq),无需单独部署 Pulsar/Kafka。

4.4 业务端到端验证(REST API)

Milvus 3.x 提供 HTTP REST API(端口 19530 的 /v2/vectordb/*),可直接用 curl 完成建集合、插入与检索:

# 1. 创建集合
curl -s http://127.0.0.1:19530/v2/vectordb/collections/create -X POST -H 'Content-Type: application/json' -d '{
  "collectionName": "book",
  "dimension": 8,
  "metricType": "L2",
  "primaryFieldName": "book_id",
  "vectorFieldName": "book_vector",
  "fields": [
    {"fieldName": "book_id", "dataType": "Int64", "isPrimary": true},
    {"fieldName": "book_name", "dataType": "VarChar", "maxLength": 256},
    {"fieldName": "book_vector", "dataType": "FloatVector", "dim": 8}
  ]
}'
# {"code":0,"data":{}}

# 2. 插入向量
curl -s http://127.0.0.1:19530/v2/vectordb/entities/insert -X POST -H 'Content-Type: application/json' -d '{
  "collectionName": "book",
  "data": [
    {"book_id": 1, "book_name": "Introduction to Milvus", "book_vector": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]},
    {"book_id": 2, "book_name": "Milvus in Action", "book_vector": [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]},
    {"book_id": 3, "book_name": "Vector Database Guide", "book_vector": [0.2, 0.1, 0.5, 0.3, 0.9, 0.4, 0.6, 0.7]},
    {"book_id": 4, "book_name": "Advanced Vector Search", "book_vector": [0.9, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]}
  ]
}'
# {"code":0,"cost":0,"data":{"insertCount":4,"insertIds":[1,2,3,4]}}

# 3. 向量相似度检索(等待数据落盘后执行,返回按 L2 距离升序)
curl -s http://127.0.0.1:19530/v2/vectordb/entities/search -X POST -H 'Content-Type: application/json' -d '{
  "collectionName": "book",
  "data": [[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]],
  "annsField": "book_vector",
  "limit": 3,
  "outputFields": ["book_id", "book_name"]
}'
# {"code":0,"cost":0,"data":[{"book_id":1,"book_name":"Introduction to Milvus","distance":0},
#  {"book_id":3,"book_name":"Vector Database Guide","distance":0.28999996},
#  {"book_id":4,"book_name":"Advanced Vector Search","distance":0.7099999}],"topks":[3]}

# 4. 查看集合详情
curl -s http://127.0.0.1:19530/v2/vectordb/collections/describe -X POST -H 'Content-Type: application/json' -d '{"collectionName":"book"}'
# {"code":0,"data":{"collectionID":469509374503816523,"collectionName":"book","load":"LoadStateLoaded",...}}

4.5 WebUI 访问

启动完成后可访问 http://127.0.0.1:9091/webui/ 查看 Milvus 实例信息(HTTP 200):

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:9091/webui/
# 200

# 版本与构建信息
curl -s http://127.0.0.1:9091/metrics | grep -v '^#' | grep milvus_build_info
# milvus_build_info{built="Fri Sep 18 10:37:46 UTC 2026",git_commit="3c4448a2ae",version="3.0.2"} 1

五、手动编排分布式伪集群(学习/测试)

官方不再提供集群版 compose 文件,以下为按 Milvus 分布式架构手动编排的 compose,适用于理解架构与功能验证,不建议用于生产。核心由 etcd + MinIO + Pulsar + 5 个 Milvus 微服务组成。

💡 说明:Milvus v2.6+ 架构中协调器合并为 mixCoord(rootcoord/datacoord/querycoord/indexcoord 合一),并引入 StreamingNode;indexNode 已并入 DataNode(实测 milvus run indexnode 返回 Unknown server type = indexnode)。因此集群微服务为:mixcoord、proxy、querynode、datanode、streamingnode。

5.1 准备集群模式配置

集群模式下消息队列必须为独立的 Pulsar(RocksMQ 仅支持单机),需要一份将 mq.type 设为 pulsar 的配置:

mkdir -p /opt/milvus-cluster-config
# 下载官方 milvus.yaml 后修改两处:
#   mq.type: default  →  mq.type: pulsar
#   pulsar.address: localhost →  pulsar.address: pulsar
# /opt/milvus-cluster-config/milvus.yaml(节选)
mq:
  type: pulsar
pulsar:
  address: pulsar
  port: 6650

5.2 伪集群 compose 文件

version: '3.5'

# Milvus v3.0.2 伪集群编排(学习/测试用途)
# 核心组件:etcd(元数据) + minio(对象存储) + pulsar(消息队列)
# Milvus 微服务:mixcoord(合并协调器) + proxy + querynode + datanode + streamingnode
# 说明:v2.6+ 架构 indexnode 已并入 datanode;官方 docker-compose 仅维护 Standalone 模式,
# 此文件为手动编排的分布式学习环境(伪集群)

x-milvus-image: &milvus-image milvusdb/milvus:v3.0.2
x-milvus-config: &milvus-config
  /opt/milvus-cluster-config/milvus.yaml:/milvus/configs/milvus.yaml:ro
x-milvus-env: &milvus-env
  ETCD_ENDPOINTS: etcd:2379
  MINIO_ADDRESS: minio:9000
  PULSAR_ADDRESS: pulsar://pulsar:6650
  MINIO_REGION: us-east-1
  MINIO_BUCKET_NAME: milvus-bucket
  ROOT_COORD_ADDRESS: mixcoord:53100
  PROXY_ADDRESS: proxy:19530

services:
  etcd:
    container_name: milvus-cluster-etcd
    image: quay.io/coreos/etcd:v3.5.25
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
    volumes:
      - etcd_data:/etcd
    command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 30s
      timeout: 20s
      retries: 3
    networks:
      - milvus-cluster-net

  minio:
    container_name: milvus-cluster-minio
    image: milvusdb/minio:RELEASE.2024-12-18T13-15-44Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - minio_data:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 20s
      retries: 3
    networks:
      - milvus-cluster-net

  pulsar:
    container_name: milvus-cluster-pulsar
    image: apachepulsar/pulsar:2.11.0
    command: bin/pulsar standalone
    ports:
      - "6650:6650"
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/admin/v2/clusters"]
      interval: 30s
      timeout: 20s
      retries: 3
    networks:
      - milvus-cluster-net

  mixcoord:
    container_name: milvus-mixcoord
    image: *milvus-image
    command: ["milvus", "run", "mixcoord"]
    security_opt:
      - seccomp:unconfined
    environment: *milvus-env
    volumes:
      - cluster_data:/var/lib/milvus
      - *milvus-config
    depends_on:
      etcd:
        condition: service_started
      minio:
        condition: service_started
      pulsar:
        condition: service_started
    networks:
      - milvus-cluster-net

  proxy:
    container_name: milvus-proxy
    image: *milvus-image
    command: ["milvus", "run", "proxy"]
    security_opt:
      - seccomp:unconfined
    environment: *milvus-env
    ports:
      - "19530:19530"
      - "9091:9091"
    volumes:
      - cluster_data:/var/lib/milvus
      - *milvus-config
    depends_on:
      - mixcoord
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
      interval: 30s
      start_period: 90s
      timeout: 20s
      retries: 3
    networks:
      - milvus-cluster-net

  querynode:
    container_name: milvus-querynode
    image: *milvus-image
    command: ["milvus", "run", "querynode"]
    security_opt:
      - seccomp:unconfined
    environment: *milvus-env
    volumes:
      - cluster_data:/var/lib/milvus
      - *milvus-config
    depends_on:
      - mixcoord
    networks:
      - milvus-cluster-net

  datanode:
    container_name: milvus-datanode
    image: *milvus-image
    command: ["milvus", "run", "datanode"]
    security_opt:
      - seccomp:unconfined
    environment: *milvus-env
    volumes:
      - cluster_data:/var/lib/milvus
      - *milvus-config
    depends_on:
      - mixcoord
    networks:
      - milvus-cluster-net

  streamingnode:
    container_name: milvus-streamingnode
    image: *milvus-image
    command: ["milvus", "run", "streamingnode"]
    security_opt:
      - seccomp:unconfined
    environment: *milvus-env
    volumes:
      - cluster_data:/var/lib/milvus
      - *milvus-config
    depends_on:
      - mixcoord
    networks:
      - milvus-cluster-net

volumes:
  etcd_data:
  minio_data:
  cluster_data:

networks:
  milvus-cluster-net:
    name: milvus-cluster-net

5.3 启动与验证

cd /opt/milvus-cluster-compose
docker compose up -d
# 8 个容器依次启动

docker compose ps
# NAME                      STATUS
# milvus-cluster-etcd       Up (healthy)
# milvus-cluster-minio      Up (healthy)
# milvus-cluster-pulsar     Up (healthy)
# milvus-mixcoord           Up
# milvus-proxy              Up (healthy)
# milvus-querynode          Up
# milvus-datanode           Up
# milvus-streamingnode      Up

curl http://127.0.0.1:9091/healthz
# OK

# 各组件通过 etcd 完成服务发现注册(实测会话列表)
etcdctl get --prefix by-dev/meta/session --keys-only
# by-dev/meta/session/datacoord
# by-dev/meta/session/datanode-9
# by-dev/meta/session/mixcoord
# by-dev/meta/session/proxy-10
# by-dev/meta/session/querycoord
# by-dev/meta/session/querynode-7
# by-dev/meta/session/querynode-8
# by-dev/meta/session/rootcoord

伪集群业务验证与 Standalone 相同,可直接复用 4.4 节 REST API 命令(同一 19530 端口):

curl -s http://127.0.0.1:19530/v2/vectordb/collections/create -X POST -H 'Content-Type: application/json' \
  -d '{"collectionName":"cluster_test","dimension":4,"metricType":"IP","primaryFieldName":"id","vectorFieldName":"vector",
       "fields":[{"fieldName":"id","dataType":"Int64","isPrimary":true},{"fieldName":"vector","dataType":"FloatVector","dim":4}]}'
# {"code":0,"data":{}}

curl -s http://127.0.0.1:19530/v2/vectordb/entities/insert -X POST -H 'Content-Type: application/json' \
  -d '{"collectionName":"cluster_test","data":[{"id":1,"vector":[1.0,0.0,0.0,0.0]},{"id":2,"vector":[0.9,0.1,0.0,0.0]},{"id":3,"vector":[0.0,1.0,0.0,0.0]}]}'
# {"code":0,"cost":0,"data":{"insertCount":3,"insertIds":[1,2,3]}}

curl -s http://127.0.0.1:19530/v2/vectordb/entities/search -X POST -H 'Content-Type: application/json' \
  -d '{"collectionName":"cluster_test","data":[[1.0,0.0,0.0,0.0]],"annsField":"vector","limit":3,"outputFields":["id"]}'
# {"code":0,"cost":0,"data":[{"distance":1,"id":1},{"distance":0.9,"id":2},{"distance":0,"id":3}],"topks":[3]}

六、数据持久化说明

  • Standalone 模式:etcd、MinIO、Milvus 数据分别持久化到 ./volumes/etcd、./volumes/minio、./volumes/milvus;docker compose down 不会删除数据卷,重启后数据仍在。
  • 伪集群模式:etcd/MinIO/Milvus 使用命名数据卷 etcd_data/minio_data/cluster_data,同样在 compose 项目内持久化。
  • 全部停止并清理(慎用,会删数据):docker compose down -v。

七、常用环境变量表

环境变量说明示例值
ETCD_ENDPOINTSetcd 端点列表etcd:2379
MINIO_ADDRESSMinIO/S3 服务地址minio:9000
MINIO_ACCESS_KEY_ID / MINIO_SECRET_ACCESS_KEYMinIO 访问密钥minioadmin
MINIO_REGIONMinIO 区域us-east-1
PULSAR_ADDRESSPulsar 服务地址(伪集群必填,带 pulsar:// 协议前缀)pulsar://pulsar:6650
DOCKER_VOLUME_DIRECTORY官方 compose 的数据卷根目录(默认 .)/opt/milvus-compose

八、常用运维命令

# 查看服务状态与日志
docker compose ps
docker compose logs -f standalone

# 进入容器执行命令(如查看配置、运行 milvus CLI)
docker exec -it milvus-standalone sh

# 查看 Milvus 支持的 server type
docker exec milvus-standalone milvus run --help
# [server type] rootcoord proxy querycoord indexnode datanode cdc
#               querynode datacoord streamingnode mixcoord standalone mixture

# 停止 / 启动
docker compose stop
docker compose start

# 完全移除(保留数据卷)
docker compose down

九、常见问题(FAQ)

9.1 milvus run indexnode 报 Unknown server type = indexnode

Milvus v2.6+ 将 indexNode 并入 DataNode,indexnode 不再是可独立启动的 server type。集群编排中只需 datanode 一个服务。

9.2 伪集群中 StreamingNode 报 Invalid service URL / service host cannot be empty

原因:PULSAR_ADDRESS 未带协议前缀或地址解析为空。应设置为完整 URL 格式:PULSAR_ADDRESS: pulsar://pulsar:6650。

9.3 创建集合超时(code: 10001, message: request timeout)

组件刚启动尚未完成服务发现时出现。等待 1~2 分钟,确认 docker compose ps 全部 Up (healthy) 后重试。

9.4 搜索报 collection not loaded 或 index not found

Milvus 3.x 检索前必须:先给向量字段建索引,再 load_collection 将集合加载进内存。REST API 流程中先 create_index(或等待 AUTOINDEX 构建完成),再用 pymilvus 的 load_collection()。

十、参考链接