一、MinIO 背景介绍

1.1 什么是 MinIO?

MinIO 是一个高性能、开源的对象存储系统,完全兼容 Amazon S3 API。它专为云原生应用设计,采用 Go 语言编写,具有极高的性能和极简的部署体验。

MinIO 诞生于 2014 年,由 Anand Babu Periasamy 创立,目标是成为私有云和混合云环境下的对象存储标准。如今,MinIO 已被全球数千家企业采用,广泛应用于数据湖、机器学习、备份归档、日志存储等场景。

1.2 为什么选择 MinIO?

特性说明
S3 兼容100% 兼容 Amazon S3 API,无缝迁移现有应用
高性能单节点可达 183 GB/s 读取、171 GB/s 写入(NVMe 环境)
云原生支持 Kubernetes Operator,原生适配容器化部署
极简架构单个二进制文件,无外部依赖,部署仅需一条命令
数据安全内置纠删码(Erasure Coding)、Bitrot 检测、自动修复
多租户支持 Bucket 级隔离、IAM 策略、LDAP/AD 集成

二、MinIO 核心功能与特性

2.1 存储模式

MinIO 支持三种部署模式:

模式描述适用场景
Standalone(单机单盘)单节点单磁盘,无冗余开发测试
Standalone Multi-Drive(单机多盘)单节点多磁盘,启用纠删码小规模生产
Distributed(分布式)多节点多磁盘,高可用大规模生产

2.2 核心特性

  1. 对象锁定(Object Locking):支持 WORM(一次写入多次读取),满足合规要求
  2. 版本控制(Versioning):自动保留对象历史版本,防止误删除
  3. 生命周期管理(Lifecycle):自动转换存储类别、过期删除
  4. 站点复制(Site Replication):跨数据中心多活复制,提供 BC/DR 能力
  5. 加密支持:支持服务端加密(SSE-S3、SSE-KMS、SSE-C)
  6. 监控告警:原生支持 Prometheus + Grafana,提供丰富指标

三、纠删码(Erasure Coding)深度解析

3.1 什么是纠删码?

纠删码是 MinIO 的核心数据保护机制。与简单的副本复制不同,纠删码将对象分割为数据分片(Data Shards)和校验分片(Parity Shards),通过 Reed-Solomon 算法实现冗余保护。

核心公式:N(纠删集大小)= K(数据分片)+ M(校验分片)

例如,EC:4 表示每个对象被分成 K 个数据分片和 4 个校验分片,可以容忍最多 4 个磁盘同时故障而不丢失数据。

3.2 纠删码 vs 副本复制

对比项纠删码(EC:4,16盘)三副本复制
原始容量16 TB16 TB
可用容量12 TB(75%)5.33 TB(33%)
存储开销33%200%
可容忍故障4 块磁盘2 块磁盘
读取性能高(并行读取)中

纠删码在存储效率和容错能力之间提供了更优的平衡。

3.3 纠删集(Erasure Set)

MinIO 将集群中的磁盘划分为一个或多个纠删集。每个纠删集的大小决定了最大可配置的校验分片数:

  • 纠删集大小范围:2 ~ 16 块磁盘(默认),最新版本支持通过 MINIO_ERASURE_SET_DRIVE_COUNT 扩展至 32 块
  • 最大校验分片数:纠删集大小的 1/2
  • 例如:16 块磁盘的纠删集,支持 EC:0 ~ EC:8

⚠️ 生产环境建议:校验分片至少设置为 EC:3 或更高。低于 EC:3 的配置仅适用于开发和测试环境。

3.4 存储类别与纠删码级别

MinIO 支持两种存储类别,可配置不同的纠删码级别:

环境变量说明默认值
MINIO_STORAGE_CLASS_STANDARD标准存储类别自动计算
MINIO_STORAGE_CLASS_RRS低冗余存储类别自动计算

配置示例:

# 标准存储:高耐久性,可容忍 4 块磁盘故障
export MINIO_STORAGE_CLASS_STANDARD="EC:4"

# 低冗余存储:节省空间,可容忍 2 块磁盘故障
export MINIO_STORAGE_CLASS_RRS="EC:2"

如果不手动设置纠删码级别,MinIO 会根据纠删集大小(Erasure Set Size)自动计算默认值。
默认值对照表:

MINIO_STORAGE_CLASS_STANDARD(标准存储)

