Minio的使用教程
Minio介紹
Minlo是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù)。它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù),例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機(jī)鏡像等,而一個對象文件可以是任意大小,從幾kb到最大5T不等。 對于中小型企業(yè),如果不選擇存儲上云,那么 MinIO 是個不錯的選擇,麻雀雖小,五臟俱全。當(dāng)然 MinIO 除了直接作為對象存儲使用,還可以作為云上對象存儲服務(wù)的網(wǎng)關(guān)層,無縫對接到 Amazon S3 等。
優(yōu)點:
- 部署簡單:一個single二進(jìn)制文件即是一切,還可支持各種平臺。
- Minio支持海量存儲,可按zone擴(kuò)展(原zone不受任何影響),支持單個對象最大5TB;
- 兼容Amazon S3接口,充分考慮開發(fā)人員的需求和體驗;
- 讀寫性能優(yōu)異
Minio基礎(chǔ)概念
| 概念名稱 | 對應(yīng)含義解釋 |
|---|---|
Object | 存儲的基本對象;比如文件、圖片等等 |
Bucket | 用于存儲 Object 的邏輯空間;相互之間互相隔離;類似于系統(tǒng)中的頂層文件夾 |
Drive | 即存儲數(shù)據(jù)的磁盤;所有的對象數(shù)據(jù)都會存儲在 Drive 里面 |
Set | 即一組 Drive 的集合;分布式部署根據(jù)集群規(guī)模自動劃分一個或多個 Set |
Linux安裝Minio
1.獲取minio安裝包
wget https://dl.min.io/server/minio/release/linux-amd64/archive/minio-20241029160148.0.0-1.x86_64.rpm -O minio.rpm

2.安裝minio
rpm -ivh minio.rpm

Minio配置
1.修改minio服務(wù)配置文件
vim /usr/lib/systemd/system/minio.service
注釋Type、User、Group
修改后的文件如下:
[Unit] Description=MinIO Documentation=https://docs.min.io Wants=network-online.target After=network-online.target AssertFileIsExecutable=/usr/local/bin/minio [Service] #Type=notify WorkingDirectory=/usr/local #User=minio-user #Group=minio-user ProtectProc=invisible EnvironmentFile=-/etc/default/minio ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES Restart=always LimitNOFILE=1048576 MemoryAccounting=no TasksMax=infinity TimeoutSec=infinity SendSIGKILL=no [Install] WantedBy=multi-user.target
參數(shù)解釋:
AssertFileIsExecutable:可以在此參數(shù)聲明的配置文件中添加minio服務(wù)啟動時所需一些參數(shù)
ExecStart:該參數(shù)用于配置Minio服務(wù)的啟動命令,其中$MINIO_OPTS、$MINIO_VOLUMES,均引用于EnvironmentFile中的變量。
Restart:設(shè)置服務(wù)在失敗時自動重啟,這里是always,意味著總是重啟。
2.配置
1.編寫EnvironmentFile中指定路徑下的配置文件
vim /etc/default/minio
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
MINIO_VOLUMES=/data
MINIO_OPTS="--console-address :9001"
解釋:
MINIO_ROOT_USER:登錄后臺管理平臺的用戶名
MINIO_ROOT_PASSWORD:登錄后臺管理平臺的密碼
MINIO_VOLUMES:指定數(shù)據(jù)存儲路徑,需確保指定的路徑是存在的
MINIO_OPTS:指定管理頁面的地址的端口號
2.創(chuàng)建minio數(shù)據(jù)存儲路徑
mkdir /data
3.防火墻設(shè)置開放端口
#開放minio的9000和9001端口
firewall-cmd --zone=public --add-port=9000/tcp --add-port=9001/tcp --permanent
#重新加載防火墻規(guī)則
firewall-cmd --reload
#查看開放的端口
firewall-cmd --list-ports
4.讓systemctl檢查配置并重新加載系統(tǒng)服務(wù)的配置文件
systemctl daemon - reload
#設(shè)置minio服務(wù)自啟動
systemctl enable minio
#啟動minio服務(wù)
systemctl start minio
#查看minio服務(wù)狀態(tài)
systemctl status minio
Minio后臺管理系統(tǒng)使用
賬號密碼就是etc/default/minio文件里面配置的MINIO_ROOT_USER和MINIO_ROOT_PASSWORD


介紹
存儲桶管理界面介紹

