利用 MinIO 輕鬆搭建靜態資源服務
阿新 • • 發佈:2020-03-31
[toc]
> 如果想搭建一個優雅、簡單、功能完備的靜態資源服務,那就用MinIO吧。
# 1 引言
開發 Web 專案過程中,經常需要處理靜態資源(如圖片、視訊、音訊,js庫 ,css 庫等),一般來說,若專案中需要用到這些資原始檔,我們常用的有以下幾種方法:
- 本地儲存:即在專案工程中的 static 目錄下,建立 js/css/icon/font/image/lib/audio/video 等目錄,分別存放對應格式的資原始檔。使用時,在 html 檔案中使用相對位置引用進行。
- 使用代理搭建靜態資源服務:即把資源存放於某一檔案目錄,使用代理伺服器(如 nginx ,apache等)對目錄進行對映,構建成資源服務。使用時,在 html 檔案中使用代理服務的 url 地址進行引用。
- 使用第三方工具搭建靜態資源服務:使用第三方開源的檔案儲存或物件儲存工具,或者自己寫個程式實現可以獲取檔案的介面。使用時,使用對應的 url 地址或介面地址。
- 使用線上靜態資源服務:如阿里雲、CDN等服務。
對於本地儲存,缺點就很明顯,資源與程式碼檔案混合一起,沒有必要,而且不方便擴充套件。對於本地內部部署的應用,顯然是自己搭建靜態資源服務比較穩妥。對於使用代理服務和第三方工具,相比起來,代理服務僅做對映,雖然可用,但功能單一,僅做對映,沒有其它管理功能,也不方便擴充套件。使用第三方檔案或物件儲存工具,可以對檔案進行管理、也能考慮高擴充套件,高效能、高可用等因素,因此是很好的選擇,其中,MinIO 就是這樣一款好用的物件儲存工具,簡單,快捷而且功能完備。
本文則是通過對 MinIO 的安裝、配置與使用,構建靜態資源服務,從而把圖片、視訊、音訊,第三方 js 庫等資源獨立部署,訪問;還會對 MinIO 提供的 Java API 進行使用簡單介紹,以便於進一步開發。
# 2 MinIO 簡介
按 [MinIO](https://min.io/) 官方介紹,MinIO 是高效能的物件儲存(塊儲存、檔案儲存和物件儲存的區別,可參考[架構師都知道的分散式物件儲存解決方案](https://juejin.im/post/5cdc16e251882568651553f9)),相容 Amazon S3 介面,充分考慮開發人員的需求和體驗;支援分散式儲存,具備高擴充套件性、高可用性;部署簡單但功能豐富。官方的文件也很詳細。它有多種不同的部署模式(單機部署,分散式部署)。為什麼說 MinIO 簡單易用,原因就在於它的啟動、執行和配置都很簡單。可以通過 docker 方式進行安裝執行,也可以下載二進位制檔案,然後使用指令碼執行。
本文以最簡單的方式進行講解,在 linux 機器中,單機部署,執行二進位制檔案。
# 3 MinIO 執行與靜態資源使用
## 3.1 MinIO 獲取
[MinIO 開發文件](https://docs.min.io)中,下載地址如下:
- linux: `https://dl.min.io/server/minio/release/linux-amd64/minio`
- windows: `https://dl.min.io/server/minio/release/windows-amd64/minio.exe`
本文在 linux 中執行。
## 3.2 MinIO 啟動與執行
### 3.2.1 前臺簡單啟動
把下載的 minio 檔案存放到某個目錄作為執行目錄(如 /opt/minio),新建一個目錄(如/opt/minio-data)作為 minio 資料儲存位置,即可啟動,如下指令碼:
``` shell
cd /opt/minio
chmod +x minio
./minio server /opt/minio-data
```
啟動後會輸出訪問地址 endpoint 和對應的 access_key 和 secret_key,使用瀏覽器訪問 endpoint 地址,若可以訪問,則表示 minio 已經安裝成功。不過這樣啟動會有幾個缺點:
- 不是後臺執行,`ctrl+c` 就會結束程序,服務就停止
- 沒有自定義訪問的使用者名稱密碼
- 沒有指定訪問IP和埠
- 日誌沒有保留到檔案
針對這些問題,建議使用下面的方式進行啟動執行。
### 3.2.2 後臺指定引數執行
使用 `nohup` 在後臺執行程式,同時指定密碼引數,訪問地址引數和日誌輸出,如下所示。
```shell
MINIO_ACCESS_KEY=minio MINIO_SECRET_KEY=minio123 nohup /opt/minio/minio server --address "${MINIO_HOST}:${MINIO_PORT}" /opt/minio-data > /opt/minio/minio.log 2>&1 &
```
> `MINIO_ACCESS_KEY` 及 `MINIO_SECRET_KEY` 是訪問密碼
>
> `${MINIO_HOST}:${MINIO_PORT}` 分別是訪問的 host 和埠,請按實際情況修改。
這樣,通過瀏覽器訪問地址 `${MINIO_HOST}:${MINIO_PORT}` ,使用指定的 `MINIO_ACCESS_KEY` 及 `MINIO_SECRET_KEY` 登入即可。
### 3.2.3 建立 bucket 並指定訪問策略
在瀏覽器中登入到 MinIO 儲存系統,點選右下角建立 bucket 來儲存物件,分別建立對應的 bucket 以存放靜態資源:image,video,audio。這樣,就可以按資源型別在對應的 bucket 中進行檔案上傳了,上傳後可以把檔案分享,其它地方可以通過分享的 url 獲取資源,如下圖所示。
![分享檔案](https://gitee.com/mianshenglee/datastorage/raw/master/md-photo/20200331-minio/share-object.png)
MinIO 預設的策略是分享地址的有效時間最多是7天,要突破這種限制,可以在 bucket 中進行策略設定。點選對應的 bucket ,`edit policy` 新增策略 `*.*`,`Read Only`,如下:
![edit policy](https://gitee.com/mianshenglee/datastorage/raw/master/md-photo/20200331-minio/edit-policy.png)
如此就放開了訪問,沒有時間限制,同時只需要按`http://${MINIO_HOST}:${MINIO_PORT}/${bucketName}/${fileName}` 則可直接訪問資源(不需要進行分享操作)。
> 關於 MinIO 目錄的誤區
>
> - 其實對於物件儲存來說,其實不區分檔案還是目錄,所有檔案和目錄都是物件,即 image/temp/xxx.jpg 和 image/temp/ 都是物件。它跟作業系統的檔案系統的樹狀結構有本質區別。
> - 上傳檔案時,objectName 可以是 `/temp/xxx.jpg`,可以認為系統自動建立了temp目錄。
> - MinIO 不會提供像刪除目錄,同時刪除此目錄下所有檔案的操作(即 `rm -rf image/temp`),因此要想把目錄 image/temp 刪除,則需要先把以 image/temp 為字首的所有檔案刪除。
> - 查詢多個檔案時,可以使用字首匹配方式獲取,見 API 文件 `listObjects(bucketName, prefix, recursive)`
## 3.3 在 html 檔案中引用靜態資源
通過上面的設定與執行,MinIO 作為靜態資源伺服器已經完成,可以寫個 html 來引用 MinIO 中的靜態資源。如下是測試的 html 裡面的圖片、視訊、音訊均使用 MinIO 的資源地址。
``` html
```
可發現資源是可以正常載入訪問的。
# 4 Java 客戶端 API 操作
MinIO 對開發者是非常友好的,提供了各種語言的 API 操作介面,具體可以參考 [MinIO開發文件](https://docs.min.io/)。下面以 Java 為例做一下測試。
## 4.1 新增依賴
```xml
io.minio
minio
6.0.13
```
## 4.2 使用 Java API 進行檔案操作
建立 MinIO 的操作客戶端 `minioClient = new MinioClient(endpoint, accessKey, secretKey);`,引數中`endpoint` 是 MinIO 的訪問地址,後面兩對應啟動時設定的密碼。
### 4.2.1 上傳檔案
```java
/**
* 上傳檔案
* @param minioClient 操作客戶端
* @param bucketName 上傳的bucket名稱
* @param objectName 上傳後儲存在bucket中的檔名
* @param filePath 上傳的本地檔案路徑
*/
public void uploadFile(MinioClient minioClient, String bucketName, String objectName, String filePath) throws XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, IOException {
try {
// 若不存在bucket,則新建
boolean isExist = minioClient.bucketExists(bucketName);
if (!isExist) {
minioClient.makeBucket(bucketName);
}
// 使用 putObject 上傳檔案
minioClient.putObject(bucketName, objectName, filePath, null, null, null, null);
} catch (MinioException e) {
System.out.println("Error occurred: " + e);
}
}
```
### 4.2.2 下載檔案
```java
/**
* 下載檔案
*
* @param minioClient 操作客戶端
* @param bucketName 上傳的bucket名稱
* @param objectName 上傳後儲存在bucket中的檔名
* @param downloadPath 下載檔案儲存路徑
*/
public void downloadFile(MinioClient minioClient, String bucketName, String objectName, String downloadPath) throws XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, IOException {
File file = new File(downloadPath);
try (OutputStream out = new FileOutputStream(file)) {
InputStream inputStream = minioClient.getObject(bucketName, objectName);
byte[] tempbytes = new byte[1024];
int byteread = 0;
while ((byteread = inputStream.read(tempbytes)) != -1) {
out.write(tempbytes, 0, byteread);
}
} catch (MinioException e) {
System.out.println("Error occurred: " + e);
}
}
```
### 4.2.3 刪除檔案
刪除檔案簡單,使用`removeObject`即可。
```java
minioClient.removeObject(bucketName, objectName);
```
### 4.2.4 列出檔案
```java
/**
* 羅列檔案
* @param minioClient
* @param bucketName
*/
public void listFile(MinioClient minioClient, String bucketName) throws XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, IOException {
try {
Iterable> results = minioClient.listObjects(bucketName);
Iterator> iterator = results.iterator();
while (iterator.hasNext()) {
Item item = iterator.next().get();
System.out.println(item.objectName() + ", " + item.objectSize() + "B");
}
} catch (MinioException e) {
System.out.println("Error occurred: " + e);
}
}
```
# 5 總結
由於有對靜態資源進行獨立訪問的需求,進行動靜分離,通過使用 MinIO ,可以快速簡單的實現靜態資源伺服器,以供訪問。本文通過對 MinIO 的下載、部署、啟動、執行、配置等描述,並以 html 引用靜態資原始檔為例,講解 MinIO 的使用,並提供 Java API 的簡單使用。希望對大家有幫助。
# 資源下載
本文中使用了 nohup 對 MinIO 進行啟動,但命令太長,一般我們都會寫成指令碼,以實現啟動、關閉及狀態查詢,因此,我把指令碼寫成完整的 sh 檔案,以供大家使用。另外,MinIO Java API 的測試,本示例使用的是 Spring Boot 專案,以單元測試的方式進行。
sh指令碼檔案及 Spring Boot 工程一起放在我的 [minio github 示例](https://github.com/mianshenglee/my-example/tree/master/minio-simple-demo) 中(指令碼`minio-serviced.sh` 在 scripts 目錄下),有需要的可下載參考。
> 指令碼使用方法:
>
> - 根據實際情況修改sh指令碼中的引數
> - 修改執行許可權:chmod +x minio-serviced.sh
> - 按引數啟動/關閉/重啟/執行狀態:./minio-serviced.sh start/stop/restart/status
# 參考資料
- [MinIO官網](https://min.io/): `https://min.io/`
- [MinIO開發文件](https://docs.min.io/): `https://docs.min.io/`
- [基於 Go 開源專案 MIMIO 的物件儲存方案在探探的實踐](https://mp.weixin.qq.com/s?__biz=MzA4ODg0NDkzOA==&mid=2247487119&idx=1&sn=6e09abb32392e015911be3a1d7f066e5&source=41):`https://mp.weixin.qq.com/s/MzA4ODg0NDkzOA==&mid=2247487119&idx=1&sn=6e09abb32392e015911be3a1d7f066e5&source=41`
- [架構師都知道的分散式物件儲存解決方案](https://juejin.im/post/5cdc16e251882568651553f9):`https://juejin.im/post/5cdc16e251882568651553f9`
- [使用minio搭建高效能物件儲存](https://tonybai.com/2020/03/16/build-high-performance-object-storage-with-minio-part1-prototype):`https://tonybai.com/2020/03/16/build-high-performance-object-storage-with-minio-part1-prototype`
# 往期文章
- [搞定SpringBoot多資料來源(3):引數化變更源](https://mp.weixin.qq.com/s/ZzzPJZAhPiGCQjN3RNZJ3Q)
- [搞定SpringBoot多資料來源(2):動態資料來源](https://mp.weixin.qq.com/s/neIN3htjkn4bifPpdq5l7w)
- [搞定SpringBoot多資料來源(1):多套源策略](https://mp.weixin.qq.com/s/0J-FLYScYtEMnj0vZToX7g)
- [java開發必學知識:動態代理](https://mp.weixin.qq.com/s/a3x_pKUryb_at_4Xk48IiQ)
- [2019 讀過的好書推薦](https://mp.weixin.qq.com/s/Wlbjhohb_HrqT67lstwVwA)
- [springboot+apache前後端分離部署https](https://mp.weixin.qq.com/s/hiJdsjdDC07axk-_sAkyVQ)
- [springboot+logback 日誌輸出企業實踐(下)](https://mp.weixin.qq.com/s/ha4LaR-E1gDxfUZ11neI-Q)
- [springboot+logback 日誌輸出企業實踐(上)](https://mp.weixin.qq.com/s/Ti5i9vv9S1j4za5q11RWeA)
我的公眾號(搜尋`Mason技術記錄`),獲取更多技術記錄:
![mason](https://gitee.com/mianshenglee/datastorage/raw/master/md-photo/myphoto/wx/wx-pub