Docker搭建Minio容器的流程步驟(完整詳細(xì)版)
簡(jiǎn)介:
Minio 是一個(gè)基于Apache License v2.0開源協(xié)議的對(duì)象存儲(chǔ)服務(wù),雖然輕量,卻擁有著不錯(cuò)的性能。它兼容亞馬遜S3云存儲(chǔ)服務(wù)接口,非常適合于存儲(chǔ)大容量非結(jié)構(gòu)化的數(shù)據(jù)。
例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機(jī)鏡像等,而一個(gè)對(duì)象文件可以是任意大小,從幾 kb 到最大 5T 不等。
最重要的是免費(fèi)
說明:
Docker如果想安裝軟件 , 必須先到Docker鏡像倉庫下載鏡像。
1、尋找Minio鏡像


2、下載Minio鏡像
# 下載鏡像 docker pull minio/minio #查看鏡像 docker images
| 命令 | 描述 |
|---|---|
| docker pull minio/minio | 下載最新版Minio鏡像 (其實(shí)此命令就等同于 : docker pull minio/minio:latest ) |
| docker pull minio/minio:RELEASE.2023-11-20T22-40-07Z.fips | 下載指定版本的Minio鏡像 (xxx指具體版本號(hào)) |

3、創(chuàng)建目錄
一個(gè)用來存放配置,一個(gè)用來存儲(chǔ)上傳文件的目錄
啟動(dòng)前需要先創(chuàng)建Minio外部掛載的配置文件( /opt/minio/config),和存儲(chǔ)上傳文件的目錄( /opt/minio/data)
mkdir -p /opt/minio/config mkdir -p /opt/minio/data
4、創(chuàng)建Minio容器并運(yùn)行
docker run \ -p 19000:9000 \ -p 9090:9090 \ --net=host \ --name minio \ -d --restart=always \ -e "MINIO_ACCESS_KEY=minioadmin" \ -e "MINIO_SECRET_KEY=minioadmin" \ -v /opt/minio/data:/data \ -v /opt/minio/config:/root/.minio \ minio/minio server \ /data --console-address ":9090" -address ":19000"
| 命令 | 描述 |
|---|---|
| -p 9000:9000 -p 9090:9090 | 這是端口映射,前一個(gè)是服務(wù)器的端口,后一個(gè)是客戶端也就是api接口訪問的端口地址 |
| –name minio | 這是給新創(chuàng)建的容器命名的選項(xiàng),名字是 “minio” |
| –net=host | 這是網(wǎng)絡(luò)設(shè)置,表示容器將使用主機(jī)的網(wǎng)絡(luò)棧,這樣就不需要在容器內(nèi)部配置網(wǎng)絡(luò) |
| -d --restart=always | 這是運(yùn)行容器的其他選項(xiàng),-d使容器在后臺(tái)運(yùn)行,–restart=always表示容器總是會(huì)在退出后自動(dòng)重啟 |
| -e “MINIO_ACCESS_KEY=minioadmin” | 用戶名 |
| -e “MINIO_SECRET_KEY=minioadmin” | 密碼 |
| -v /opt/minio/data:/data | 這意味著將宿主機(jī)上的 /opt/minio/data 目錄掛載到容器內(nèi)的 /data 目錄 |
| -v /opt/minio/config:/root/.minio | 將宿主機(jī)上的 /opt/minio/config 目錄掛載到容器內(nèi)的 /root/.minio 目錄 |
| minio/minio server /data --console-address “:9090” -address “:9000” | 這是容器內(nèi)要運(yùn)行的命令,啟動(dòng)一個(gè)名為 “minio” 的服務(wù)器,數(shù)據(jù)存儲(chǔ)在 /data 目錄下,服務(wù)器的控制臺(tái)地址為 “:9090”,服務(wù)地址為 “:9000” |
| \ | 換行 |
4.1、訪問操作
訪問:http://47.117.160.102:9090/login 用戶名:密碼 minioadmin:minioadmin

4.2、創(chuàng)建用戶


4.3、創(chuàng)建組


4.4、創(chuàng)建Buckets


4.5、創(chuàng)建Access Keys

4.6、文件上傳

4.7、瀏覽器訪問上傳文件

4.6.1、輸入ip:19000/Buckets名/文件名,如果不行,看看端口是否開放

