分布式文件存储系统Minio,tuling,fox

MinIO | 高性能,对Kubernetes友好的对象存储

MinIO High Performance Object Storage — MinIO Object Storage for Linux

一 分布式文件系统应用场景

  1. fastDFS
    1. 缺点:
      1. 部署麻烦。
      2. 因为文件名是自动生成的,所以如果要处理文件的话,还要经过额外的编码。
  2. Minio介绍
    1. 应用场景
      1. 互联网海量非结构化数据的存储需求,如
                    电商网站:海量商品图片
                    视频网站:海量视频文件
                    网盘 : 海量文件
                    社交网站:海量图片
      2. 对于中小型企业,如果不选择存储上云,那么 Minio 是个不错的选择,麻雀虽小,五脏俱全。当然 Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3、 MicroSoft Azure。
      3. 非结构化数据与结构化数据
        1. 非结构化数据:文件、音频、视频、图片
        2. 结构化数据:如常见的关系型数据库(mysql、oracle、sqlserver)用表存储某个网站的会员信息。
    2. minio是什么?
      1. MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。
        1. 对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服 务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成 本。
      2. Minio是使用go语言编写的,天然支持跨平台。
    3. minio的优点
      1. 部署简单: 一个single二进制文件即是一切,还可支持各种平台。
      2. minio支持海量存储,可按zone扩展(原zone不受任何影响),支持单个对象最大5TB;
      3. 兼容Amazon S3接口,充分考虑开发人员的需求和体验;
      4. 低冗余且磁盘损坏高容忍,标准且最高的数据冗余系数为2(即存储一个1M的数据对象,实际占用 磁盘空间为2M)。但在任意n/2块disk损坏的情况下依然可以读出数据(n为一个纠删码集合(Erasure Coding Set)中的disk数量)。并且这种损坏恢复是基于单个对象的,而不是基于整个存储卷的。
      5. 读写性能优异
  3. MinIO的基础概念
    1. Object:一个文件 / 视频 / 音频 / 字节流 / Anything......
    2. Bucket:翻译过来是桶,可理解为一个顶层的目录(文件夹)。Bucket是用来装Object的。
    3. Drive:即存储数据的磁盘。
    4. Set :分布式集群场景或多磁盘场景下。一组Drive的集合。
    5. 备注:
      1. 当MinIO集群服务启动以后,表明已经把Drive配置好了(当然,我们需要去指定Drive的位置、存储目录)。
      2. Object和Bucket是我们真正去操作、控制的2个东西,比如想把文件存储到哪个Bucket下面,我们要上传哪些Object。
  4. 纠删码EC(Erasure Code): 备份与恢复
    1. 定义、流原
      1. 纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code将 (ps:用户上传的每一个对象) 对象拆分成N/2 数据和N/2 奇偶校验块。 这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块),你仍可以从剩下的盘中的数据进行恢复。
        1. BLOCK:块。在minio中,一个block大概是10M。
        2. DATA BLOCK:数据块。
        3. PARITY BLOCK:校验块。 

    2. 作用:
      1. EC机制是用来保证MinIO高可靠性。
        1. 第一步:EC机制是用来校验数据是否损坏(如本身磁盘(硬件)就损坏了,如单单数据的损坏)。
          1. 校验原理(Bit Rot Protection):直接对MinIO中的文件进行一个hash。因为hash码是唯一的,所以如果hash码不变说明文件没有损坏,反之说明文件已经损坏了。
        2. 第二步:EC机制是用来做数据冗余和恢复的
          1. 官网纠删码的作用描述:Minio使用纠删码 erasure code 和校验和 checksum 来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。
          2. 如果数据损坏,可以校验是否是源文件数据损坏了,并且可以使用EC机制highwayhash来处理数据损坏(Bit Rot Protection)。
          3. minIO纠删码还原,是依赖于EC盘的数量去做处理的。
            1. 规则1:所有的盘都是可读的。
            2. 规则2:坏死盘数量不能大于n/2+1,大于的话就恢复不了数据。
            3. 规则3:如果是坏死盘,MinIO是不允许我们再上传新的文件到坏死盘上面去的。
            4. 规则4:如果坏死的磁盘大于等于N/2,那么minio是不允许上传文件的。只能坏死的磁盘不超过一半(n/2)时,minio才允许上传文件的。
            5. 规则5:必须要有大于等于N/2+1的盘是可读的正常状态的,,才能保证有EC盘数据的存在,也才能有可能通过EC机制来恢复数据。
    3. 案例1:EC机制下的数据冗余与恢复
      1. 有6块盘(因为EC机制生效最少需要4块盘)。
      2. 其中4块盘用于存储用户的数据,比如1.jpg。
      3. 其中2块盘用于存储对它EC机制编号后生成的1.jpg。
      4. 如果丢失1份数据,可以是4块盘中之一的1.jpg,也可以是2块盘之一EC后的1.jpg。那么,根据一定的算法可以恢复和还原。
      5. 如果丢失2份数据,而且是2块盘EC后的1.jpg都丢失了,那么不是还有4个盘的1.jpg嘛。
      6. 如果丢失3份数据,4块盘中之一和2块盘EC后的1.jpg都丢失了,那么就无法去恢复和还原了。
    4. 案例2:为了保证数据的冗余和恢复MinIO推荐使用方式
      1. MinIO推荐平均去分配
        1. 8个盘。
        2. 4个盘存源数据,4个盘存EC数据。
        3. 意味着,不管在什么情况下,如果丢失的数据<=4个盘,数据仍可以恢复。
  5. 存储形式
    1. 开启EC模式下的存储形式: 
  6. 存储方案
    1. MinIO集群的存储方案:
      1. 第一步:搭建MinIO集群
      2. 第二步:MinIO集群提供操作的API接口,默认端口9000,可以读写集群中的文件。
      3. 第三步:MinIO集群提供的控制台,端口随便定义,比如50000 