纠删集大小(磁盘数)默认纠删码数据分片 : 校验分片可用容量
1EC:01:0100%
2 ~ 3EC:12:1 或 3:166% ~ 75%
4 ~ 5EC:24:2 或 5:260% ~ 62.5%
6 ~ 7EC:36:3 或 7:357% ~ 58%
8 ~ 16EC:412:4(16盘时)75%(16盘时)

MINIO_STORAGE_CLASS_RRS(低冗余存储)

纠删集大小默认值
1EC:0
> 1EC:1

四、部署教程

4.1 Docker Compose 单机部署

适用于开发测试或轻量级生产环境,单节点多磁盘模式。

services:
  minio:
    image: minio/minio:RELEASE.2025-04-22T22-12-26Z
    container_name: minio
    restart: unless-stopped
    environment:
      - TZ=Asia/Shanghai
      - MINIO_ROOT_USER=admin
      - MINIO_ROOT_PASSWORD=123456
    ports:
      - "9000:9000"   # S3 API 端口
      - "9001:9001"   # Web Console 端口
    volumes:
      - /data/minio:/data
    command: minio server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: '4.0'
          memory: 8G
        reservations:
          cpus: '4.0'
          memory: 8G
    networks:
      - my_net
networks:
  my_net:
    driver: bridge

部署步骤:

# 1. 创建数据目录
mkdir -p /data/minio

# 2. 启动服务
docker compose up -d

# 3. 查看日志
docker logs -f minio

# 4. 访问控制台
# 浏览器打开 http://localhost:9001
# 账号:admin / 密码:123456

💡 说明:此部署为单机单盘模式,无纠删码保护。若磁盘损坏,数据将丢失。建议生产环境使用单机多盘或分布式部署。


4.2 Kubernetes 单机部署(无纠删码)

适用于 K8s 环境下的快速验证,单 Pod 多磁盘,关闭纠删码(EC:0)。

apiVersion: v1
kind: Secret
metadata:
  name: minio-secret
  namespace: demo
type: Opaque
data:
  # echo -n "minioadmin" | base64
  root-user: bWluaW9hZG1pbg==
  # echo -n "minio123" | base64
  root-password: bWluaW8xMjM=
---
apiVersion: v1
kind: Service
metadata:
  name: minio-service
  namespace: demo
  labels:
    app: minio
spec:
  type: NodePort
  ports:
    - port: 9000
      name: s3-api
      targetPort: 9000
      nodePort: 9000
    - port: 9001
      name: web-console
      targetPort: 9001
      nodePort: 9001
  selector:
    app: minio
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  namespace: demo
  labels:
    app: minio
spec:
  replicas: 1
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      nodeName: minio # 调度到指定节点
      containers:
      - name: minio
        image: docker.io/minio/minio:RELEASE.2025-04-22T22-12-26Z
        args:
        - server
        - /data{1...4}
        - --console-address
        - ":9001"
        env:
        - name: MINIO_ROOT_USER
          valueFrom:
            secretKeyRef:
              name: minio-secret
              key: root-user
        - name: MINIO_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: minio-secret
              key: root-password
        - name: MINIO_STORAGE_CLASS_STANDARD
          value: "EC:0"
        - name: MINIO_STORAGE_CLASS_RRS
          value: "EC:0"
        ports:
        - containerPort: 9000
          name: s3-api
        - containerPort: 9001
          name: web-console
        volumeMounts:
        - name: storage1
          mountPath: /data1
        - name: storage2
          mountPath: /data2
        - name: storage3
          mountPath: /data3
        - name: storage4
          mountPath: /data4
      volumes:
      - name: storage1
        hostPath:
          path: /data1
          type: DirectoryOrCreate
      - name: storage2
        hostPath:
          path: /data2
          type: DirectoryOrCreate
      - name: storage3
        hostPath:
          path: /data3
          type: DirectoryOrCreate
      - name: storage4
        hostPath:
          path: /data4
          type: DirectoryOrCreate

部署步骤:

# 1. 创建命名空间
kubectl create namespace demo

# 2. 应用配置
kubectl apply -f minio-ec0.yaml

# 3. 查看 Pod 状态
kubectl get pods -n demo -w

# 4. 访问服务
# S3 API: http://<NodeIP>:9000
# Console: http://<NodeIP>:9001
# 账号:minioadmin / 密码:minio123

