使用MinIO搭建物件儲存服務

我也有夢想呀 發表於 2022-05-20

1.MinIO是什麼?

  • MinIO 是一款高效能、分散式的物件儲存系統. 它是一款軟體產品, 可以100%的執行在標準硬體。即X86等低成本機器也能夠很好的執行MinIO。
  • MinIO與傳統的儲存和其他的物件儲存不同的是:它一開始就針對效能要求更高的私有云標準進行軟體架構設計。因為MinIO一開始就只為物件儲存而設計。所以他採用了更易用的方式進行設計,它能實現物件儲存所需要的全部功能,在效能上也更加強勁,它不會為了更多的業務功能而妥協,失去MinIO的易用性、高效性。 這樣的結果所帶來的好處是:它能夠更簡單的實現局有彈性伸縮能力的原生物件儲存服務。
  • MinIO在傳統物件儲存用例(例如輔助儲存,災難恢復和歸檔)方面表現出色。同時,它在機器學習、大資料、私有云、混合雲等方面的儲存技術上也獨樹一幟。當然,也不排除資料分析、高效能應用負載、原生雲的支援。

之前我使用的是阿里雲OSS,想了解阿里雲OSS的小夥伴參考SpringBoot整合阿里雲OSS

2.我這裡使用的是docker安裝方式,使用的前提是小夥伴你已經安裝好了一個docker了,關於docker的具體使用可以參考docker的具體使用

image

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:指定的是"密碼",可以這麼理解,後面我們檔案上傳需要使用

image

下載並執行完成

image

注意:
  • 有可能下載的過程中會出現如下圖,minio容器並沒有正常啟動
    docker ps -a:檢視所有容器
    image

  • 我們可以使用docker logs 容器ID(CONTAINERID)檢視一下容器的日誌
    image

  • 可以看出數data目錄沒有許可權,執行如下命令在啟動試試
    chmod 777 /opt/minio/data:設定目錄許可權為可讀可寫可執行
    docker start 容器ID:啟動容器
    image

(2)我們先在瀏覽器訪問一下http://192.168.137.72:9000/

image

(3)我們在minio中建立一個bucket

(4)接下來我們建立一個SpringBoot專案

image

(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: 7200

spring:
  application:
    name: minio

app:
  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:
 */
@SpringBootApplication
public 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
@EnableSwagger2
public 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", "[email protected]"))
                .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
@Data
public class MinioConfig {

    private String endpoint;
    private String accessKey;
    private String secretKey;
    private String bucket;
}

(9)編寫測試程式碼

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";
    }

}

image

(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測試一下

image

(12)結果

  • swagger
    image

  • minio控制檯
    image

(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
    image

  • minio控制檯
    image

(15)注意:我們配置完了,啟動我們的專案可能會出現這麼一個錯誤,說我們的請求時間與伺服器時間相差太大

image

(16)解決辦法,linux控制檯

yum -y install ntp ntpdate:安裝外掛工具
hwclock --systohc:同步時間
docker restart minio映象ID:重啟映象

至此SpringBoot整合Minio實現檔案上傳完成,更多詳細的功能配置各位小夥伴可以參考minio官方