二 Minio环境搭建

  1. 概述:3种模式
  2. 方式1:单机部署 - 无纠删码
    1. 不使用docker
      1. linux:systemctl stop firewalld(关闭防火墙)
        1. 优化前的启动
          1. 第一步:下载: wget https://dl.min.io/server/minio/release/linux-amd64/minio
          2. 第二步:chmod +x minio,把它变成可执行文件。
          3. 第三步:./minio server /data,指定磁盘位置(数据保存在哪)并运行。这里没有用后台启动,想跟大家一起去看看日志。
          4. 第四步:查看日志

          5. 第五步:验证:登录控制台,操作一下文件的上传、下载
        2. 优化后的启动
          1. 第一步:下载: wget https://dl.min.io/server/minio/release/linux-amd64/minio
          2. 第二步:chmod +x minio,把它变成可执行文件。
          3. 第三步:指定登录控制台使用的用户名和密码:
            export MINIO_ROOT_USER=admin
            export MINIO_ROOT_PASSWORD=12345678
          4. 第四步:使用自定义的配置文件所在的路径:
            ./minio server --config-dir /usr/local/minioInstall/config /usr/local/minioInstall/data
            1. --config-dir /usr/local/minioInstall/config:自定义配置文件所在的路
            2. /usr/local/minioInstall/data:上传下载的文件所在的路径
          5. 第五步:指定登录控制台监听的端口为5000:
            ./minio server --console-address ":50000" /usr/local/minioInstall/data
            1. --console-address ":50000":指定登录控制台监听的端口为5000
          6. 第六步:验证:登录控制台,操作一下文件的上传、下载
        3. 总结
          1. 特点1:这就是我们通过单机的,没有纠删码的部署模式。为什么没有纠删码呢?因为我们这里只分配了1块磁盘呀,纠删码部署模式下是要求有4块磁盘以上的吧。
          2. 特点2:在没有纠删码部署模式下,/usr/local/minioInstall/data保存的文件是源文件,而并非经过加密后的文件:
      2. window
        1. 第一步:下载:http://dl.minio.org.cn/server/minio/release/windows-amd64/minio.exe
        2. 第二步:minio.exe server D:\,指定磁盘位置并运行
    2. 使用docker
      1. linux:中文官网文档更新慢(配置中没有暴露控制台的访问端口),一定要去参考英文官网的英文文档
        1. docker run -d -p 9000:9000 -p 50000:50000 --name minio \
          -e "MINIO_ROOT_USER=admin" \
          -e "MINIO_ROOT_PASSWORD=12345678" \
          -v /usr/loca/minioInstall/data:/data \
          -v /mnt/config:/root/.minio \
          minio/minio server --console-address ":50000" /data
          1. docker run -d: 表明是后台启动
          2. -e "MINIO_ROOT_USER=admin" \:指定控制台用户名
          3. -e "MINIO_ROOT_PASSWORD=12345678" \:指定控制台密码
          4. -v /usr/loca/minioInstall/data:/data \:指定挂载的目录,文件(上传下载)所在的挂载目录
            1. :/data:变量,对应下面的/data
          5. -v /mnt/config:/root/.minio \:指定自定义配置文件所在目录
          6. --console-address ":50000":暴露的控制台端口5000。
          7. /data:指定文件(上传下载)的磁盘,这里/data只是一个变量,真正的值使用的是上面的/usr/loca/minioInstall/data。
      2. window
  3. 方式2:单机部署 - 有纠删码,即要至少挂载4个磁盘(disk1,disk2,disk3,disk4......)
    1. 不使用docker
      1. linux
      2. windows
    2. 使用docker
      1. linux
        1. 第一步:启动
          docker run -d -p 9000:9000 -p 50000:50000 --name minio \
          -v /mnt/data1:/data1 \
          -v /mnt/data2:/data2 \
          -v /mnt/data3:/data3 \
          -v /mnt/data4:/data4 \
          -v /mnt/data5:/data5 \
          -v /mnt/data6:/data6 \
          -v /mnt/data7:/data7 \
          -v /mnt/data8:/data8 \
          minio/minio server /data{1...8} --console-address ":50000"
          1. docker run -d:后台跑
          2. 9000:9000:向宿主机暴露API端口9000
          3. 50000:50000:向宿主机暴露控制台端口50000
          4. --console-address ":50000":向宿主机暴露控制台端口50000
          5. -v /mnt/data1:/data1 \
            -v /mnt/data2:/data2 \
            -v /mnt/data3:/data3 \
            -v /mnt/data4:/data4 \
            -v /mnt/data5:/data5 \
            -v /mnt/data6:/data6 \
            -v /mnt/data7:/data7 \
            -v /mnt/data8:/data8 \
            把你这个目录呀,去挂载到,外面的磁盘上面去,即宿主机的磁盘上面去。
            上面表明启用了8块盘。
        2. 第二步:验证
          1. 第一步:登录控制台
          2. 第二步:简单完成文件上传与下载
          3. 第三步:进到文件所在目录,看见有8个盘:

          4. 第四步:tree命令查看到,之前上传的文件每个目录都会有:

        3. 第三步:总结:这就是纠删码模式,纠删码模式下会对你的磁盘进行平均分盘。如果有8个盘,那么就会有4个去存我们的数据,有4个去存我们的校验码。

           

      2. windows
  4. 方式3:分布式纠删码集群部署:高可用的部署方式
    1. 基础知识
      1. 分布式存储可靠性常用方法
        1. 冗余
          1. minio如何去实现冗余呢?即使用的我们纠删码(EC码)。
        2. 校验
          1. minio如何去实现校验呢?校验我们的Rot Bit,通过hash的方式去判断文件是否损坏了,如果你不是源文件那么hashcode肯定不一样嘛,不一样就表明出问题了。
    2. 业务需求:
      1. 单机纠删码模式下的缺点:虽然也可以恢复数据,但是会有单点故障。
    3. 案例:
      1. 例如,一个16节点的Minio集群,每个节点16块硬盘,就算8台服務器宕机,这个集群仍然是可读的,不过你需要9台服務器才能写数据。
    4. 原理:
      1. 更好的方式是,把我们的磁盘均匀地分布到不同的机器上。比如,我们的多个磁盘,它是一个set。比如,有很多个节点,节点上面会分别挂载多个磁盘。集群给我们分了很多组set,我们一个对象存在一个Set中,这样一来就可以进行一个容错处理:
    5. 分布式集群部署方案图:
      1. 发布的话也很方便:minio server http://host{1...n}/export{1...m}
        1. http://host{1...n}:节点(ip+port),即指定host列表
        2. export{1...m}:文件存储的目录,比如data1、data2、data3、data4、data5、data6。
          1. export是什么?export就是我们的目录。
      2. 发布的话,我们前面还可以加多一个loadbalance(负载均衡器),让文件均衡地落在哪个节点的哪个磁盘上面去,其实就是这么去找的呀。
    6. 详细的分布式纠删码集群部署步骤:
      1. 详细步骤1:基本实现
        1. 第一步:编写启动分布式Minio实例脚本

          1. 案例1:启动分布式Minio实例,8个节点(不同的ip port表明是1个节点),每节点1块盘(export1...8),需要在8个节点上都运行下面的命令:

            1. export MINIO_ROOT_USER = admin
              export MINIO_ROOT_PASSWORD = 12345678
              minio server http://192.168.1.11/export1 http://192.168.1.12/export2 \
              http://192.168.1.13/export3 http://192.168.1.14/export4 \
              http://192.168.1.15/export5 http://192.168.1.16/export6 \
              http://192.168.1.17/export7 http://192.168.1.18/export8
            2. 注:以上的命令不全,因为都没有暴露端口的命令在里面。
          2. 案例2:启动分布式Minio实例,4节点,每节点4块盘,需要在4个节点上都运行下面的命令:
            export MINIO_ROOT_USER = admin
            export MINIO_ROOT_PASSWORD = 12345678
            minio server http://192.168.1.11/export1 http://192.168.1.11/export2 \
            http://192.168.1.11/export3 http://192.168.1.11/export4 \
            http://192.168.1.12/export1 http://192.168.1.12/export2 \
            http://192.168.1.12/export3 http://192.168.1.12/export4 \
            http://192.168.1.13/export1 http://192.168.1.13/export2 \
            http://192.168.1.13/export3 http://192.168.1.13/export4 \
            http://192.168.1.14/export1 http://192.168.1.14/export2 \
            http://192.168.1.14/export3 http://192.168.1.14/export4  
            1. 注:同一个ip port,后面挂载3个export嘛。
          3. 为了方便,我这里写了一个脚本来启动:vim minio-cluster.sh:
        2. 第二步:停掉docker:
          1. docker ps,获取id
          2. docker stop xxxxxx
        3. 第三步:执行脚本:./minio -cluster.sh
        4. 第四步:验证
          1. 第1步:ps -ef|grep minio查看效果:
            1. 从上图可以看出,我们启动了4节点(9001~9004),控制台端口(50001~50004)。
          2. 第2步:浏览器访问4个控制台(5001~5004)
          3. 第3步:简单操作文件上传与下载
          4. 第4步:tree命令查询效果
        5. 第五步:基于nginx实现loadbalancer。需求:这样一来的话,我们真正去使用的话肯定要有一个入口嘛。即如果是这种分布式纠删码部署模式下,我们肯定是要有入口的,要有一个统一的入口啊。那统一的入口的话,怎么做呀?是不是要有一个负载均衡器(loadbalance)。
          1. 第1步:配置nginx
            upstream minio {
                server 192.168.3.14:9001;
                server 192.168.3.14:9002;
                server 192.168.3.14:9003;
                server 192.168.3.14:9004;
            }
            upstream console {
                ip_hash;
                server 192.168.3.14:50001;
                server 192.168.3.14:50002;
                server 192.168.3.14:50003;
                server 192.168.3.14:50004;
            }
            server {
                listen 9000;
                listen [::]:9000;
                server_name localhost;
            
                # To allow special characters in headers
                ignore_invalid_headers off;
                # Allow any size file to be uploaded.
                # Set to a value such as 1000m; to restrict file size to a specific value
                client_max_body_size 0;
                # To disable buffering
                proxy_buffering off;
                location / {
                    proxy_set_header Host $http_host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;
            
                    proxy_connect_timeout 300;
                    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
                    proxy_http_version 1.1;
                    proxy_set_header Connection "";
                    chunked_transfer_encoding off;
                    proxy_pass http://minio;
                }
            }
            server {
                listen 50000;
                listen [::]:50000;
                server_name localhost;
                # To allow special characters in headers
                ignore_invalid_headers off;
                # Allow any size file to be uploaded.
                # Set to a value such as 1000m; to restrict file size to a specific value
                client_max_body_size 0;
                # To disable buffering
                proxy_buffering off;
                location / {
                    proxy_set_header Host $http_host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;
            
                    proxy_set_header X-NginX-Proxy true;
                    proxy_connect_timeout 300;
                    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
                    proxy_http_version 1.1;
                    proxy_set_header Connection "";
                    chunked_transfer_encoding off;
                    proxy_pass http://console;
            }
            }
            第a步:配置一个upstream,9001~9004。
            第b步:proxy_pass http://minio;,我们通用proxy_pass访问这个minio。
            第c步:listen 9000;,我把我的这个端口变成9000,是不是就可以了第d步:listen 50000,同样地,我们把控制台的端口变成50000
            第e步:我们通过ip_hash的方式,进行一个路由。
          2. 第2步:通过指定的配置文件启动nginx:sbin nginx

          3. 第3步:验证nginx启动:ps ef|grep nginx

        6. 第六步:测试

          1. http://192.168.3.14:50001/dashboard,并完成简单的上传与下载文件

      2. 详细步骤2:使用docker compost部署分布式集群的minio

        1. 第一步:请下载docker-compose.yaml和nginx.conf到你当前的工作目录。docker-compose.yaml是通过docker-compose pull直接一下子把它拉下来的。nginx.conf是它提供的一个配置文件,里面有nginx的配置:

          1. 第1步:docker-compose pull:直接一下子把它拉下来:

          2. 第2步:打开它提供的配置文件,查看nginx配置。
        2. 第二步:docker-compose up

      3. 详细步骤3:扩展:磁盘不够了加磁盘,加节点都很多方便。

        1. 比如我之前只部署了32个节点,部署了32个磁盘。现在,我要把它扩充到64个。怎么做?即原来的32个节点上,再加上新的32个节点即可。

    7. 分布式纠删码集群部署注意事项(官网翻译):
      1. 分布式Minio里所有的节点需要有同样的access秘钥和secret秘钥,这样这些节点才能建立联接。 为了实现这个,你需要在执行minio server命令之前,先将access秘钥和secret秘钥export成环境变量。新版本使用MINIO_ROOT_USER&MINIO_ROOT_PASSWORD。
        1. ps:集群部署模式下,要配置权限认证、用户名、密码,即这些的话每台机器上都要跑一遍。
      2. 分布式Minio使用的磁盘里必须是干净的,里面没有数据。
      3. 下面示例里的IP仅供示例参考,你需要改成你真实用到的IP和文件夹路径。
        1. ps:换成物理的真实的IP地址,充分保证了各个节点之间要可以通信。比如,下面那些可能都是你局域网的IP PORT,保证了各个节点之间要可以通信。
      4. 分布式Minio里的节点时间差不能超过3秒,你可以使用NTP来保证时间一致。
        1. ps:重要,高亮标注。
      5. 在Windows下运行分布式Minio处于实验阶段,请悠着点使用。
  5. 总结:
    1. ps:大家注意啊,如果你们自己玩的话,机器也不是怎么好的话(4G 8G内存而已),你们可以搞个单机模式嘛。纠删码呀,都可以,纠删码无非就是加几块磁盘嘛。集群模式的话,大家可以在虚拟机中docker容器里面去玩啊。其实,部署还是非常方便的,这也是minio能够普及的一个原因。

