MinIO 入门实战:Docker 安装 + Spring Boot 文件上传(公有 / 私有)

文章目录

  • [一、MinIO 简介](#一、MinIO 简介)
  • [二、MinIO 的核心特点](#二、MinIO 的核心特点)
  • [三、Docker 安装 MinIO](#三、Docker 安装 MinIO)
  • 四、时间同步问题
  • [五、Spring Boot 文件上传到 MinIO](#五、Spring Boot 文件上传到 MinIO)
  • 六、总结

一、MinIO 简介

MinIO 是一个基于 Apache License v3.0 的开源对象存储服务,兼容 Amazon S3 API ,非常适合存储大规模 非结构化数据,例如:

  • 图片
  • 视频
  • 日志文件
  • 备份数据
  • 容器 / 虚拟机镜像

单个对象大小可从 KB 级别到最大 5TB

与传统的存储服务相比,MinIO 非常 轻量级 ,可以像 Redis、MySQL、Node.js 一样轻松集成到各种系统中。

👉 官方文档(英文):
https://docs.min.io/


二、MinIO 的核心特点

1. 高性能

在标准硬件环境下,MinIO 可达到:

  • 55 GB/s 读取速度
  • 35 GB/s 写入速度

非常适合高并发、大文件读写场景。

2. 高可扩展

  • 支持多个 MinIO 集群组成 联邦
  • 形成 全局命名空间
  • 支持跨数据中心部署

3. 云原生

  • 支持容器化部署
  • 可运行在 Kubernetes
  • 支持多租户

4. 完全兼容 Amazon S3

  • 支持 S3 v2 / v4 API

  • 可直接使用:

    • MinIO SDK
    • AWS SDK
    • AWS CLI

5. 多种后端存储

  • 本地文件系统
  • DAS / JBOD
  • NAS
  • Google Cloud Storage
  • Azure Blob Storage

6. SDK 与生态完善

支持多种语言 SDK:

  • Java
  • Python
  • Go 等

7. 事件与 Lambda 计算

支持通过 事件通知 触发 Lambda,兼容 AWS SNS / SQS,可对接:

  • Kafka
  • Redis
  • MySQL
  • Elasticsearch
  • WebHook 等

8. 纠删码机制(Erasure Code)

MinIO 使用 纠删码 + 校验和

即使丢失 一半磁盘(N/2),仍然可以恢复数据

这是基于数学算法的数据容错机制,极大提高了数据安全性。


三、Docker 安装 MinIO

1. 拉取镜像

bash 复制代码
docker pull minio/minio

2. 启动容器

bash 复制代码
docker run \
-p 9000:9000 \
-p 9001:9001 \
--name minio \
-d --restart=always \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=admin123456" \
-v /home/data:/data \
-v /home/config:/root/.minio \
minio/minio server /data --console-address ":9001"

3. 访问控制台

浏览器访问:

复制代码
http://IP:9001/minio/login

登录账号:

  • 用户名:admin
  • 密码:admin123456

四、时间同步问题

在上传文件时,如果 Linux 服务器时间与 Windows 时间不一致,可能会导致 MinIO 访问异常。

使用 NTP 同步时间

bash 复制代码
# 1. 安装 ntp
yum -y install ntp

# 2. 设置开机启动
systemctl enable ntpd

# 3. 启动服务
systemctl start ntpd

# 4. 设置时区
timedatectl set-timezone Asia/Shanghai

# 5. 启用 NTP
timedatectl set-ntp yes

# 6. 查看同步状态
ntpq -p

五、Spring Boot 文件上传到 MinIO

1. 控制器(Controller)

java 复制代码
package com.donglin.file.controller;


import com.donglin.file.entity.BucketType;
import com.donglin.file.service.FileUploadService;
import com.donglin.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;


@RestController
public class FileController {

    @Autowired
    private FileUploadService fileUploadService;

    @PostMapping("/upload/public")
    public String uploadPublic(@RequestParam MultipartFile file) {
        return fileUploadService.upload(file, BucketType.PUBLIC);
    }

    @PostMapping("/upload/private")
    public String uploadPrivate(@RequestParam MultipartFile file) {
        return fileUploadService.upload(file, BucketType.PRIVATE);
    }
}

2. Service 接口

java 复制代码
package com.donglin.file.service;

import com.donglin.file.entity.BucketType;
import org.springframework.web.multipart.MultipartFile;

public interface FileUploadService {

    String upload(MultipartFile file, BucketType aPrivate);
}

3. Service 实现类

java 复制代码
package com.donglin.file.service.impl;

import com.donglin.file.entity.BucketType;
import com.donglin.file.entity.MinioConstantProperties;
import com.donglin.file.service.FileUploadService;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.UUID;

@Service
public class FileUploadServiceImol implements FileUploadService {
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConstantProperties prop;

    @Override
    public String upload(MultipartFile file, BucketType bucketType) {

        try {
            // 1. 选择 bucket
            String bucket = bucketType == BucketType.PUBLIC
                    ? prop.getPublicBucket()
                    : prop.getPrivateBucket();

            // 2. 文件后缀
            String ext = FilenameUtils.getExtension(file.getOriginalFilename());

            // 3. 对象名(分目录)
            String objectName = String.format(
                    "%s/%s/%s.%s",
                    bucketType.name().toLowerCase(),
                    java.time.LocalDate.now(),
                    UUID.randomUUID().toString().replace("-", ""),
                    ext
            );

            // 4. 上传
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build()
            );

            // 5. public:返回直链
            if (bucketType == BucketType.PUBLIC) {
                return prop.getEndpointUrl()
                        + "/" + bucket
                        + "/" + objectName;
            }

            // 6. private:返回预签名 URL
            return minioClient.getPresignedObjectUrl(
                    io.minio.GetPresignedObjectUrlArgs.builder()
                            .method(io.minio.http.Method.GET)
                            .bucket(bucket)
                            .object(objectName)
                            .expiry(1 * 60)
                            .build()
            );

        } catch (Exception e) {
            throw new RuntimeException("文件上传失败", e);
        }
    }
}

4. MinIO 配置类

java 复制代码
package com.donglin.file.entity;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioConstantProperties {

    // MinIO 服务地址
    private String endpointUrl;

    // AccessKey
    private String accessKey;

    // SecretKey
    private String secretKey;

    // Bucket 名称
    private String bucketName;

    // public / private bucket
    private String publicBucket;
    private String privateBucket;
}
csharp 复制代码
package com.donglin.file.entity;

public enum BucketType {
    PUBLIC,
    PRIVATE
}

config配置类

csharp 复制代码
package com.donglin.file.config;

import com.donglin.file.entity.MinioConstantProperties;
import io.minio.MinioClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MinioConfig {

    @Bean
    public MinioClient minioClient(MinioConstantProperties prop) {
        return MinioClient.builder()
                .endpoint(prop.getEndpointUrl())
                .credentials(prop.getAccessKey(), prop.getSecretKey())
                .build();
    }
}

yml

csharp 复制代码
minio:
  endpoint-url: http://192.168.121.140:9000
  access-key: admin
  secret-key: admin123456
  public-bucket: sky-public
  private-bucket: sky-private
server:
  port: 9600

把sky-public设置成public公有

结果

公共存储,一直能看

私有存储,目前设置的只能看1分钟


六、总结

  • MinIO 是一个 高性能、轻量级、S3 兼容 的对象存储服务

  • 非常适合:

    • 微服务项目
    • 图片 / 音视频存储
    • 日志与备份系统
  • 使用 Docker + Spring Boot 可快速落地

  • 注意 服务器时间同步,否则容易踩坑

相关推荐
gAlAxy...1 天前
5 种 SpringBoot 项目创建方式
java·spring boot·后端
Ahtacca1 天前
解决服务间通信难题:Spring Boot 中 HttpClient 的标准使用姿势
java·spring boot·后端
better_liang1 天前
每日Java面试场景题知识点之-Docker容器化部署
java·docker·微服务·devops·容器化·企业级开发
悟空码字1 天前
SpringBoot整合Kafka,实现高可用消息队列集群
java·spring boot·后端
qq_12498707531 天前
基于springboot的仁和机构的体检预约系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·mysql·spring·毕业设计·计算机毕业设计
南山nash1 天前
Docker 网络详细讲解
运维·docker·容器
海鸥811 天前
K8S中使用 reloader 实现滚动升级
云原生·容器·kubernetes
meichao91 天前
springboot3.5.8集成websocket问题
网络·spring boot·websocket·网络协议
白驹过隙不负青春1 天前
Docker-compose部署java服务及前端服务
java·运维·前端·docker·容器·centos