Docker搭建Minio容器的流程步驟(完整詳細版)
簡介:
Minio 是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),雖然輕量,卻擁有著不錯的性能。它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù)。
例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機鏡像等,而一個對象文件可以是任意大小,從幾 kb 到最大 5T 不等。
最重要的是免費
說明:
Docker如果想安裝軟件 , 必須先到Docker鏡像倉庫下載鏡像。
1、尋找Minio鏡像
2、下載Minio鏡像
# 下載鏡像 docker pull minio/minio #查看鏡像 docker images
命令 | 描述 |
---|---|
docker pull minio/minio | 下載最新版Minio鏡像 (其實此命令就等同于 : docker pull minio/minio:latest ) |
docker pull minio/minio:RELEASE.2023-11-20T22-40-07Z.fips | 下載指定版本的Minio鏡像 (xxx指具體版本號) |
3、創(chuàng)建目錄
一個用來存放配置,一個用來存儲上傳文件的目錄
啟動前需要先創(chuàng)建Minio外部掛載的配置文件( /opt/minio/config),和存儲上傳文件的目錄( /opt/minio/data)
mkdir -p /opt/minio/config mkdir -p /opt/minio/data
4、創(chuàng)建Minio容器并運行
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 | 這是端口映射,前一個是服務(wù)器的端口,后一個是客戶端也就是api接口訪問的端口地址 |
–name minio | 這是給新創(chuàng)建的容器命名的選項,名字是 “minio” |
–net=host | 這是網(wǎng)絡(luò)設(shè)置,表示容器將使用主機的網(wǎng)絡(luò)棧,這樣就不需要在容器內(nèi)部配置網(wǎng)絡(luò) |
-d --restart=always | 這是運行容器的其他選項,-d使容器在后臺運行,–restart=always表示容器總是會在退出后自動重啟 |
-e “MINIO_ACCESS_KEY=minioadmin” | 用戶名 |
-e “MINIO_SECRET_KEY=minioadmin” | 密碼 |
-v /opt/minio/data:/data | 這意味著將宿主機上的 /opt/minio/data 目錄掛載到容器內(nèi)的 /data 目錄 |
-v /opt/minio/config:/root/.minio | 將宿主機上的 /opt/minio/config 目錄掛載到容器內(nèi)的 /root/.minio 目錄 |
minio/minio server /data --console-address “:9090” -address “:9000” | 這是容器內(nèi)要運行的命令,啟動一個名為 “minio” 的服務(wù)器,數(shù)據(jù)存儲在 /data 目錄下,服務(wù)器的控制臺地址為 “: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簡單使用
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,用于唯一標識你的賬戶 */ @Value("${minio.accessKey}") private String accessKey; /** * secretKey是你賬戶的密碼 */ @Value("${minio.secretKey}") private String secretKey; /** * 默認存儲桶 */ @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 ******************************/ /** * 啟動SpringBoot容器的時候初始化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 存儲桶 * @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 存儲桶 * @param objectName 文件名 * @return 二進制流 */ @SneakyThrows(Exception.class) public InputStream getObject(String bucketName, String objectName) { return minioClient.getObject( GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); } /** * 斷點下載 * * @param bucketName 存儲桶 * @param objectName 文件名稱 * @param offset 起始字節(jié)的位置 * @param length 要讀取的長度 * @return 二進制流 */ @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 存儲桶 * @param prefix 文件名稱 * @param recursive 是否遞歸查找,false:模擬文件夾結(jié)構(gòu)查找 * @return 二進制流 */ public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) { return minioClient.listObjects( ListObjectsArgs.builder() .bucket(bucketName) .prefix(prefix) .recursive(recursive) .build()); } /** * 使用MultipartFile進行文件上傳 * * @param bucketName 存儲桶 * @param file 文件名 * @param objectName 對象名 * @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以上的版本移除了,報錯最簡單解決換成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 存儲桶 * @param objectName 對象名稱 * @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 存儲桶 * @param objectName 文件對象 * @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 存儲桶 * @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 存儲桶 * @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 存儲桶 * @param objectName 文件名 * @param srcBucketName 目標存儲桶 * @param srcObjectName 目標文件名 */ @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 存儲桶 * @param objectName 文件名稱 */ @SneakyThrows(Exception.class) public void removeFile(String bucketName, String objectName) { minioClient.removeObject( RemoveObjectArgs.builder() .bucket(bucketName) .object(objectName) .build()); } /** * 批量刪除文件 * * @param bucketName 存儲桶 * @param keys 需要刪除的文件列表 * @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 存儲桶 * @param objectName 文件名 * @param expires 過期時間 <=7 秒 (外鏈有效時間(單位:秒)) * @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、測試驗證
6.1、文件上傳
使用Postman調(diào)用http://localhost:3333/oss/upload 接口,選擇某個文件測試上傳功能,如下圖所示:
6.2、文件下載
在瀏覽器中,調(diào)用http://localhost:3333/oss/download?fileName=1701436432918.gif 接口,驗證文件下載接口,如下圖所示:
以上就是Docker搭建Minio容器的流程步驟的詳細內(nèi)容,更多關(guān)于Docker搭建Minio容器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Docker部署SpringBoot項目的實現(xiàn)步驟
本文主要介紹了Docker部署SpringBoot項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2007-02-02linux中無make命令的問題(make: *** 沒有指明目標并且找不到 makefile及make命令安裝方法)
這篇文章主要介紹了linux中無make命令的問題(make: *** 沒有指明目標并且找不到 makefile及make命令安裝方法),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08docker 啟動elasticsearch鏡像,掛載目錄后報錯的解決
這篇文章主要介紹了docker 啟動 elasticsearch鏡像,掛載目錄后報錯的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11docker容器下配置jupyter notebook的操作
這篇文章主要介紹了docker容器下配置jupyter notebook的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03