三 mc admin使用(用户CRUD、文件的权限控制(只读、可写))

  1. 概述
    1. MinIO Client(mc)提供了“ admin”子命令来对您的MinIO部署执行管理任务:
      1. service 服务重启并停止所有MinIO服务器
      2. update 更新更新所有MinIO服务器
      3. info 信息显示MinIO服务器信息
      4. user 用户管理用户
      5. group 小组管理小组
      6. policy MinIO服务器中定义的策略管理策略
      7. config 配置管理MinIO服务器配置
      8. heal 修复MinIO服务器上的磁盘,存储桶和对象
      9. profile 概要文件生成概要文件数据以进行调试
      10. top 顶部提供MinIO的顶部统计信息
      11. trace 跟踪显示MinIO服务器的http跟踪
      12. console 控制台显示MinIO服务器的控制台日志
      13. prometheus Prometheus管理Prometheus配置
      14. kms kms执行KMS管理操作
  2. 比较常用的命令
    1. 服务器信息显示
      1. info:信息显示MinIO服务器信息
      2. trace:跟踪显示MinIO服务器的http跟踪
      3. console:控制台显示MinIO服务器的控制台日志
    2. 服务器管理
      1. service:服务重启并停止所有MinIO服务器
      2. policy MinIO:服务器中定义的策略管理策略
        1. 文件及文件夹(桶)的权限控制(只读(桶的下载)、可写(桶的上传))
      3. config:配置管理MinIO服务器配置,如服务器地址
    3. 用户及小组crud
      1. user:用户管理用户
      2. group:小组管理小组
  3. 案例1:用户管理
    #命令列表
    mc admin 
    #命令列表
    mc admin user --help
    # 新建用户, 此时用户没有任何权限(甚至登录控制台的权限都没有),此时要做权限管理(策略管理)
    mc admin user add minio-server fox
    mc admin user add minio-server fox02 12345678
    # 查看用户
    mc admin user list minio-server
    # 禁用用户
    mc admin user disable minio-server fox02
    # 启用用户
    mc admin user enable minio-server fox02
    # 查看用户信息
    mc admin user info minio-server fox
    # 删除用户
    mc admin user remove minio-server fox02
    #查看用户的文件及文件夹(桶)权限控制
    mc admin user policy minio-server fox02
  4. 案例2:策略管理
    1. policy命令,用于添加,删除,列出策略,获取有关策略的信息并为MinIO服务器上的用户设置策略。
      #命令列表
      mc admin policy --help
      #列出MinIO上的所有固定策略(
        即所有的操作权限:
              diagnostics:用于我们管控的,用于监测的
              readonly:只读
              readwrite:读写
              writeonly:只写
              consoleAdmin:控制台登录权限 

      mc admin policy list minio-server
      # 查看 plicy 信息。查看读写权限的信息。
      mc admin policy info minio-server readwrite
    2. 添加新的策略:

      1. 第一步:编写策略文件(权限脚本):/root/tulingmall.json 》vim tulingmall.json 》粘贴下面代码 》wq

        {
           "Version" : "2012-10-17" ,
           "Statement" : [
            {
              "Effect" : "Allow" , #允许
              "Action" : [
                  "s3:GetBucketLocation" #获取桶的路径的权限
                  "s3:GetObject"  #获取具体对象(下载)的权限
               ],
              "Resource" : [
                  "arn:aws:s3:::tulingmall"  #只针对tulingmall这个桶
               ]
            },{
              "Effect" : "Allow" , #允许
              "Action" : [
                  "s3:*"  #所有的行为都被允许
               ],
              "Resource" : [
                  "arn:aws:s3:::tulingmall/*" #只针对tulingmall这个桶和此桶的所有子桶
               ]
            }
        ]
        }

      2. 第二步:tulingmall.json添加到策略数据库
        # 添加新的策略
        # 这里定义一个“tulingmall-admin”角色,并指定采用的策略
        mc admin policy add minio-server tulingmall-admin /root/tulingmall.json

        # 查看策略信息时,会多出一个策略
        mc admin policy list minio-server
         
      3. 第三步: 给新建的用户添加绑定新的策略(添加某些权限)
        mc admin user add minio-server fox03 12345678
        # 设置用户的访问策略
        mc admin policy set minio-server tulingmall-admin user = fox03
      4. 第四步:验证
        1. 测试: fox03/12345678 登录 minio 控制台 http://192.168.3.14:50000/ ,只能操作(上传文件、下载文件等等) tulingmall bucket(桶,即文件夹)
      5. 附:行为列表
        "Action": [
           "s3:GetBucketLocation",
           "s3:ListBucket",
           "s3:GetObject",
           "s3:PutObject",
           "s3:DeleteObject"
        ]

