开源分布式对象存储-Minio

1,062 阅读3分钟
  • 项目中大多会遇到文件上传需求,通常我们会将一些图片、视频、文档等数据上传并存储在对象存储中
  • 目前市面上用到的对象存储大多是阿里云的OSS(收费)、FastDFS(自己搭建繁琐)等
  • 这里给大家分享一个搭建简单,使用方便,基于Apache License v2.0开源协议的对象存储系统,完全兼容Amazon S3接口的开源分布式对象存储-Minio。

1.简介

Minio对象存储系统是为海量数据存储、人工智能、大数据分析而设计,基于Apache License v2.0开源协议的对象存储系统,它完全兼容Amazon S3接口,单个对象最大可达5TB,适合存储海量图片、视频、日志文件、备份数据和容器/虚拟机镜像等。Minio主要采用Golang语言实现,整个系统都运行在操作系统的用户态空间,客户端与存储服务器之间采用http/https通信协议。

2.安装

2.1.使用Docker安装Minio

linux安装Docker可以参考我之前的文章:Linux安装Docker

2.1.1.拉取minio(最新版本坑多还不好用)

输入命令拉取minio老版本:

docker pull minio/minio:RELEASE.2021-06-17T00-10-46Z

使用命令 docker images 查看下载好的镜像。 image.png

2.1.2.启动minio(这里介绍的是单点启动)

请运行以下命令:

docker run -p 9000:9000 minio/minio:RELEASE.2021-06-17T00-10-46Z server /data

打开新的linux界面,查看minio服务是否启动,输入命令:

docker ps

image.png

2.1.3.访问minio

ip + 9000 image.png image.png

2.1.4.MinIO自定义Access和Secret密钥

访问需要登录用户与秘钥,由于之前的minio运行命令太过简单,没有设置用户名、秘钥,所以要覆盖MinIO的自动生成的密钥,可以自己设置Access Key和Secret Key密钥:(命令加入 '-d' 表示后台运行)

docker run -d -p 9000:9000 --name minio\
  -e "MINIO_ACCESS_KEY=minioadmin" \
  -e "MINIO_SECRET_KEY=minioadmin" \
  -v /usr/local/minio/data:/data \
  -v /usr/local/minio/config:/root/.minio \
  minio/minio:RELEASE.2021-06-17T00-10-46Z server /data
/usr/local/minio/data   //数据卷存放路径
/usr/local/minio/config //服务配置文件

使用自己创建的用户、密码登录minio: image.png Unbelievable !!!!!! image.png

3.使用

3.1.springboot项目中使用minio存储数据

3.1.1.引入minio的maven依赖

<!-- MiniO依赖 -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.1</version>
</dependency>

3.1.2.在yml配置连接minio的地址、用户名、密码、存储桶名(上传文件所在的文件夹)

# minio链连接配置
minio:
  endpoint: http://192.168.56.10:9000
  accessKey: minioadmin
  secretKey: minioadmin
  bucketName: images

3.1.3.上传接口实现

import com.zhizai.cimzfbz.common.result.R;
import io.minio.*;
import io.minio.http.Method;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Api(tags = "minio存储")
@RestController
@RequestMapping("/minio")
public class MinioController {

    private static final Logger LOGGER = LoggerFactory.getLogger(MinioController.class);
    private static final String policyJson = "{"Version":"2012-10-17","Statement":" +
            "[{"Action":["s3:GetBucketLocation","s3:ListBucket","s3:ListBucketMultipartUploads"]," +
            ""Effect":"Allow","Principal":{"AWS":["*"]},"Resource":["arn:aws:s3:::test"]," +
            ""Sid":""},{"Action":["s3:AbortMultipartUpload","s3:DeleteObject","s3:GetObject"," +
            ""s3:ListMultipartUploadParts","s3:PutObject"],"Effect":"Allow","Principal":{"AWS":["*"]}," +
            ""Resource":["arn:aws:s3:::test/*"],"Sid":""}]}";
    @Value("${minio.endpoint}")
    private String ENDPOINT;
    @Value("${minio.bucketName}")
    private String BUCKET_NAME;
    @Value("${minio.accessKey}")
    private String ACCESS_KEY;
    @Value("${minio.secretKey}")
    private String SECRET_KEY;

    @ApiOperation("文件上传")
    @PostMapping(value = "/upload")
    public R upload1(@ApiParam(name = "file", value = "文件", required = true) @RequestParam MultipartFile file) {
        try {
            //创建一个Minio的Java客户端
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint(ENDPOINT)
                            .credentials(ACCESS_KEY, SECRET_KEY)
                            .build();
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET_NAME).build());
            if (found) {
                LOGGER.info("存储桶已经存在!");
            } else {
                //创建存储桶并设置只读权限
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build());
                minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(BUCKET_NAME).config(policyJson).build());
            }
            String filename = file.getOriginalFilename();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + "/" + filename;
            // 使用putObject上传一个文件到存储桶中
            minioClient.putObject(PutObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).stream(
                    file.getInputStream(), -1, 10485760)
                    .contentType(file.getContentType())
                    .build());
            LOGGER.info("文件上传成功!");
            //文件访问路径
            String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs
                    .builder()
                    .method(Method.GET)
                    .bucket(BUCKET_NAME)
                    .object(objectName)
                    .expiry(2, TimeUnit.HOURS)
                    .build());
            //返回可以下载上传文件的访问路径
            return R.ok().data("url", url).data("name", objectName).message("文件上传成功!");
        } catch (Exception e) {
            LOGGER.info("上传发生错误: {}!", e.getMessage());
            return R.error().message("上传发生错误!");
        }
    }


    @ApiOperation("文件删除")
    @DeleteMapping(value = "/delete")
    public R delete(@RequestParam("objectName") String objectName) {
        try {
            //创建一个Minio的Java客户端
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint(ENDPOINT)
                            .credentials(ACCESS_KEY, SECRET_KEY)
                            .build();
       minioClient.removeObject(RemoveObjectArgs.builder().bucket(BUCKET_NAME).object(objectName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return R.ok().message("文件删除失败");
        }
        return R.ok().message("文件删除成功");
    }

}

推荐大家去阅读官方文档,学习更多技能:docs.minio.org.cn/docs/master…

大功告成ヽ( ̄▽ ̄)و