Docker 搭建 Minio 容器 (完备详细版)

打印 上一主题 下一主题

主题 593|帖子 593|积分 1779

Docker 搭建 Minio 容器 (完备详细版)

简介:

   Minio 是一个基于Apache License v2.0开源协议的对象存储服务,固然轻量,却拥有着不错的性能。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非布局化的数据。
  例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意巨细,从几 kb 到最大 5T 不等。
  最重要的是免费
  阐明:

   Docker如果想安装软件 , 必须先到Docker镜像堆栈下载镜像。
  Docker官方镜像
1、探求Minio镜像



2、下载Minio镜像

  1. # 下载镜像
  2. docker pull minio/minio
  3. #查看镜像
  4. 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、创建目录

   一个用来存放配置,一个用来存储上传文件的目录
  启动前需要先创建Minio外部挂载的配置文件( /opt/minio/config),和存储上传文件的目录( /opt/minio/data)
  1. mkdir -p /opt/minio/config
  2. mkdir -p /opt/minio/data
复制代码
4、创建Minio容器并运行

  1. docker run \
  2. -p 19000:9000 \
  3. -p 9090:9090 \
  4. --net=host \
  5. --name minio \
  6. -d --restart=always \
  7. -e "MINIO_ACCESS_KEY=minioadmin" \
  8. -e "MINIO_SECRET_KEY=minioadmin" \
  9. -v /opt/minio/data:/data \
  10. -v /opt/minio/config:/root/.minio \
  11. minio/minio server \
  12. /data --console-address ":9090" -address ":19000"
复制代码
下令形貌-p 9000:9000 -p 9090:9090这是端口映射,前一个是服务器的端口,后一个是客户端也就是api接口访问的端口地点–name minio这是给新创建的容器命名的选项,名字是 “minio”–net=host这是网络设置,表示容器将使用主机的网络栈,如许就不需要在容器内部配置网络-d --restart=always这是运行容器的其他选项,-d使容器在背景运行,–restart=always表示容器总是会在退出后自动重启-e “MINIO_ACCESS_KEY=minioadmin”用户名-e “MINIO_SECRET_KEY=minioadmin”密码-v /opt/minio/data:/data这意味着将宿主机上的 /opt/minio/data 目录挂载到容器内的 /data 目录-v /opt/minio/config:/root/.minio将宿主机上的 /opt/minio/config 目录挂载到容器内的 /root/.minio 目录minio/minio server /data --console-address “:9090” -address “:9000”这是容器内要运行的下令,启动一个名为 “minio” 的服务器,数据存储在 /data 目录下,服务器的控制台地点为 “:9090”,服务地点为 “:9000”\换行 4.1、访问操作

访问:http://47.117.160.102:9090/login 用户名:密码 minioadmin:minioadmin

4.2、创建用户



4.3、创建组



4.4、创建Buckets



4.5、创建Access Keys


4.6、文件上传


4.6、浏览器访问上传文件


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


5、Springboot简朴使用

5.1、添加MinIO依赖Pom

  1. <dependencies>
  2.         
  3.         <dependency>
  4.             <groupId>org.springframework.boot</groupId>
  5.             <artifactId>spring-boot-starter-web</artifactId>
  6.         </dependency>
  7.         <!-- MinIO 客户端 -->
  8.         <dependency>
  9.             <groupId>io.minio</groupId>
  10.             <artifactId>minio</artifactId>
  11.             <version>8.5.7</version>
  12.         </dependency>
  13.    
  14.         <dependency>
  15.             <groupId>org.projectlombok</groupId>
  16.             <artifactId>lombok</artifactId>
  17.         </dependency>
  18.         <dependency>
  19.             <groupId>org.apache.commons</groupId>
  20.             <artifactId>commons-lang3</artifactId>
  21.             <version>3.11</version>
  22.         </dependency>
  23.    
  24. </dependencies>
复制代码
5.2、配置MinIO的yaml

  1. server:
  2.   port: 3333
  3. spring:
  4.   servlet:
  5.     multipart:
  6.       max-request-size: 200MB
  7.       max-file-size: 200MB
  8. minio:
  9.   url: http://127.0.0.1:19000 #换成自己的minio服务端地址
  10.   accessKey: minioadmin # 用户名
  11.   secretKey: minioadmin # 密码
  12.   bucketName: demo  # bucketName指的就是之前创建的MinIO桶Bucket