⚠️ 注意:此配置将纠删码设置为 EC:0,即无数据冗余保护。4 个磁盘仅提供容量聚合,任意一块磁盘损坏都会导致数据丢失。仅用于开发和测试环境。


4.3 Kubernetes 最小高可用部署(分布式)

生产环境推荐使用分布式模式,最小高可用配置为 4 节点 × 4 磁盘,共 16 块磁盘,默认启用 EC:4 纠删码。

apiVersion: v1
kind: Secret
metadata:
  name: minio-creds
  namespace: minio
type: Opaque
data:
  root-user: bWluaW9hZG1pbg==
  root-password: bWluaW8xMjM=
---
apiVersion: v1
kind: Service
metadata:
  name: minio
  namespace: minio
  labels:
    app: minio
spec:
  clusterIP: None
  ports:
    - port: 9000
      name: s3-api
    - port: 9001
      name: web-console
  selector:
    app: minio
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  namespace: minio
  labels:
    app: minio
spec:
  serviceName: minio
  replicas: 4
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
      - name: minio
        image: quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z
        args:
        # 4 节点 × 4 磁盘 = 16 块磁盘
        # 自动创建 1 个纠删集,默认 EC:4(12 数据 + 4 校验)
        - server
        - http://minio-{0...3}.minio.minio.svc.cluster.local/data{1...4}
        - --console-address
        - ":9001"
        env:
        - name: MINIO_ROOT_USER
          valueFrom:
            secretKeyRef:
              name: minio-creds
              key: root-user
        - name: MINIO_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: minio-creds
              key: root-password
        - name: MINIO_STORAGE_CLASS_STANDARD
          value: "EC:4"
        - name: MINIO_STORAGE_CLASS_RRS
          value: "EC:2"
        ports:
        - containerPort: 9000
          name: s3-api
        - containerPort: 9001
          name: web-console
        volumeMounts:
        - name: data-0
          mountPath: /data1
        - name: data-1
          mountPath: /data2
        - name: data-2
          mountPath: /data3
        - name: data-3
          mountPath: /data4
        resources:
          requests:
            memory: "4Gi"
            cpu: "2000m"
          limits:
            memory: "8Gi"
            cpu: "4000m"
  volumeClaimTemplates:
  - metadata:
      name: data-0
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Gi
  - metadata:
      name: data-1
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Gi
  - metadata:
      name: data-2
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Gi
  - metadata:
      name: data-3
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Gi

部署步骤:

# 1. 创建命名空间
kubectl create namespace minio

# 2. 应用配置
kubectl apply -f minio-ha.yaml

# 3. 等待 Pod 就绪(约 1-2 分钟)
kubectl get pods -n minio -w

# 4. 配置 mc 客户端
kubectl run mc --image=minio/mc --rm -it -- sh
mc alias set myminio http://minio.minio.svc.cluster.local:9000 minioadmin minio123

# 5. 查看集群信息
mc admin info myminio

预期输出:

●  minio-0.minio.minio.svc.cluster.local:9000
   Uptime: 5 minutes
   Version: 2025-04-22T22:12:26Z
   Network: 4/4 OK
   Drives: 16/16 OK
   Pool: 1

   Pools:
      1st, Erasure sets: 1, Drives per erasure set: 16

   16 drives online, 0 drives offline, EC:4

五、如何调整纠删码级别

5.1 调整方式

纠删码级别通过环境变量在 MinIO 启动时配置,无法在运行中动态修改。修改后需要重启服务生效。

# 标准存储类别
export MINIO_STORAGE_CLASS_STANDARD="EC:4"

# 低冗余存储类别
export MINIO_STORAGE_CLASS_RRS="EC:2"

5.2 纠删码级别选择指南

磁盘总数推荐 EC 级别可用容量可容忍故障
4 块EC:250%2 块
8 块EC:450%4 块
16 块EC:4(默认)75%4 块
16 块EC:8(最大)50%8 块

5.3 Docker Compose 调整示例

services:
  minio:
    image: minio/minio:latest
    environment:
      - MINIO_STORAGE_CLASS_STANDARD=EC:2
      - MINIO_STORAGE_CLASS_RRS=EC:1
    # ... 其他配置

5.4 Kubernetes 调整示例

env:
- name: MINIO_STORAGE_CLASS_STANDARD
  value: "EC:4"