Access Policy:訪問策略
- public:允許所有人對該存儲桶進(jìn)行讀寫操作
- private:只允許所有者操作該存儲桶,其他人不能讀寫該存儲桶
- custom:自定義存儲桶的訪問權(quán)限,如:只允許所有者寫,但允許所有人讀,自定義訪問權(quán)限有格式要求,格式為JSON
Encryption:加密策略,可選值:Disabled、SSE-S3、SSE-KMS
Reported Usage:存儲桶使用情況,即使用的內(nèi)存大小
Quota:配置存儲桶限制的數(shù)據(jù)量
Browse Bucket:瀏覽存儲桶列表
存儲桶列表界面
介紹

Upload File:上傳文件
Upload Folder:上傳文件夾
Refresh:刷新
Download:下載文件
Share:共享圖片(可以設(shè)置共享的連接的時效性)

Preview:查看圖片
Delete:刪除圖片
Object Info:對象信息,包含了名稱、大小、上次修改時間、內(nèi)容類型等等信息
文件上傳
創(chuàng)建
1.創(chuàng)建存儲桶


創(chuàng)建時可選值
Bucket Name:存儲桶名稱
Versioning:允許在同一鍵下保留同一對象的多個版本。
Object Locking:確保一旦對象存儲在特定的存儲桶中,它們就不能被刪除,這是為了滿足數(shù)據(jù)保留和法律保留的要求。這種特性或策略只能在創(chuàng)建存儲桶的時候設(shè)置,一旦存儲桶被創(chuàng)建,就不能再對這個特性進(jìn)行更改。
Quota:限制存儲桶中的數(shù)據(jù)量。
2.上傳圖片
1.選擇Upload File

2.選擇要上傳的文件

3.上傳后可以看到界面的右上角有文件的上傳進(jìn)度

訪問上傳的圖片
訪問minio的存儲桶的圖片的url格式就是
首先在存儲桶瀏覽列表復(fù)制存儲桶中文件的路徑

然后再URL打上自己的Minio服務(wù)的主機(jī)IP加上端口號最后拼接上我們復(fù)制的文件地址
192.168.181.31:9000/test/房間-臥室-1.jpg

訪問報錯?

原因分析:因為我們的存儲桶的訪問權(quán)限為私有的所以我們訪問不了這個存儲桶中的圖片\文件,所以我們要修改訪問權(quán)限
步驟:
1.點擊存儲桶瀏覽列表右上角的設(shè)置

2.編輯存儲桶的訪問權(quán)限,我們選擇自定義權(quán)限

再存儲桶管理界面介紹中就介紹到了存儲桶的訪問權(quán)限,所以這里我們選擇自定義,權(quán)限為:只允許所有者寫,但允許所有人讀,但是
自定義訪問權(quán)限,需要使用一個規(guī)定格式的JSON字符串進(jìn)行描述,具體格式可參考官方文檔。
如:允許(Allow)所有人(*)讀取(s3:GetObject)指定桶(test)的所有內(nèi)容
{
"Statement" : [ {
"Action" : "s3:GetObject",
"Effect" : "Allow",
"Principal" : "*",
"Resource" : "arn:aws:s3:::test/*"
} ],
"Version" : "2012-10-17"
}
按照上圖片進(jìn)行配置之后,再去訪問圖片,就可以正常訪問了