复制代码
5.3、配置类Config

  1. /**
  2. * @author HAOYANG
  3. * @create 2023-12-01 20:40
  4. */
  5. @Data
  6. @Configuration
  7. public class MinioConfig {
  8.     /**
  9.      * 访问地址
  10.      */
  11.     @Value("${minio.url}")
  12.     private String endpoint;
  13.     /**
  14.      * accessKey类似于用户ID,用于唯一标识你的账户
  15.      */
  16.     @Value("${minio.accessKey}")
  17.     private String accessKey;
  18.     /**
  19.      * secretKey是你账户的密码
  20.      */
  21.     @Value("${minio.secretKey}")
  22.     private String secretKey;
  23.     /**
  24.      * 默认存储桶
  25.      */
  26.     @Value("${minio.bucketName}")
  27.     private String bucketName;
  28.     @Bean
  29.     public MinioClient minioClient() {
  30.         MinioClient minioClient = MinioClient.builder()
  31.                 .endpoint(endpoint)
  32.                 .credentials(accessKey, secretKey)
  33.                 .build();
  34.         return minioClient;
  35.     }
  36. }
复制代码
5.4、创建MinIO工具类

  1. /**
  2. * MinIO工具类
  3. *
  4. */
  5. @Slf4j
  6. @Component
  7. @RequiredArgsConstructor
  8. public class MinioUtils {
  9.     private final MinioClient minioClient;
  10.     /******************************  Operate Bucket Start  ******************************/
  11.     /**
  12.      * 启动SpringBoot容器的时候初始化Bucket
  13.      * 如果没有Bucket则创建
  14.      *
  15.      * @param bucketName
  16.      */
  17.     @SneakyThrows(Exception.class)
  18.     private void createBucket(String bucketName) {
  19.         if (!bucketExists(bucketName)) {
  20.             minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
  21.         }
  22.     }
  23.     /**
  24.      * 判断Bucket是否存在,true:存在,false:不存在
  25.      *
  26.      * @param bucketName
  27.      * @return
  28.      */
  29.     @SneakyThrows(Exception.class)
  30.     public boolean bucketExists(String bucketName) {
  31.         return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
  32.     }
  33.     /**
  34.      * 获得Bucket的策略
  35.      *
  36.      * @param bucketName
  37.      * @return
  38.      */
  39.     @SneakyThrows(Exception.class)
  40.     public String getBucketPolicy(String bucketName) {
  41.         return minioClient.getBucketPolicy(GetBucketPolicyArgs
  42.                 .builder()
  43.                 .bucket(bucketName)
  44.                 .build());
  45.     }
  46.     /**
  47.      * 获得所有Bucket列表
  48.      *
  49.      * @return
  50.      */
  51.     @SneakyThrows(Exception.class)
  52.     public List<Bucket> getAllBuckets() {
  53.         return minioClient.listBuckets();
  54.     }
  55.     /**
  56.      * 根据bucketName获取其相关信息
  57.      *
  58.      * @param bucketName
  59.      * @return
  60.      */
  61.     @SneakyThrows(Exception.class)
  62.     public Optional<Bucket> getBucket(String bucketName) {
  63.         return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
  64.     }
  65.     /**
  66.      * 根据bucketName删除Bucket,true:删除成功; false:删除失败,文件或已不存在
  67.      *
  68.      * @param bucketName
  69.      * @throws Exception
  70.      */
  71.     @SneakyThrows(Exception.class)
  72.     public void removeBucket(String bucketName) {
  73.         minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
  74.     }
  75.     /******************************  Operate Bucket End  ******************************/
  76.     /******************************  Operate Files Start  ******************************/
  77.     /**
  78.      * 判断文件是否存在
  79.      *
  80.      * @param bucketName
  81.      * @param objectName
  82.      * @return
  83.      */
  84.     public boolean isObjectExist(String bucketName, String objectName) {
  85.         boolean exist = true;
  86.         try {
  87.             minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
  88.         } catch (Exception e) {
  89.             log.error("[Minio工具类]>>>> 判断文件是否存在, 异常:", e);
  90.             exist = false;
  91.         }
  92.         return exist;
  93.     }
  94.     /**
  95.      * 判断文件夹是否存在
  96.      *
  97.      * @param bucketName
  98.      * @param objectName
  99.      * @return
  100.      */
  101.     public boolean isFolderExist(String bucketName, String objectName) {
  102.         boolean exist = false;
  103.         try {
  104.             Iterable<Result<Item>> results = minioClient.listObjects(
  105.                     ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
  106.             for (Result<Item> result : results) {
  107.                 Item item = result.get();
  108.                 if (item.isDir() && objectName.equals(item.objectName())) {
  109.                     exist = true;
  110.                 }
  111.             }
  112.         } catch (Exception e) {
  113.             log.error("[Minio工具类]>>>> 判断文件夹是否存在,异常:", e);
  114.             exist = false;
  115.         }
  116.         return exist;
  117.     }
  118.     /**
  119.      * 根据文件前置查询文件
  120.      *
  121.      * @param bucketName 存储桶
  122.      * @param prefix     前缀
  123.      * @param recursive  是否使用递归查询
  124.      * @return MinioItem 列表
  125.      */
  126.     @SneakyThrows(Exception.class)
  127.     public List<Item> getAllObjectsByPrefix(String bucketName,
  128.                                             String prefix,
  129.                                             boolean recursive) {
  130.         List<Item> list = new ArrayList<>();
  131.         Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
  132.                 ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
  133.         if (objectsIterator != null) {
  134.             for (Result<Item> o : objectsIterator) {
  135.                 Item item = o.get();
  136.                 list.add(item);
  137.             }
  138.         }
  139.         return list;
  140.     }
  141.     /**
  142.      * 获取文件流
  143.      *
  144.      * @param bucketName 存储桶
  145.      * @param objectName 文件名
  146.      * @return 二进制流
  147.      */
  148.     @SneakyThrows(Exception.class)
  149.     public InputStream getObject(String bucketName, String objectName) {
  150.         return minioClient.getObject(
  151.                 GetObjectArgs.builder()
  152.                         .bucket(bucketName)
  153.                         .object(objectName)
  154.                         .build());
  155.     }
  156.     /**
  157.      * 断点下载
  158.      *
  159.      * @param bucketName 存储桶
  160.      * @param objectName 文件名称
  161.      * @param offset     起始字节的位置
  162.      * @param length     要读取的长度
  163.      * @return 二进制流
  164.      */
  165.     @SneakyThrows(Exception.class)
  166.     public InputStream getObject(String bucketName, String objectName, long offset, long length) {
  167.         return minioClient.getObject(
  168.                 GetObjectArgs.builder()
  169.                         .bucket(bucketName)
  170.                         .object(objectName)
  171.                         .offset(offset)
  172.                         .length(length)
  173.                         .build());
  174.     }
  175.     /**
  176.      * 获取路径下文件列表
  177.      *
  178.      * @param bucketName 存储桶
  179.      * @param prefix     文件名称
  180.      * @param recursive  是否递归查找,false:模拟文件夹结构查找
  181.      * @return 二进制流
  182.      */
  183.     public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {
  184.         return minioClient.listObjects(
  185.                 ListObjectsArgs.builder()
  186.                         .bucket(bucketName)
  187.                         .prefix(prefix)
  188.                         .recursive(recursive)
  189.                         .build());
  190.     }
  191.     /**
  192.      * 使用MultipartFile进行文件上传
  193.      *
  194.      * @param bucketName  存储桶
  195.      * @param file        文件名
  196.      * @param objectName  对象名
  197.      * @param contentType 类型
  198.      * @return
  199.      */
  200.     @SneakyThrows(Exception.class)
  201.     public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) {
  202.         InputStream inputStream = file.getInputStream();
  203.         return minioClient.putObject(
  204.                 PutObjectArgs.builder()
  205.                         .bucket(bucketName)
  206.                         .object(objectName)
  207.                         .contentType(contentType)
  208.                         .stream(inputStream, inputStream.available(), -1)
  209.                         .build());
  210.     }
  211.     /**
  212.      * 图片上传
  213.      * @param bucketName
  214.      * @param imageBase64
  215.      * @param imageName
  216.      * @return
  217.      */
  218.     public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String imageName) {
  219.         if (!StringUtils.isEmpty(imageBase64)) {
  220.             InputStream in = base64ToInputStream(imageBase64);
  221.             String newName = System.currentTimeMillis() + "_" + imageName + ".jpg";
  222.             String year = String.valueOf(new Date().getYear());
  223.             String month = String.valueOf(new Date().getMonth());
  224.             return uploadFile(bucketName, year + "/" + month + "/" + newName, in);
  225.         }
  226.         return null;
  227.     }
  228. // BASE64Decoder在jdk8以上的版本移除了,报错最简单解决换成jdk8就行了
  229.     public static InputStream base64ToInputStream(String base64) {
  230.         ByteArrayInputStream stream = null;
  231.         try {
  232.             byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());
  233.             stream = new ByteArrayInputStream(bytes);
  234.         } catch (Exception e) {
  235.             e.printStackTrace();
  236.         }
  237.         return stream;
  238.     }
  239.     /**
  240.      * 上传本地文件
  241.      *
  242.      * @param bucketName 存储桶
  243.      * @param objectName 对象名称
  244.      * @param fileName   本地文件路径
  245.      * @return
  246.      */
  247.     @SneakyThrows(Exception.class)
  248.     public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {
  249.         return minioClient.uploadObject(
  250.                 UploadObjectArgs.builder()
  251.                         .bucket(bucketName)
  252.                         .object(objectName)
  253.                         .filename(fileName)
  254.                         .build());
  255.     }
  256.     /**
  257.      * 通过流上传文件
  258.      *
  259.      * @param bucketName  存储桶
  260.      * @param objectName  文件对象
  261.      * @param inputStream 文件流
  262.      * @return
  263.      */
  264.     @SneakyThrows(Exception.class)
  265.     public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {
  266.         return minioClient.putObject(
  267.                 PutObjectArgs.builder()
  268.                         .bucket(bucketName)
  269.                         .object(objectName)
  270.                         .stream(inputStream, inputStream.available(), -1)
  271.                         .build());
  272.     }
  273.     /**
  274.      * 创建文件夹或目录
  275.      *
  276.      * @param bucketName 存储桶
  277.      * @param objectName 目录路径
  278.      * @return
  279.      */
  280.     @SneakyThrows(Exception.class)
  281.     public ObjectWriteResponse createDir(String bucketName, String objectName) {
  282.         return minioClient.putObject(
  283.                 PutObjectArgs.builder()
  284.                         .bucket(bucketName)
  285.                         .object(objectName)
  286.                         .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
  287.                         .build());
  288.     }
  289.     /**
  290.      * 获取文件信息, 如果抛出异常则说明文件不存在
  291.      *
  292.      * @param bucketName 存储桶
  293.      * @param objectName 文件名称
  294.      * @return
  295.      */
  296.     @SneakyThrows(Exception.class)
  297.     public String getFileStatusInfo(String bucketName, String objectName) {
  298.         return minioClient.statObject(
  299.                 StatObjectArgs.builder()
  300.                         .bucket(bucketName)
  301.                         .object(objectName)
  302.                         .build()).toString();
  303.     }
  304.     /**
  305.      * 拷贝文件
  306.      *
  307.      * @param bucketName    存储桶
  308.      * @param objectName    文件名
  309.      * @param srcBucketName 目标存储桶
  310.      * @param srcObjectName 目标文件名
  311.      */
  312.     @SneakyThrows(Exception.class)
  313.     public ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) {
  314.         return minioClient.copyObject(
  315.                 CopyObjectArgs.builder()
  316.                         .source(CopySource.builder().bucket(bucketName).object(objectName).build())
  317.                         .bucket(srcBucketName)
  318.                         .object(srcObjectName)
  319.                         .build());
  320.     }
  321.     /**
  322.      * 删除文件
  323.      *
  324.      * @param bucketName 存储桶
  325.      * @param objectName 文件名称
  326.      */
  327.     @SneakyThrows(Exception.class)
  328.     public void removeFile(String bucketName, String objectName) {
  329.         minioClient.removeObject(
  330.                 RemoveObjectArgs.builder()
  331.                         .bucket(bucketName)
  332.                         .object(objectName)
  333.                         .build());
  334.     }
  335.     /**
  336.      * 批量删除文件
  337.      *
  338.      * @param bucketName 存储桶
  339.      * @param keys       需要删除的文件列表
  340.      * @return
  341.      */
  342.     public void removeFiles(String bucketName, List<String> keys) {
  343.         List<DeleteObject> objects = new LinkedList<>();
  344.         keys.forEach(s -> {
  345.             objects.add(new DeleteObject(s));
  346.             try {
  347.                 removeFile(bucketName, s);
  348.             } catch (Exception e) {
  349.                 log.error("[Minio工具类]>>>> 批量删除文件,异常:", e);
  350.             }
  351.         });
  352.     }
  353.     /**
  354.      * 获取文件外链
  355.      *
  356.      * @param bucketName 存储桶
  357.      * @param objectName 文件名
  358.      * @param expires    过期时间 <=7 秒 (外链有效时间(单位:秒))
  359.      * @return url
  360.      */
  361.     @SneakyThrows(Exception.class)
  362.     public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) {
  363.         GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
  364.         return minioClient.getPresignedObjectUrl(args);
  365.     }
  366.     /**
  367.      * 获得文件外链
  368.      *
  369.      * @param bucketName
  370.      * @param objectName
  371.      * @return url
  372.      */
  373.     @SneakyThrows(Exception.class)
  374.     public String getPresignedObjectUrl(String bucketName, String objectName) {
  375.         GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
  376.                 .bucket(bucketName)
  377.                 .object(objectName)
  378.                 .method(Method.GET).build();
  379.         return minioClient.getPresignedObjectUrl(args);
  380.     }
  381.     /**
  382.      * 将URLDecoder编码转成UTF8
  383.      *
  384.      * @param str
  385.      * @return
  386.      * @throws UnsupportedEncodingException
  387.      */
  388.     public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
  389.         String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
  390.         return URLDecoder.decode(url, "UTF-8");
  391.     }
  392. }