5、Springboot簡(jiǎn)單使用
5.1、添加MinIO依賴Pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MinIO 客戶端 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.7</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
</dependencies>
5.2、配置MinIO的yaml
server:
port: 3333
spring:
servlet:
multipart:
max-request-size: 200MB
max-file-size: 200MB
minio:
url: http://127.0.0.1:19000 #換成自己的minio服務(wù)端地址
accessKey: minioadmin # 用戶名
secretKey: minioadmin # 密碼
bucketName: demo # bucketName指的就是之前創(chuàng)建的MinIO桶Bucket
5.3、配置類Config
/**
* @author HAOYANG
* @create 2023-12-01 20:40
*/
@Data
@Configuration
public class MinioConfig {
/**
* 訪問地址
*/
@Value("${minio.url}")
private String endpoint;
/**
* accessKey類似于用戶ID,用于唯一標(biāo)識(shí)你的賬戶
*/
@Value("${minio.accessKey}")
private String accessKey;
/**
* secretKey是你賬戶的密碼
*/
@Value("${minio.secretKey}")
private String secretKey;
/**
* 默認(rèn)存儲(chǔ)桶
*/
@Value("${minio.bucketName}")
private String bucketName;
@Bean
public MinioClient minioClient() {
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
return minioClient;
}
}
5.4、創(chuàng)建MinIO工具類
/**
* MinIO工具類
*
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class MinioUtils {
private final MinioClient minioClient;
/****************************** Operate Bucket Start ******************************/
/**
* 啟動(dòng)SpringBoot容器的時(shí)候初始化Bucket
* 如果沒有Bucket則創(chuàng)建
*
* @param bucketName
*/
@SneakyThrows(Exception.class)
private void createBucket(String bucketName) {
if (!bucketExists(bucketName)) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
/**
* 判斷Bucket是否存在,true:存在,false:不存在
*
* @param bucketName
* @return
*/
@SneakyThrows(Exception.class)
public boolean bucketExists(String bucketName) {
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
}
/**
* 獲得Bucket的策略
*
* @param bucketName
* @return
*/
@SneakyThrows(Exception.class)
public String getBucketPolicy(String bucketName) {
return minioClient.getBucketPolicy(GetBucketPolicyArgs
.builder()
.bucket(bucketName)
.build());
}
/**
* 獲得所有Bucket列表
*
* @return
*/
@SneakyThrows(Exception.class)
public List<Bucket> getAllBuckets() {
return minioClient.listBuckets();
}
/**
* 根據(jù)bucketName獲取其相關(guān)信息
*
* @param bucketName
* @return
*/
@SneakyThrows(Exception.class)
public Optional<Bucket> getBucket(String bucketName) {
return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
}
/**
* 根據(jù)bucketName刪除Bucket,true:刪除成功; false:刪除失敗,文件或已不存在
*
* @param bucketName
* @throws Exception
*/
@SneakyThrows(Exception.class)
public void removeBucket(String bucketName) {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
/****************************** Operate Bucket End ******************************/
/****************************** Operate Files Start ******************************/
/**
* 判斷文件是否存在
*
* @param bucketName
* @param objectName
* @return
*/
public boolean isObjectExist(String bucketName, String objectName) {
boolean exist = true;
try {
minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (Exception e) {
log.error("[Minio工具類]>>>> 判斷文件是否存在, 異常:", e);
exist = false;
}
return exist;
}
/**
* 判斷文件夾是否存在
*
* @param bucketName
* @param objectName
* @return
*/
public boolean isFolderExist(String bucketName, String objectName) {
boolean exist = false;
try {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
for (Result<Item> result : results) {
Item item = result.get();
if (item.isDir() && objectName.equals(item.objectName())) {
exist = true;
}
}
} catch (Exception e) {
log.error("[Minio工具類]>>>> 判斷文件夾是否存在,異常:", e);
exist = false;
}
return exist;
}
/**
* 根據(jù)文件前置查詢文件
*
* @param bucketName 存儲(chǔ)桶
* @param prefix 前綴
* @param recursive 是否使用遞歸查詢
* @return MinioItem 列表
*/
@SneakyThrows(Exception.class)
public List<Item> getAllObjectsByPrefix(String bucketName,
String prefix,
boolean recursive) {
List<Item> list = new ArrayList<>();
Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
if (objectsIterator != null) {
for (Result<Item> o : objectsIterator) {
Item item = o.get();
list.add(item);
}
}
return list;
}
/**
* 獲取文件流
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件名
* @return 二進(jìn)制流
*/
@SneakyThrows(Exception.class)
public InputStream getObject(String bucketName, String objectName) {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
}
/**
* 斷點(diǎn)下載
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件名稱
* @param offset 起始字節(jié)的位置
* @param length 要讀取的長(zhǎng)度
* @return 二進(jìn)制流
*/
@SneakyThrows(Exception.class)
public InputStream getObject(String bucketName, String objectName, long offset, long length) {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.offset(offset)
.length(length)
.build());
}
/**
* 獲取路徑下文件列表
*
* @param bucketName 存儲(chǔ)桶
* @param prefix 文件名稱
* @param recursive 是否遞歸查找,false:模擬文件夾結(jié)構(gòu)查找
* @return 二進(jìn)制流
*/
public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {
return minioClient.listObjects(
ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(prefix)
.recursive(recursive)
.build());
}
/**
* 使用MultipartFile進(jìn)行文件上傳
*
* @param bucketName 存儲(chǔ)桶
* @param file 文件名
* @param objectName 對(duì)象名
* @param contentType 類型
* @return
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) {
InputStream inputStream = file.getInputStream();
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.contentType(contentType)
.stream(inputStream, inputStream.available(), -1)
.build());
}
/**
* 圖片上傳
* @param bucketName
* @param imageBase64
* @param imageName
* @return
*/
public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String imageName) {
if (!StringUtils.isEmpty(imageBase64)) {
InputStream in = base64ToInputStream(imageBase64);
String newName = System.currentTimeMillis() + "_" + imageName + ".jpg";
String year = String.valueOf(new Date().getYear());
String month = String.valueOf(new Date().getMonth());
return uploadFile(bucketName, year + "/" + month + "/" + newName, in);
}
return null;
}
// BASE64Decoder在jdk8以上的版本移除了,報(bào)錯(cuò)最簡(jiǎn)單解決換成jdk8就行了
public static InputStream base64ToInputStream(String base64) {
ByteArrayInputStream stream = null;
try {
byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());
stream = new ByteArrayInputStream(bytes);
} catch (Exception e) {
e.printStackTrace();
}
return stream;
}
/**
* 上傳本地文件
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 對(duì)象名稱
* @param fileName 本地文件路徑
* @return
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {
return minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(fileName)
.build());
}
/**
* 通過流上傳文件
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件對(duì)象
* @param inputStream 文件流
* @return
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(inputStream, inputStream.available(), -1)
.build());
}
/**
* 創(chuàng)建文件夾或目錄
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 目錄路徑
* @return
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse createDir(String bucketName, String objectName) {
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
.build());
}
/**
* 獲取文件信息, 如果拋出異常則說明文件不存在
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件名稱
* @return
*/
@SneakyThrows(Exception.class)
public String getFileStatusInfo(String bucketName, String objectName) {
return minioClient.statObject(
StatObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build()).toString();
}
/**
* 拷貝文件
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件名
* @param srcBucketName 目標(biāo)存儲(chǔ)桶
* @param srcObjectName 目標(biāo)文件名
*/
@SneakyThrows(Exception.class)
public ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) {
return minioClient.copyObject(
CopyObjectArgs.builder()
.source(CopySource.builder().bucket(bucketName).object(objectName).build())
.bucket(srcBucketName)
.object(srcObjectName)
.build());
}
/**
* 刪除文件
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件名稱
*/
@SneakyThrows(Exception.class)
public void removeFile(String bucketName, String objectName) {
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
}
/**
* 批量刪除文件
*
* @param bucketName 存儲(chǔ)桶
* @param keys 需要?jiǎng)h除的文件列表
* @return
*/
public void removeFiles(String bucketName, List<String> keys) {
List<DeleteObject> objects = new LinkedList<>();
keys.forEach(s -> {
objects.add(new DeleteObject(s));
try {
removeFile(bucketName, s);
} catch (Exception e) {
log.error("[Minio工具類]>>>> 批量刪除文件,異常:", e);
}
});
}
/**
* 獲取文件外鏈
*
* @param bucketName 存儲(chǔ)桶
* @param objectName 文件名
* @param expires 過期時(shí)間 <=7 秒 (外鏈有效時(shí)間(單位:秒))
* @return url
*/
@SneakyThrows(Exception.class)
public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) {
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
return minioClient.getPresignedObjectUrl(args);
}
/**
* 獲得文件外鏈
*
* @param bucketName
* @param objectName
* @return url
*/
@SneakyThrows(Exception.class)
public String getPresignedObjectUrl(String bucketName, String objectName) {
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
.method(Method.GET).build();
return minioClient.getPresignedObjectUrl(args);
}
/**
* 將URLDecoder編碼轉(zhuǎn)成UTF8
*
* @param str
* @return
* @throws UnsupportedEncodingException
*/
public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
return URLDecoder.decode(url, "UTF-8");
}
}
5.5、創(chuàng)建Controller
/**
* @author HAOYANG
* @create 2023-12-01 20:38
*/
@Slf4j
@RestController
@RequestMapping("/oss")
public class OSSController {
@Autowired
private MinioUtils minioUtils;
@Autowired
private MinioConfig minioConfig;
/**
* 文件上傳
*
* @param file
*/
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
try {
//文件名
String fileName = file.getOriginalFilename();
String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");
//類型
String contentType = file.getContentType();
minioUtils.uploadFile(minioConfig.getBucketName(), file, newFileName, contentType);
return "上傳成功";
} catch (Exception e) {
log.error("上傳失敗");
return "上傳失敗";
}
}
/**
* 刪除
*
* @param fileName
*/
@DeleteMapping("/")
public void delete(@RequestParam("fileName") String fileName) {
minioUtils.removeFile(minioConfig.getBucketName(), fileName);
}
/**
* 獲取文件信息
*
* @param fileName
* @return
*/
@GetMapping("/info")
public String getFileStatusInfo(@RequestParam("fileName") String fileName) {
return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);
}
/**
* 獲取文件外鏈
*
* @param fileName
* @return
*/
@GetMapping("/url")
public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {
return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);
}
/**
* 文件下載
*
* @param fileName
* @param response
*/
@GetMapping("/download")
public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
try {
InputStream fileInputStream = minioUtils.getObject(minioConfig.getBucketName(), fileName);
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.setContentType("application/force-download");
response.setCharacterEncoding("UTF-8");
IOUtils.copy(fileInputStream, response.getOutputStream());
} catch (Exception e) {
log.error("下載失敗");
}
}
}
6、測(cè)試驗(yàn)證
6.1、文件上傳
使用Postman調(diào)用http://localhost:3333/oss/upload 接口,選擇某個(gè)文件測(cè)試上傳功能,如下圖所示:

6.2、文件下載
在瀏覽器中,調(diào)用http://localhost:3333/oss/download?fileName=1701436432918.gif 接口,驗(yàn)證文件下載接口,如下圖所示:

以上就是Docker搭建Minio容器的流程步驟的詳細(xì)內(nèi)容,更多關(guān)于Docker搭建Minio容器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Docker部署SpringBoot項(xiàng)目的實(shí)現(xiàn)步驟
本文主要介紹了Docker部署SpringBoot項(xiàng)目的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2007-02-02
linux中無make命令的問題(make: *** 沒有指明目標(biāo)并且找不到 makefile及make命令安裝方法)
這篇文章主要介紹了linux中無make命令的問題(make: *** 沒有指明目標(biāo)并且找不到 makefile及make命令安裝方法),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
docker 啟動(dòng)elasticsearch鏡像,掛載目錄后報(bào)錯(cuò)的解決
這篇文章主要介紹了docker 啟動(dòng) elasticsearch鏡像,掛載目錄后報(bào)錯(cuò)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11
docker容器下配置jupyter notebook的操作
這篇文章主要介紹了docker容器下配置jupyter notebook的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03
docker 設(shè)置windows存儲(chǔ)路徑的操作
這篇文章主要介紹了docker 設(shè)置windows存儲(chǔ)路徑的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03
Docker搭建LibreSpeed的實(shí)現(xiàn)步驟
LibreSpeed 是一個(gè)輕量級(jí)的網(wǎng)絡(luò)速度測(cè)試工具,本文主要介紹了Docker搭建LibreSpeed的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04