Minio Java SDK使用
Minio提供了多種語言的SDK供開發(fā)者使用,具體內(nèi)容可參考官方文檔。
1. 在Spring Boot項目的pom中引入Minio依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>創(chuàng)建一個類方法測試,然后執(zhí)行查看是否上傳成功
public class App {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
try {
//構(gòu)造MinIO Client
MinioClient minioClient = MinioClient.builder()
.endpoint("http://192.168.10.101:9000")//填寫你的地址
.credentials("minioadmin", "minioadmin")//填寫你的賬號、密碼
.build();
//創(chuàng)建hello-minio桶
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket("hello-minio").build());
if (!found) {
//創(chuàng)建hello-minio桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket("hello-minio").build());
//設(shè)置hello-minio桶的訪問權(quán)限
//JDK15之后的特性,三引號
String policy = """
{
"Statement" : [ {
"Action" : "s3:GetObject",
"Effect" : "Allow",
"Principal" : "*",
"Resource" : "arn:aws:s3:::hello-minio/*"
} ],
"Version" : "2012-10-17"
}""";
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket("hello-minio").config(policy).build());
} else {
System.out.println("Bucket 'hello-minio' already exists.");
}
//上傳圖片
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket("hello-minio")
.object("公寓-外觀.jpg")
.filename("D:\\workspace\\hello-minio\\src\\main\\resources\\公寓-外觀.jpg")
//這個文件填寫你電腦要上傳的圖片的路徑
.build());
System.out.println("上傳成功");
} catch (MinioException e) {
System.out.println("Error occurred: " + e);
}
}
}如果使用的JDK版本不高與15的話可以用這一段代替
String policy = "{\n" +
" \"Statement\" : [ {\n" +
" \"Action\" : \"s3:GetObject\",\n" +
" \"Effect\" : \"Allow\",\n" +
" \"Principal\" : \"*\",\n" +
" \"Resource\" : \"arn:aws:s3:::hello-minio/*\"\n" +
" } ],\n" +
" \"Version\" : \"2012-10-17\"\n" +
"}";2. 在application.yml或properties中添加Minio配置參數(shù)
#項目名
server:
servlet:
context-path: /minioDemo
minio:
endpoint: http://192.168.181.29:9000 #minio地址
access-key: minioadmin #用戶名
secret-key: minioadmin #密碼
bucket-name: lease #存儲的minio名稱(自定義)3. 創(chuàng)建Minio配置類和配置參數(shù)類
3.1. 創(chuàng)建配置類MinioConfiguration
@Configuration
@EnableConfigurationProperties(MinioProperties.class)//單個配置參數(shù)類掃描
//@ConfigurationPropertiesScan("com.waitforme.lease.common.minio")掃描一個路徑下的所有配置參數(shù)類
//@EnableConfigurationProperties、@ConfigurationPropertiesScan兩個注解的作用都是為了注冊配置參數(shù)類,根據(jù)需要使用其一即可
public class MinioConfiguration {
@Autowired
private MinioProperties properties;
@Bean
public MinioClient minioClient() {
return MinioClient
.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.build();
}
}3.2. 創(chuàng)建一個配置參數(shù)類
因為配置類中需要用到之前第二步添加的Minio的配置參數(shù),所以創(chuàng)建它
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
}注意:如果出現(xiàn)了如圖的錯誤提示,是因為你沒有在配置類中注冊配置參數(shù)類,所以要先進(jìn)行注冊,在MinioConfiguration類上加上@EnableConfigurationProperties或@ConfigurationPropertiesScan注解進(jìn)行注冊