复制代码
5.5、创建Controller

  1. /**
  2. * @author HAOYANG
  3. * @create 2023-12-01 20:38
  4. */
  5. @Slf4j
  6. @RestController
  7. @RequestMapping("/oss")
  8. public class OSSController {
  9.     @Autowired
  10.     private MinioUtils minioUtils;
  11.     @Autowired
  12.     private MinioConfig minioConfig;
  13.     /**
  14.      * 文件上传
  15.      *
  16.      * @param file
  17.      */
  18.     @PostMapping("/upload")
  19.     public String upload(@RequestParam("file") MultipartFile file) {
  20.         try {
  21.             //文件名
  22.             String fileName = file.getOriginalFilename();
  23.             String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");
  24.             //类型
  25.             String contentType = file.getContentType();
  26.             minioUtils.uploadFile(minioConfig.getBucketName(), file, newFileName, contentType);
  27.             return "上传成功";
  28.         } catch (Exception e) {
  29.             log.error("上传失败");
  30.             return "上传失败";
  31.         }
  32.     }
  33.     /**
  34.      * 删除
  35.      *
  36.      * @param fileName
  37.      */
  38.     @DeleteMapping("/")
  39.     public void delete(@RequestParam("fileName") String fileName) {
  40.         minioUtils.removeFile(minioConfig.getBucketName(), fileName);
  41.     }
  42.     /**
  43.      * 获取文件信息
  44.      *
  45.      * @param fileName
  46.      * @return
  47.      */
  48.     @GetMapping("/info")
  49.     public String getFileStatusInfo(@RequestParam("fileName") String fileName) {
  50.         return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);
  51.     }
  52.     /**
  53.      * 获取文件外链
  54.      *
  55.      * @param fileName
  56.      * @return
  57.      */
  58.     @GetMapping("/url")
  59.     public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {
  60.         return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);
  61.     }
  62.     /**
  63.      * 文件下载
  64.      *
  65.      * @param fileName
  66.      * @param response
  67.      */
  68.     @GetMapping("/download")
  69.     public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
  70.         try {
  71.             InputStream fileInputStream = minioUtils.getObject(minioConfig.getBucketName(), fileName);
  72.             response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
  73.             response.setContentType("application/force-download");
  74.             response.setCharacterEncoding("UTF-8");
  75.             IOUtils.copy(fileInputStream, response.getOutputStream());
  76.         } catch (Exception e) {
  77.             log.error("下载失败");
  78.         }
  79.     }
  80. }
复制代码
6、测试验证

6.1、文件上传

使用Postman调用http://localhost:3333/oss/upload 接口,选择某个文件测试上传功能,如下图所示:

6.2、文件下载

在浏览器中,调用http://localhost:3333/oss/download?fileName=1701436432918.gif 接口,验证文件下载接口,如下图所示:

更多精彩文章可以关注 鹏摇星海 公众号


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

缠丝猫

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表