使用MinIO搭建对象存储服务
1.MinIO是什么?
- MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。
- MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。
- MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。
2.我这里使用的是docker安装方式,使用的前提是小伙伴你已经安装好了一个docker了,关于docker的具体使用可以参考docker的具体使用
3.使用步骤
(1)下载镜像,下载可能有点慢大家等待一下或者配置一下阿里云镜像***
docker run -d -p 9000:9000 -p 9001:9001 --name minio -e MINIO_ACCESS_KEY=qbb -e MINIO_SECRET_KEY=startqbb -v /opt/minio/data:/data -v /opt/minio/config:/root/.minio minio/minio server /data --console-address ":9000" --address ":9001"
- MINIO_ACCESS_KEY:指定的是"用户名",可以这么理解,后面我们文件上传需要使用
- MINIO_SECRET_KEY:指定的是"密码",可以这么理解,后面我们文件上传需要使用
下载并运行完成
注意:
- 有可能下载的过程中会出现如下图,minio容器并没有正常启动 docker ps -a:查看所有容器
- 我们可以使用docker logs 容器ID(CONTAINERID)查看一下容器的日志
- 可以看出数data目录没有权限,执行如下命令在启动试试 chmod 777 /opt/minio/data:设置目录权限为可读可写可执行
docker start 容器ID:启动容器
(2)我们先在浏览器访问一下http://192.168.137.72:9000/
(3)我们在minio中创建一个bucket
(4)接下来我们创建一个SpringBoot项目
(5)导入相关的依赖
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.qbb</groupId> <artifactId>springboot-minio</artifactId> <version>1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version> </dependency> <!--swagger ui--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.3.0</version> </dependency> </dependencies></project>
(6)修改application.yml配置文件
server: port: 7200spring: application: name: minioapp: minio: endpoint: http://192.168.137.72:9001 accessKey: qbb secretKey: startqbb bucket: qbb
注意:9000是我们浏览器访问控制台的端口,而9001是SDK代码操作的端口
(7)主启动类
package com.qbb.minio;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;/** * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit) * @version 1.0 * @date 2022-05-20 15:45 * @Description: */@SpringBootApplicationpublic class MinioApplication { public static void main(String[] args) { SpringApplication.run(MinioApplication.class, args); }}
(8)这里我配置一个swagger2方便测试,还配置了一个minio的配置类绑定配置文件信息,具体配置如下
package com.qbb.minio.config;import com.google.common.base.Predicates;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/** * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit) * @version 1.0 * @date 2022-05-20 16:23 * @Description:swagger配置类 */@Configuration@EnableSwagger2public class Swagger2Config { @Bean public Docket adminApiConfig() { return new Docket(DocumentationType.SWAGGER_2) .groupName("minioApi") .apiInfo(adminApiInfo()) .select() //只显示admin路径下的页面 .paths(Predicates.and(PathSelectors.regex("/minio/.*"))) .build(); } private ApiInfo adminApiInfo() { return new ApiInfoBuilder() .title("minio-API文档") .version("1.0") .contact(new Contact("QIUQIU&LL", "https://www.cnblogs.com/qbbit", "startqbb@163.com")) .build(); }}package com.qbb.minio.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Configuration;/** * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit) * @version 1.0 * @date 2022-05-20 18:57 * @Description: */@ConfigurationProperties(prefix = "app.minio")@EnableConfigurationProperties@Configuration@Datapublic class MinioConfig { private String endpoint; private String accessKey; private String secretKey; private String bucket;}
编写测试代码
package com.qbb.minio.controller;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit) * @version 1.0 * @date 2022-05-20 16:23 * @Description: */@Api(tags = "minio文件管理")@RestController@RequestMapping("/minio")public class FileController { @ApiOperation("测试程序") @GetMapping("/hello") public String hello() { return "hello"; }}
(10)接下来我们编写文件上传代码
package com.qbb.minio.controller;import com.qbb.minio.config.MinioConfig;import io.minio.MinioClient;import io.minio.PutObjectOptions;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;import java.util.UUID;/** * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit) * @version 1.0 * @date 2022-05-20 16:23 * @Description: */@Api(tags = "minio文件管理")@RestController@RequestMapping("/minio")public class FileController { @Autowired private MinioConfig minioConfig; @ApiOperation("测试程序") @GetMapping("/hello") public String hello() { return "hello"; } @ApiOperation("文件上传") @PostMapping("/fileUpload") public String fileUpload(MultipartFile file) { /** * 这里应该放在service层处理的,将上传的文件路径存入数据库,我就不这么麻烦了,直接返回给前端 */ String bucket = minioConfig.getBucket(); String endpoint = minioConfig.getEndpoint(); String accessKey = minioConfig.getAccessKey(); String secretKey = minioConfig.getSecretKey(); // 1.获取文件名 String originalFilename = file.getOriginalFilename(); // 2.修改文件名,防止上传重复文件名,导致文件覆盖 String fileName = UUID.randomUUID().toString().replace("-", "") + "_" + originalFilename; // 文件流 try (InputStream inputStream = file.getInputStream()) { // 3.使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象 MinioClient minioClient = new MinioClient(endpoint, accessKey, secretKey); // 4.检查存储桶是否已经存在 boolean isExist = minioClient.bucketExists(bucket); if (isExist) { System.out.println("Bucket already exists"); } else { // 不存在则创建一个名为bucket的存储桶,用于存储照片的zip文件。 minioClient.makeBucket(bucket); } // 6.上传参数设置项 PutObjectOptions options = new PutObjectOptions(inputStream.available(), -1); // 7.设置此次上传的文件的内容类型 String contentType = file.getContentType(); options.setContentType(contentType); // 8.上传 minioClient.putObject(bucket, fileName, inputStream, options); // 9.访问路径 String url = endpoint + "/" + bucket + "/" + fileName; return url; } catch (Exception e) { e.printStackTrace(); return null; } }}
(11)使用Swagger测试一下
(12)结果
- swagger
- minio控制台
(13)删除minio中的文件
@ApiOperation("删除文件") @DeleteMapping("/remove") public boolean remove() { try { // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象 MinioClient minioClient = new MinioClient(minioConfig.getEndpoint(), minioConfig.getAccessKey(), minioConfig.getSecretKey()); // 从bucket中删除文件(文件名)。 minioClient.removeObject(minioConfig.getBucket(), "ed8aa56a8ec640d6a36a271ed4222605_xiaomi.png"); System.out.println("successfully removed mybucket/myobject"); return true; } catch (Exception e) { System.out.println("Error: " + e); return false; } }
(14)删除后的结果
- swagger
- minio控制台
(15)注意:我们配置完了,启动我们的项目可能会出现这么一个错误,说我们的请求时间与服务器时间相差太大
(16)解决办法,linux控制台
yum -y install ntp ntpdate:安装插件工具
hwclock --systohc:同步时间
docker restart minio镜像ID:重启镜像