4.創(chuàng)建FileService接口及其實現(xiàn),實現(xiàn)圖片獲取、上傳、刪除邏輯
service
public interface FileService {
//圖片上傳
String upload(MultipartFile file) throws Exception;
//獲取圖片列表
List<String> getListObjects() throws Exception;
//刪除單個圖片
Boolean deleteObject(String fileName) throws Exception;
}serviceImpl
@Service("fileService")
public class FileServiceImpl implements FileService {
@Autowired
MinioClient minioClient;
@Autowired
MinioProperties properties;
@Override
public String upload(MultipartFile file) throws Exception {
boolean bucketExists = minioClient.bucketExists(
BucketExistsArgs.builder()
.bucket(properties.getBucketName()).build());
if (!bucketExists) {
//判斷minio中是否存在我們配置的存儲桶名稱
minioClient.makeBucket(MakeBucketArgs.builder().bucket(properties.getBucketName()).build());
//創(chuàng)建存儲桶
minioClient.setBucketPolicy(
SetBucketPolicyArgs.builder()
.bucket(properties.getBucketName())
.config(createBucketPolicyConfig(properties.getBucketName())).build());
//為創(chuàng)建的存儲桶設(shè)置訪問權(quán)限
}
String fileName = UUID.randomUUID() + "-" + file.getOriginalFilename();
//上傳的文件名
minioClient.putObject(PutObjectArgs.builder()
.bucket(properties.getBucketName())
//上傳的存儲桶名稱
.stream(file.getInputStream(), file.getSize(), -1)
/*上傳的文件,三個參數(shù)分別表示:
1. 上傳的文件io流
2. 上傳的文件大小
3. -1表示我們確定了自己要上傳的文件大小后,讓minio自己自動去分配每次上傳的大小,因為minio不是一次性刪除而是分片上傳*/
.object(fileName)
//上傳后的文件名
.contentType(file.getContentType())
//上傳文件類型,通過file.getContentType獲取,因為不設(shè)置的話就是steam類型,訪問的時候會下載圖片,而不是預(yù)覽圖片
.build());
//上傳文件
return String.join("/", properties.getEndpoint(), properties.getBucketName(), fileName);
//join方法用于通過指定一個分割符,將傳入的的參數(shù)拼接成一串字符,可以傳入多個參數(shù)
}
/**
* 獲取圖片列表
* @return 返回處理完的圖片數(shù)組列表
* @throws Exception 直接拋出最大的異常類
*/
@Override
public List<String> getListObjects() throws Exception {
List<String> objectNames = new ArrayList<>();
//創(chuàng)建一個數(shù)組用于存儲獲取到的圖片
Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder()
.bucket(properties.getBucketName())
.build());
//獲取指定存儲桶中的圖片列表
for (Result<Item> result : results) {
Item item = result.get();
objectNames.add(String.join("/", properties.getEndpoint(), properties.getBucketName(), item.objectName()));
//遍歷得到的數(shù)組,并通過指定為:http://xxx.xxx.xxx.xx:9000/bucketName/fileName.jpg的格式到數(shù)組中
}
return objectNames;
}
/**
* 刪除存儲桶中的單個圖片
* @param fileName 圖片名稱包括后綴
* @return 直接返回ture
* @throws Exception
*/
@Override
public Boolean deleteObject(String fileName) throws Exception {
minioClient.removeObject(RemoveObjectArgs.builder()
.bucket(properties.getBucketName())
.object(fileName)
.build());
return true;
}
/**
* @param bucketName 存儲桶名稱
* @return 返回存儲桶的訪問權(quán)限JSON字符串
* 返回值表示允許所以人讀取該存儲桶下的所有文件,沒有設(shè)置寫權(quán)限是因為默認(rèn)創(chuàng)建人就是寫權(quán)限擁有者
* 其中resource中的%s表示占位符,.formatted中的就是占位符的值
*/
private String createBucketPolicyConfig(String bucketName) {
//三引號是jdk15添加的新功能
return """
{
"Statement" : [ {
"Action" : "s3:GetObject",
"Effect" : "Allow",
"Principal" : "*",
"Resource" : "arn:aws:s3:::%s/*"
} ],
"Version" : "2012-10-17"
}
""".formatted(bucketName);
}
}如果使用的JDK版本低于15可以用這段代替createBucketPolicyConfig方法里面的代碼
private String createBucketPolicyConfig(String bucketName) {
String policy = String.format(
"{\n" +
" \"Statement\" : [ {\n" +
" \"Action\" : \"s3:GetObject\",\n" +
" \"Effect\" : \"Allow\",\n" +
" \"Principal\" : \"*\",\n" +
" \"Resource\" : \"arn:aws:s3:::%s/*\"\n" +
" } ],\n" +
" \"Version\" : \"2012-10-17\"\n" +
"}", bucketName);
return policy;
}5.創(chuàng)建Controller
@Controller
public class MinioController {
@Autowired
MinioService minioService;
@RequestMapping("/upload")
public String upload(@RequestParam MultipartFile file, Model model) {
try {
String url = minioService.upload(file);
model.addAttribute("url", url);
model.addAttribute("msg", "上傳成功");
} catch (Exception e) {
model.addAttribute("msg", "上傳失敗:" + e.getMessage());
}
return "redirect:/list";
}
@RequestMapping({"/list", ""})
public String getListObjects(Model model) throws Exception {
List<String> listObjects = minioService.getListObjects();
model.addAttribute("listObjects", listObjects);
model.addAttribute("msg", listObjects == null ? "獲取圖片失敗或是沒有圖片" : "");
return "index";
}
@RequestMapping("/remove")
@ResponseBody
public Object removeObject(@RequestParam String fileName) {
Map map = null;
try {
Boolean flag = minioService.deleteObject(fileName);
map = new HashMap();
map.put("flag", flag);
map.put("msg", "刪除成功");
} catch (Exception e) {
map.put("msg", "刪除失敗:" + e.getMessage());
return map;
}
return map;
}
}6.在templates中創(chuàng)建index.html頁面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style type="text/css">
ul{
list-style-type: none;
}
ul>li{
margin: 20px;
}
</style>
<body>
<div align="center">
<h1>minio的增刪改查示例</h1>
<form th:action="@{/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">上傳圖片</button>
</form>
</div>
<div align="center">
<h2 align="center">已上傳的圖片</h2>
<ul>
<li th:each="object : ${listObjects}">
<img th:src="@{${object}}" alt="11" width="450px" height="230px">
<a href="#" th:onclick="del(this,[[${object}]]);" style="padding-left: 100px">刪除</a>
</li>
</ul>
<p id="msg" style="color: red" align="center">[[${msg}]]</p>
</div>
</body>
<script th:src="@{/js/jquery-1.12.4.js}" type="text/javascript"></script>
<script type="text/javascript">
function del(obj, url) {
if (confirm("確認(rèn)要刪除嗎?")) {
var parts = url.split("/");
var fileName = parts[parts.length - 1];
$.getJSON("remove", "fileName=" + fileName, function (data) {
if (data.flag) {
$(obj).parents("li").remove();
}
$("#msg").html(data.msg);
})
}
}
</script>
</html>然后,在static中創(chuàng)建js文件夾放入 jquery-1.12.4.js
頁面效果