四 Minio客户端(minio client)使用

  1. 概述
    1. minio client提供了一套的类似于linux的命令,非常方便,如mc ls、mc mb等:
      ls 列出文件和文件夹(桶)。
      mb 创建一个存储桶或一个文件夹。
      cat 显示文件和对象内容。
      pipe 将一个 STDIN 重定向到一个对象或者文件或者 STDOUT
      share 生成用于共享的 URL
      cp 拷贝文件和对象。
      mirror 给存储桶和文件夹做镜像。
      find 基于参数查找文件。
      diff 对两个文件夹或者存储桶比较差异。
      rm 删除具体的一个文件和对象。
      events 管理对象通知。
      watch 监视文件和对象的事件。
      policy 管理访问策略。
      config 管理 mc 配置文件。客户端与服务端通信,客户端得指定服务器(minio server)所在的IP+端口吧。
      update 检查软件更新。
      version 输出版本信息。
  2. 业务
    1. Minio客户端(MC)怎么去操作Minio呢?
  3. 详细步骤:英文官网文档:MINIO CLIENT目录下
    1. 第一步:查看Minio客户端的命令:linux 》cmd 》mc:
      1. 通过cp、ls、mb等等这些命令,完成:使用Minio客户端创建一个桶、删除一个桶等等的minio操作。
    2. 第二步:部署客户端
      wget http://dl.minio.org.cn/client/mc/release/linux-amd64/mc
      chmod + x mc
      ./mc --help
      mv mc /usr/local/sbin/
      注:为了方便使用mc+...命令,不用每次都要到mc所在的目录,我们可以把下载下来的可执行文件复制到sbin目录下。同理,windows的话把可把下载下来可执行文件(mc.exe)复制到system32下。
    3. 第三步:配置mc
      mc 将所有的配置信息都存储在 ~/.mc/config.json 文件中:
      # 查询mc host配置(mc config可用命令参数列表)
      mc config host ls
      # 添加 minio 服务,即给MC连接一哪台minio server上
      mc config host add minio-server http://192.168.32.133:9000 admin 12345678
      # 删除host, “minio-server”为服务器的名称
      mc config host remove minio-server
    4. 第四步:mc命令使用
      1. mc coinfig

      2. mc config host ls
      3. 连接某个minio服务器,查看里面的某些目录的文件信息:
        1. ls tuling-minio:带上host(minio server的名称)
        2. ls tuling-minio/springcloud:查看tuling-minio服务器中springcloud的文件信息
      4. 查看某个minio服务器的桶(目录)信息:
        1. 添加minio server到mc中,并取一个名称
        2. mc ls 服务器名称
    5. 第五步:演示上传、下载 ,并在控制台验证
      1. 第1步:添加minio server到mc中(mc连接上minio server),并取一个名称
      2. 第2步:
        # linux/windows minion server:查询minio 服务上的所有 buckets( 文件和文件夹 )
        mc ls minio-server
         
        # linux minion server:下载文件到本地(linux本地文件夹)
        mc cp minio-server/tulingmall/fox/fox.jpg /tmp/
        # windows minion server:下载文件到本地(windows本地文件夹)
        mc cp minio-server/tulingmall/fox/fox.jpg D:/tmp/
         
        # 删除minio server中的文件
        mc rm minio-server/tulingmall/fox/fox.jpg
         
        #linux minion server:linux的本地的文件,上传到minio server ,其中tulingmall是桶(文件夹)
        mc cp zookeeper.out minio-server/tulingmall/
        #windows minion server:windows的本地的文件,上传到minio server,其中tulingmall是桶(文件夹)
        mc cp zookeeper.out minio-server/tulingmall/
    6. 第六步:演示Bucket管理,并在控制台验证
      # 创建 bucket
      mc mb minio-server/bucket01
      # 删除 bucket
      mc rb minio-server/bucket02
      # bucket 不为空,可以强制删除 慎用
      mc rb --force minio-server/bucket01
      # 查询bucket03磁盘使用情况
      mc du minio-server                 查看总共用了多少
      mc du minio-server/bucket03 查看bucket03用了多少 