- name: MINIO_STORAGE_CLASS_RRS
  value: "EC:2"

修改后执行:

kubectl rollout restart statefulset/minio -n minio

5.5 验证纠删码配置

# 使用 mc 客户端查看
mc admin info myminio

# 查看特定对象的纠删码分布
mc admin object info myminio/bucket/object.txt

六、后期扩容指南

6.1 MinIO 扩容原理

MinIO 通过添加 新的服务器池(Server Pool) 来扩容。每个 Pool 是独立的故障域,新对象按各 Pool 的可用空间比例进行分配。

⚠️ 重要限制:

  • 扩容不提供跨 Pool 的 BC/DR 级保护
  • 完全丢失一个 Pool 会导致所有 Pool 的 I/O 停止
  • 建议通过 站点复制(Site Replication) 实现跨数据中心容灾

6.2 扩容方式

方式一:对等扩容(Pool Expansion)

最常用的扩容方式,要求新 Pool 的节点数/磁盘数与原集群对等(或为其倍数)。

示例:原集群 4 节点 × 4 磁盘,新增 4 节点 × 4 磁盘

# 原集群启动命令
minio server http://minio{1...4}.example.com:9000/data{1...4}

# 扩容后启动命令(在所有节点上同时更新并重启)
minio server   http://minio{1...4}.example.com:9000/data{1...4}   http://minio{5...8}.example.com:9000/data{1...4}

Docker Compose 扩容示例:

services:
  minio:
    image: minio/minio:latest
    command: >
      server
      http://minio1:9000/data{1...4}
      http://minio2:9000/data{1...4}
      http://minio3:9000/data{1...4}
      http://minio4:9000/data{1...4}
      http://minio5:9000/data{1...4}
      http://minio6:9000/data{1...4}
      http://minio7:9000/data{1...4}
      http://minio8:9000/data{1...4}
      --console-address ":9001"

Kubernetes 扩容示例(使用 MinIO Operator):

apiVersion: minio.min.io/v2
kind: Tenant
metadata:
  name: minio
  namespace: minio-tenant
spec:
  pools:
  - servers: 4
    name: pool-0
    volumesPerServer: 4
    volumeClaimTemplate:
      spec:
        resources:
          requests:
            storage: 100Gi
  # 新增 Pool
  - servers: 4
    name: pool-1
    volumesPerServer: 4
    volumeClaimTemplate:
      spec:
        resources:
          requests:
            storage: 200Gi

应用后,新对象会自动分配到 pool-1。

方式二:联邦扩容(Federation)

通过引入 etcd 将多个 MinIO 集群在逻辑上组成联邦,对外提供统一命名空间。

优点:

  • 各集群不要求节点数/磁盘数对等
  • 可以无限扩展
  • 单集群故障不影响其他集群

缺点:

  • 需要额外部署 etcd 集群
  • 配置复杂度较高

💡 建议:若数据量增长较快、扩容频繁,建议在首次部署时就引入联邦模式。

6.3 数据重平衡

扩容后,已有对象不会自动迁移到新 Pool。如需重新分布,可手动执行:

# 查看重平衡状态
mc admin rebalance myminio

# 启动重平衡
mc admin rebalance start myminio

# 监控进度
mc admin rebalance status myminio

6.4 扩容最佳实践

  1. 提前规划:首次部署时预留扩容空间,选择可扩展的架构
  2. 硬件一致:新节点硬件配置(CPU、内存、磁盘类型)尽量与原集群一致
  3. 网络带宽:确保节点间网络带宽充足,以支持 Healing 和 Rebalance
  4. 监控驱动器健康:及时更换故障磁盘,避免进入危险状态
  5. 节点上限:单个集群节点数建议不超过 32 个,避免分布式锁性能问题

七、总结

维度建议
开发测试Docker Compose 单机单盘 或 K8s EC:0 单机多盘
小规模生产Docker Compose 单机多盘 + EC:2
生产高可用K8s 分布式 4×4 磁盘 + EC:4
大规模生产K8s Operator + 多 Pool + 站点复制
纠删码生产环境至少 EC:3,推荐 EC:4
扩容使用 Pool Expansion,保持节点/磁盘对等

MinIO 以其极简的设计、卓越的性能和云原生特性,成为私有对象存储的首选方案。通过合理配置纠删码和规划扩容策略,可以构建既安全又灵活的存储基础设施。


参考资源