遇到的錯誤
獲取圖片信息報錯?

報錯原因:因為物理機(jī)的請求時間跟服務(wù)器的時間相差太大了,簡單說就是要同步一下虛擬機(jī)的時間
解決步驟:
1.進(jìn)入虛擬機(jī),點擊右上角序號1,然后點擊root,再點擊賬號設(shè)置

2.在彈出的窗口中選擇日期和時間,然后把自動設(shè)置日期和時間、自動設(shè)置時區(qū)打開,等待時間與物理機(jī)相同即可
注意:此方案需要有網(wǎng)絡(luò)才能實現(xiàn)

a標(biāo)簽用th:onclick="|del(this,${object})|"報錯500?

原因分析:應(yīng)該是thymeleaf的版本問題
解決方案:替換th:onclick="|del(this,${object})|"為th:onclick="del(this,[[${object}]]);"
<a href="#" th:onclick="del(this,[[${object}]]);" style="padding-left: 100px">刪除</a>到此這篇關(guān)于Minio的使用的文章就介紹到這了,更多相關(guān)Minio的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud+RocketMQ實現(xiàn)分布式事務(wù)的實踐
分布式事務(wù)已經(jīng)成為了我們的經(jīng)常使用的。所以我們來一步一步的實現(xiàn)基于RocketMQ的分布式事務(wù)。感興趣的可以了解一下2021-10-10
Java SimpleDateFormat中英文時間格式化轉(zhuǎn)換詳解
這篇文章主要為大家詳細(xì)介紹了Java SimpleDateFormat中英文時間格式化轉(zhuǎn)換,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12
Struts2返回json格式數(shù)據(jù)代碼實例
這篇文章主要介紹了Struts2返回json格式數(shù)據(jù)代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-04-04
Java中數(shù)組轉(zhuǎn)list的兩種簡單實現(xiàn)方式
這篇文章主要介紹了兩種將數(shù)組轉(zhuǎn)換為List的方法,兩種方法分別是使用Arrays.asList()方法和使用ArrayList構(gòu)造函數(shù),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-03-03
HotSpot的Java對象模型之Oop-Klass模型詳解
這篇文章主要介紹了HotSpot的Java對象模型之Oop-Klass模型詳解,在JVM層面,不僅Java類是對象,Java 方法也是對象, 字節(jié)碼常量池也是對象,一切皆是對象,JVM使用不同的oop-klass模型來表示各種不同的對象,需要的朋友可以參考下2023-08-08
SpringBoot大事務(wù)問題的常用優(yōu)化方案
大事務(wù)是指運(yùn)行時間比較長,操作的數(shù)據(jù)比較多的事務(wù)123,大事務(wù)的產(chǎn)生原因包括操作的數(shù)據(jù)比較多、大量的鎖競爭、事務(wù)中有其他非數(shù)據(jù)庫的耗時操作等,本文給大家總結(jié)了SpringBoot大事務(wù)問題的常用優(yōu)化方案,需要的朋友可以參考下2024-04-04
springboot多模塊化整合mybatis,mapper自動注入失敗問題及解決
這篇文章主要介紹了springboot多模塊化整合mybatis,mapper自動注入失敗問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01