五 Minio Java Client使用:查官网案例和api使用手册

  1. 概述
    1. MinIO Java Client(客户端) SDK 提供简单的 API 来访问minio服务端
    2. 官方 demo: https://github.com/minio/minio-java  
    3. 官方文档: https://docs.min.io/docs/java-client-api-reference.html
      英文官网 》MINIO SDKS 》Java Client Quickstart Guide(对java的支持)/ Java Client API Reference(API的具体用法(操作))
  2. 文件上传
    1. 第一步:引入依赖
      <dependency>
              <groupId> io.minio </groupId>
              <artifactId> minio </artifactId>
      <version> 8.3.0 </version>
      </dependency>
              <dependency>
              <groupId> me.tongfei </groupId>
              <artifactId> progressbar </artifactId> 用于通信的依赖
              <version> 0.5.3 </version>
      </dependency>
      <dependency>
              <groupId> com.squareup.okhttp3 </groupId>
              <artifactId> okhttp </artifactId> 用于通信的依赖
              <version> 4.8.1 </version>
      </dependency>
    2. 第二步:连接上Minio Server(服务器),上传文件到具体的桶(文件夹)中
      package com.atguigu.pojo;
      
      import io.minio.BucketExistsArgs;
      import io.minio.MakeBucketArgs;
      import io.minio.MinioClient;
      import io.minio.UploadObjectArgs;
      import io.minio.errors.MinioException;
      import java.io.IOException;
      import java.security.InvalidKeyException;
      import java.security.NoSuchAlgorithmException;
      
      public class FileUploader {
          public static void main(String[] args)
                  throws IOException, NoSuchAlgorithmException, InvalidKeyException {
              try {
                   // Create a minioClient with the MinIO server playground, its access key and secret key.
                   // 获取Minio Java client(客户端)对象
                   MinioClient minioClient =
                           MinioClient.builder() //建造者模式
                                      .endpoint("http://192.168.32.133:9000") //绑定地址
                                      .credentials("admin", "12345678") //绑定用户名和密码
                                      .build(); //建造
                  // 创建bucket
                  String bucketName = "tulingmall";
                  boolean exists =
                          minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
                  if (!exists) {
                      // 判断bucket是否存在。如果不存在,创建一个bucket。
                      minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                  }
                  // 上传一个对象(一个文件)
                  minioClient.uploadObject(
                          UploadObjectArgs.builder()
                                  .bucket(bucketName)
                                  .object("tuling-mall-master.zip")//自定义对象的名称
                                  .filename("F:\\mall\\tuling-mall-master.zip") //本地磁盘上,上传的对象(文件)路径+名称
                                  .build());
                  System.out.println("上传文件成功");
              } catch (MinioException e) {
                  System.out.println("Error occurred: " + e);
                  System.out.println("HTTP trace: " + e.httpTrace());
              }
          }
      }
      
    3. 第三步:登录控制台,找到桶,查看文件
  3. 文件下载
    1. 第一步:引入依赖
    2. 第二步:连接上Minio Server(服务器),从具体的桶(文件夹)中下载对象(文件)
      package com.atguigu.pojo;
      
      import io.minio.DownloadObjectArgs;
      import io.minio.MinioClient;
      
      public class DownLoadDemo {
          public static void main(String[] args) {
              // Create a minioClient with the MinIO server playground, its access key and secret key.
              // 获取Minio Java client(客户端)对象
              MinioClient minioClient =
              MinioClient.builder()
                      .endpoint("http://192.168.3.14:9000")
                      .credentials("admin", "12345678")
                      .build();
              // Download object given the bucket, object name and output file name
              try {
                  minioClient.downloadObject(
                          DownloadObjectArgs.builder()
                                  .bucket("tulingmall")  //桶的名称
                                  .object("fox/fox.jpg") //桶(tulingmall) 》 子桶(fox) 》 对象(fox.jpg)
                                  .filename("fox.jpg")   //下载到本地磁盘的路径与名称(可自定义对象名称)
                                  .build());
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
    3. 第三步:看到下载的文件
  4. Spring boot整合minio
    1. 业务需求:
      1. 上面例子的问题:我们都是通过api去操作的,而真正开发过程中我们创建的肯定是一个springboot的应用。而要想在springboot中去操作minio Server,关键点在于把“ 获取Minio Java client(客户端)对象 ”的这部分代码变成一个可重用的。最好的方法是,把“ Minio Java client(客户端)对象 ”交给spring容器去管理,后续我们可以直接使用它去调用api完成对服务端的操作。
      2. 可以对官网代码进一步封装,写出自己的一个Uitl.java工具类
      3. 官方并没有提供minio server和spingboot的整合包,需要我们自己去实现整合
    2. 原理
      1. 把MinioClient对象交给spring容器去管理:
        1. 方案1:自己写一个XxxConfigure.java的配置类。
        2. 方案2:可以自己写一个springboot-minio-starter的启动类(起步依赖),其中自己去实现一个自动配置类。自动配置类中配置minio的XxxFactory.java,XxxFactory.java生产的是自动配置类的实例。
      2. 备注:springboot无非就是对spring做进一步的封装,利用了自动配置类简化了许多的配置。
    3. 方案1:自己写一个XxxConfigure.java的配置类,用于构建MinioClient对象,并交给spring管理。
      1. 第一步:依赖
        <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
            <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.6.3</version>
                <relativePath/> <!-- lookup parent from repository -->
            </parent>
            <groupId>com.atguigu</groupId>
            <artifactId>mybatisplus_demo01</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <name>mybatisplus_demo01</name>
            <description>Demo project for Spring Boot</description>
            <properties>
                <java.version>8</java.version>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </dependency>
                <dependency>
                    <groupId>io.minio</groupId>
                    <artifactId>minio</artifactId>
                    <version>8.3.0</version>
                </dependency>
                <dependency>
                    <groupId>me.tongfei</groupId>
                    <artifactId>progressbar</artifactId>
                    <version>0.5.3</version>
                </dependency>
                <dependency>
                    <groupId>com.squareup.okhttp3</groupId>
                    <artifactId>okhttp</artifactId>
                    <version>4.8.1</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-test</artifactId>
                    <scope>test</scope>
                </dependency>
                <dependency>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                    <version>3.5.1</version>
                </dependency>
                <dependency>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <optional>true</optional>
                </dependency>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <scope>runtime</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                    <groupId>commons-io</groupId>
                    <artifactId>commons-io</artifactId>
                    <version>2.6</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>fastjson</artifactId>
                    <version>LATEST</version>
                </dependency>
                <dependency>
                    <groupId>com.squareup.okhttp3</groupId>
                    <artifactId>okhttp</artifactId>
                    <version>4.8.1</version>
                </dependency>
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                    </plugin>
                    <!--加上这个是为了防止出现maven打包错误-->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-resources-plugin</artifactId>
                        <version>3.1.0</version><!--亲测:3.1.0和2.4.3都可以。-->
                    </plugin>
                </plugins>
            </build>
        
        </project>
        
      2. 第二步:.yml:配置创建minio对象所需的3个参数:
        minio:
          endpoint: http://192.168.32.133:9000
          accesskey: admin
          secretKey: 12345678
          bucketName: bucker03
      3. 第三步:MinioProperties.java:属性配置类
        import lombok.Data;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.stereotype.Component;
        
        @Data
        @Component
        @ConfigurationProperties(prefix = "minio")  //定义前缀
        public class MinioProperties {
            private String endpoint;    //端点
            private String accessKey;   //用户名
            private String secretKey;   //密码
        }
      4. 第四步:MinioConfig.java:minio配置类
        package com.atguigu.springboot;
        
        import io.minio.MinioClient;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        
        @Configuration
        public class MinioConfig {
            @Autowired
            private MinioProperties minioProperties;
            @Bean
            public MinioClient minioClient(){
                //  构建MinioClient对象需要3个参数:
                //      第1步:这3个参数可以通过yml的方式配置在配置文件中。
                //      第2步:并且通过1个属性配置类来封装便于获取。
                MinioClient minioClient = MinioClient.builder()
                                .endpoint(minioProperties.getEndpoint())
                                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                                .build();
                return minioClient;
            }
        }
      5. 第五步:MinioController.java:开放restful接口
        package com.atguigu.springboot;
        import com.alibaba.fastjson.JSON;
        import io.minio.*;
        import io.minio.messages.Item;
        import lombok.extern.slf4j.Slf4j;
        import org.apache.tomcat.util.http.fileupload.IOUtils;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.web.bind.annotation.*;
        import org.springframework.web.multipart.MultipartFile;
        import javax.servlet.http.HttpServletResponse;
        import java.io.IOException;
        import java.io.InputStream;
        import java.net.URLEncoder;
        import java.text.DecimalFormat;
        import java.util.*;
        
        @RestController
        @Slf4j
        public class MinioController {
            @Autowired
            private MinioClient minioClient;
            //  .yml(目录、文件夹)。因为中配置桶用户去做上传下载操作时,要把要操作的具体的桶传过来。
            @Value("${minio.bucketName}")
            private String bucketName;
            @GetMapping("/list")
            public void list() throws Exception {
                //获取bucket列表
                Iterable<Result<Item>> myObjects = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());
                Iterator<Result<Item>> iterator = myObjects.iterator();
                List<Object> items = new ArrayList<>();
                String format = "{'fileName':'%s','fileSize':'%s'}";//自定义输出格式
                //遍历所有的bucket
                while (iterator.hasNext()) {
                    Item item = iterator.next().get();
                    items.add(JSON.parse(String.format(format, item.objectName(), formatFileSize(item.size()))));
                }
                //return items;
                System.out.println(items.size());
            }
            @PostMapping("/upload")
            public void upload(@RequestParam(name = "file", required = false) MultipartFile[] file) {
                if (file == null || file.length == 0) {
                    /*return Res.error("上传文件不能为空");*/
                    System.out.println("上传文件不能为空");
                }else {
                    //上传多个文件
                    List<String> orgfileNameList = new ArrayList<>(file.length);
                    for (MultipartFile multipartFile : file) {
                        String orgfileName = multipartFile.getOriginalFilename();
                        orgfileNameList.add(orgfileName);
                        try {
                            //文件上传
                            InputStream in = multipartFile.getInputStream();
                            minioClient.putObject(
                                    PutObjectArgs.builder().bucket(bucketName).object(orgfileName).stream(
                                            in, multipartFile.getSize(), -1)
                                            .contentType(multipartFile.getContentType())
                                            .build());
                            in.close();
                        } catch (Exception e) {
                            log.error(e.getMessage());
                            System.out.println("上传失败");
                            //return Res.error("上传失败");
                        }
                    }
                    Map<String, Object> data = new HashMap<String, Object>();
                    data.put("bucketName", bucketName);
                    data.put("fileName", orgfileNameList);
                    //return Res.ok("上传成功",data);
                    System.out.println("上传成功");
                }
            }
            @RequestMapping("/download/{fileName}")
            public void download(HttpServletResponse response, @PathVariable("fileName") String fileName) {
                InputStream in = null;
                try {
                    // 获取对象信息
                    StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
                    response.setContentType(stat.contentType());
                    response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                    //文件下载
                    //因为这里响应的是浏览器,所以返回的是一个流
                    in = minioClient.getObject(
                            GetObjectArgs.builder()
                                    .bucket(bucketName)
                                    .object(fileName)
                                    .build());
                    IOUtils.copy(in, response.getOutputStream());
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            log.error(e.getMessage());
                        }
                    }
                }
            }
            @DeleteMapping("/delete/{fileName}")
            public void delete(@PathVariable("fileName") String fileName) {
                try {
                    minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
                } catch (Exception e) {
                    log.error(e.getMessage());
                    //return Res.error("删除失败");
                    System.out.println("删除失败");
                }
                //return Res.ok("删除成功",null);
                System.out.println("删除成功");
            }
            private static String formatFileSize(long fileS) {
                DecimalFormat df = new DecimalFormat("#.00");
                String fileSizeString = "";
                String wrongSize = "0B";
                if (fileS == 0) {
                    return wrongSize;
                }
                if (fileS < 1024) {
                    fileSizeString = df.format((double) fileS) + " B";
                } else if (fileS < 1048576) {
                    fileSizeString = df.format((double) fileS / 1024) + " KB";
                } else if (fileS < 1073741824) {
                    fileSizeString = df.format((double) fileS / 1048576) + " MB";
                } else {
                    fileSizeString = df.format((double) fileS / 1073741824) + " GB";
                }
                return fileSizeString;
            }
        }
        
      6. 第六步:测试
        1. 列表
        2. 上传
        3. 下载
        4. 删除

六 Minio控制台使用详解(对应mc命令)

猜你喜欢

转载自blog.csdn.net/aiwokache/article/details/128236989