MinIO | 高性能,对Kubernetes友好的对象存储
MinIO High Performance Object Storage — MinIO Object Storage for Linux
一 分布式文件系统应用场景
- fastDFS
- 缺点:
- 部署麻烦。
- 因为文件名是自动生成的,所以如果要处理文件的话,还要经过额外的编码。
- 缺点:
- Minio介绍
- 应用场景
- 互联网海量非结构化数据的存储需求,如
电商网站:海量商品图片视频网站:海量视频文件网盘 : 海量文件社交网站:海量图片
-
对于中小型企业,如果不选择存储上云,那么 Minio 是个不错的选择,麻雀虽小,五脏俱全。当然 Minio 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3、 MicroSoft Azure。
-
非结构化数据与结构化数据
-
非结构化数据:文件、音频、视频、图片
-
结构化数据:如常见的关系型数据库(mysql、oracle、sqlserver)用表存储某个网站的会员信息。
-
- 互联网海量非结构化数据的存储需求,如
-
minio是什么?
- MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。
-
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服 务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成 本。
-
- Minio是使用go语言编写的,天然支持跨平台。
- MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。
- minio的优点
-
部署简单: 一个single二进制文件即是一切,还可支持各种平台。
-
minio支持海量存储,可按zone扩展(原zone不受任何影响),支持单个对象最大5TB;
-
兼容Amazon S3接口,充分考虑开发人员的需求和体验;
-
低冗余且磁盘损坏高容忍,标准且最高的数据冗余系数为2(即存储一个1M的数据对象,实际占用 磁盘空间为2M)。但在任意n/2块disk损坏的情况下依然可以读出数据(n为一个纠删码集合(Erasure Coding Set)中的disk数量)。并且这种损坏恢复是基于单个对象的,而不是基于整个存储卷的。
-
读写性能优异
-
- 应用场景
-
MinIO的基础概念
-
Object:一个文件 / 视频 / 音频 / 字节流 / Anything......
-
Bucket:翻译过来是桶,可理解为一个顶层的目录(文件夹)。Bucket是用来装Object的。
-
Drive:即存储数据的磁盘。
-
Set :分布式集群场景或多磁盘场景下。一组Drive的集合。
-
备注:
-
当MinIO集群服务启动以后,表明已经把Drive配置好了(当然,我们需要去指定Drive的位置、存储目录)。
-
Object和Bucket是我们真正去操作、控制的2个东西,比如想把文件存储到哪个Bucket下面,我们要上传哪些Object。
-
-
-
纠删码EC(Erasure Code): 备份与恢复
- 定义、流原:
-
纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code将 (ps:用户上传的每一个对象) 对象拆分成N/2 数据和N/2 奇偶校验块。 这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块),你仍可以从剩下的盘中的数据进行恢复。
-
BLOCK:块。在minio中,一个block大概是10M。
-
DATA BLOCK:数据块。
-
PARITY BLOCK:校验块。
-
-
- 作用:
- EC机制是用来保证MinIO高可靠性。
- 第一步:EC机制是用来校验数据是否损坏(如本身磁盘(硬件)就损坏了,如单单数据的损坏)。
- 校验原理(Bit Rot Protection):直接对MinIO中的文件进行一个hash。因为hash码是唯一的,所以如果hash码不变说明文件没有损坏,反之说明文件已经损坏了。
- 第二步:EC机制是用来做数据冗余和恢复的
- 官网纠删码的作用描述:Minio使用纠删码 erasure code 和校验和 checksum 来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。
- 如果数据损坏,可以校验是否是源文件数据损坏了,并且可以使用EC机制highwayhash来处理数据损坏(Bit Rot Protection)。
- minIO纠删码还原,是依赖于EC盘的数量去做处理的。
- 规则1:所有的盘都是可读的。
- 规则2:坏死盘数量不能大于n/2+1,大于的话就恢复不了数据。
- 规则3:如果是坏死盘,MinIO是不允许我们再上传新的文件到坏死盘上面去的。
- 规则4:如果坏死的磁盘大于等于N/2,那么minio是不允许上传文件的。只能坏死的磁盘不超过一半(n/2)时,minio才允许上传文件的。
- 规则5:必须要有大于等于N/2+1的盘是可读的正常状态的,,才能保证有EC盘数据的存在,也才能有可能通过EC机制来恢复数据。
- 第一步:EC机制是用来校验数据是否损坏(如本身磁盘(硬件)就损坏了,如单单数据的损坏)。
- EC机制是用来保证MinIO高可靠性。
- 案例1:EC机制下的数据冗余与恢复
- 有6块盘(因为EC机制生效最少需要4块盘)。
- 其中4块盘用于存储用户的数据,比如1.jpg。
- 其中2块盘用于存储对它EC机制编号后生成的1.jpg。
- 如果丢失1份数据,可以是4块盘中之一的1.jpg,也可以是2块盘之一EC后的1.jpg。那么,根据一定的算法可以恢复和还原。
- 如果丢失2份数据,而且是2块盘EC后的1.jpg都丢失了,那么不是还有4个盘的1.jpg嘛。
- 如果丢失3份数据,4块盘中之一和2块盘EC后的1.jpg都丢失了,那么就无法去恢复和还原了。
- 案例2:为了保证数据的冗余和恢复MinIO推荐使用方式
- MinIO推荐平均去分配
- 8个盘。
- 4个盘存源数据,4个盘存EC数据。
- 意味着,不管在什么情况下,如果丢失的数据<=4个盘,数据仍可以恢复。
- MinIO推荐平均去分配
- 定义、流原:
- 存储形式
- 开启EC模式下的存储形式:
- 存储方案
- MinIO集群的存储方案:
- 第一步:搭建MinIO集群
- 第二步:MinIO集群提供操作的API接口,默认端口9000,可以读写集群中的文件。
- 第三步:MinIO集群提供的控制台,端口随便定义,比如50000
- MinIO集群的存储方案:
二 Minio环境搭建
- 概述:3种模式
- 方式1:单机部署 - 无纠删码
- 不使用docker
- linux:systemctl stop firewalld(关闭防火墙)
- 优化前的启动
- 第一步:下载: wget https://dl.min.io/server/minio/release/linux-amd64/minio
- 第二步:chmod +x minio,把它变成可执行文件。
- 第三步:./minio server /data,指定磁盘位置(数据保存在哪)并运行。这里没有用后台启动,想跟大家一起去看看日志。
-
第四步:查看日志
- 第五步:验证:登录控制台,操作一下文件的上传、下载
- 优化后的启动
- 第一步:下载: wget https://dl.min.io/server/minio/release/linux-amd64/minio
- 第二步:chmod +x minio,把它变成可执行文件。
- 第三步:指定登录控制台使用的用户名和密码:
export MINIO_ROOT_USER=adminexport MINIO_ROOT_PASSWORD=12345678
- 第四步:使用自定义的配置文件所在的路径:
./minio server --config-dir /usr/local/minioInstall/config /usr/local/minioInstall/data- --config-dir /usr/local/minioInstall/config:自定义配置文件所在的路
- /usr/local/minioInstall/data:上传下载的文件所在的路径
- 第五步:指定登录控制台监听的端口为5000:
./minio server --console-address ":50000" /usr/local/minioInstall/data- --console-address ":50000":指定登录控制台监听的端口为5000
- 第六步:验证:登录控制台,操作一下文件的上传、下载
- 总结
- 特点1:这就是我们通过单机的,没有纠删码的部署模式。为什么没有纠删码呢?因为我们这里只分配了1块磁盘呀,纠删码部署模式下是要求有4块磁盘以上的吧。
- 特点2:在没有纠删码部署模式下,/usr/local/minioInstall/data保存的文件是源文件,而并非经过加密后的文件:
- 优化前的启动
- window
- 第一步:下载:http://dl.minio.org.cn/server/minio/release/windows-amd64/minio.exe
- 第二步:minio.exe server D:\,指定磁盘位置并运行
- linux:systemctl stop firewalld(关闭防火墙)
- 使用docker
- linux:中文官网文档更新慢(配置中没有暴露控制台的访问端口),一定要去参考英文官网的英文文档
-
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
-
docker run -d: 表明是后台启动
-
-e "MINIO_ROOT_USER=admin" \:指定控制台用户名
-
-e "MINIO_ROOT_PASSWORD=12345678" \:指定控制台密码
-
-v /usr/loca/minioInstall/data:/data \:指定挂载的目录,文件(上传下载)所在的挂载目录
-
:/data:变量,对应下面的/data
-
-
-v /mnt/config:/root/.minio \:指定自定义配置文件所在目录
-
--console-address ":50000":暴露的控制台端口5000。
-
/data:指定文件(上传下载)的磁盘,这里/data只是一个变量,真正的值使用的是上面的/usr/loca/minioInstall/data。
-
-
- window
- linux:中文官网文档更新慢(配置中没有暴露控制台的访问端口),一定要去参考英文官网的英文文档
- 不使用docker
- 方式2:单机部署 - 有纠删码,即要至少挂载4个磁盘(disk1,disk2,disk3,disk4......)
- 不使用docker
- linux
- windows
- 使用docker
- linux
-
第一步:启动
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"-
docker run -d:后台跑
-
9000:9000:向宿主机暴露API端口9000
-
50000:50000:向宿主机暴露控制台端口50000
-
--console-address ":50000":向宿主机暴露控制台端口50000
-
-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块盘。
-
-
第二步:验证
-
第一步:登录控制台
-
第二步:简单完成文件上传与下载
-
第三步:进到文件所在目录,看见有8个盘:
-
第四步:tree命令查看到,之前上传的文件每个目录都会有:
-
-
第三步:总结:这就是纠删码模式,纠删码模式下会对你的磁盘进行平均分盘。如果有8个盘,那么就会有4个去存我们的数据,有4个去存我们的校验码。
-
- windows
- linux
- 不使用docker
- 方式3:分布式纠删码集群部署:高可用的部署方式
- 基础知识
-
分布式存储可靠性常用方法
-
冗余
-
minio如何去实现冗余呢?即使用的我们纠删码(EC码)。
-
-
校验
-
minio如何去实现校验呢?校验我们的Rot Bit,通过hash的方式去判断文件是否损坏了,如果你不是源文件那么hashcode肯定不一样嘛,不一样就表明出问题了。
-
-
-
- 业务需求:
- 单机纠删码模式下的缺点:虽然也可以恢复数据,但是会有单点故障。
- 案例:
- 例如,一个16节点的Minio集群,每个节点16块硬盘,就算8台服務器宕机,这个集群仍然是可读的,不过你需要9台服務器才能写数据。
- 原理:
- 更好的方式是,把我们的磁盘均匀地分布到不同的机器上。比如,我们的多个磁盘,它是一个set。比如,有很多个节点,节点上面会分别挂载多个磁盘。集群给我们分了很多组set,我们一个对象存在一个Set中,这样一来就可以进行一个容错处理:
- 分布式集群部署方案图:
- 发布的话也很方便:minio server http://host{1...n}/export{1...m}
- http://host{1...n}:节点(ip+port),即指定host列表
- export{1...m}:文件存储的目录,比如data1、data2、data3、data4、data5、data6。
- export是什么?export就是我们的目录。
- 发布的话,我们前面还可以加多一个loadbalance(负载均衡器),让文件均衡地落在哪个节点的哪个磁盘上面去,其实就是这么去找的呀。
- 发布的话也很方便:minio server http://host{1...n}/export{1...m}
- 详细的分布式纠删码集群部署步骤:
- 详细步骤1:基本实现
-
第一步:编写启动分布式Minio实例脚本
-
案例1:启动分布式Minio实例,8个节点(不同的ip port表明是1个节点),每节点1块盘(export1...8),需要在8个节点上都运行下面的命令:
-
export MINIO_ROOT_USER = adminexport MINIO_ROOT_PASSWORD = 12345678minio 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:启动分布式Minio实例,4节点,每节点4块盘,需要在4个节点上都运行下面的命令:
export MINIO_ROOT_USER = adminexport MINIO_ROOT_PASSWORD = 12345678minio 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
-
注:同一个ip port,后面挂载3个export嘛。
-
-
为了方便,我这里写了一个脚本来启动:vim minio-cluster.sh:
-
-
第二步:停掉docker:
-
docker ps,获取id
-
docker stop xxxxxx
-
-
第三步:执行脚本:./minio -cluster.sh
- 第四步:验证
- 第1步:ps -ef|grep minio查看效果:
- 从上图可以看出,我们启动了4节点(9001~9004),控制台端口(50001~50004)。
- 第2步:浏览器访问4个控制台(5001~5004)
- 第3步:简单操作文件上传与下载
- 第4步:tree命令查询效果
- 第1步:ps -ef|grep minio查看效果:
- 第五步:基于nginx实现loadbalancer。需求:这样一来的话,我们真正去使用的话肯定要有一个入口嘛。即如果是这种分布式纠删码部署模式下,我们肯定是要有入口的,要有一个统一的入口啊。那统一的入口的话,怎么做呀?是不是要有一个负载均衡器(loadbalance)。
- 第1步:配置nginx
第a步:配置一个upstream,9001~9004。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; } }
第b步:proxy_pass http://minio;,我们通用proxy_pass访问这个minio。
第c步:listen 9000;,我把我的这个端口变成9000,是不是就可以了第d步:listen 50000,同样地,我们把控制台的端口变成50000
第e步:我们通过ip_hash的方式,进行一个路由。 -
第2步:通过指定的配置文件启动nginx:sbin nginx
-
第3步:验证nginx启动:ps ef|grep nginx
- 第1步:配置nginx
-
第六步:测试
-
http://192.168.3.14:50001/dashboard,并完成简单的上传与下载文件
-
-
-
详细步骤2:使用docker compost部署分布式集群的minio
-
第一步:请下载docker-compose.yaml和nginx.conf到你当前的工作目录。docker-compose.yaml是通过docker-compose pull直接一下子把它拉下来的。nginx.conf是它提供的一个配置文件,里面有nginx的配置:
-
第1步:docker-compose pull:直接一下子把它拉下来:
- 第2步:打开它提供的配置文件,查看nginx配置。
-
-
第二步:docker-compose up
-
-
详细步骤3:扩展:磁盘不够了加磁盘,加节点都很多方便。
-
比如我之前只部署了32个节点,部署了32个磁盘。现在,我要把它扩充到64个。怎么做?即原来的32个节点上,再加上新的32个节点即可。
-
- 详细步骤1:基本实现
- 分布式纠删码集群部署注意事项(官网翻译):
-
分布式Minio里所有的节点需要有同样的access秘钥和secret秘钥,这样这些节点才能建立联接。 为了实现这个,你需要在执行minio server命令之前,先将access秘钥和secret秘钥export成环境变量。新版本使用MINIO_ROOT_USER&MINIO_ROOT_PASSWORD。
-
ps:集群部署模式下,要配置权限认证、用户名、密码,即这些的话每台机器上都要跑一遍。
-
-
分布式Minio使用的磁盘里必须是干净的,里面没有数据。
-
下面示例里的IP仅供示例参考,你需要改成你真实用到的IP和文件夹路径。
-
ps:换成物理的真实的IP地址,充分保证了各个节点之间要可以通信。比如,下面那些可能都是你局域网的IP PORT,保证了各个节点之间要可以通信。
-
-
分布式Minio里的节点时间差不能超过3秒,你可以使用NTP来保证时间一致。
-
ps:重要,高亮标注。
-
-
在Windows下运行分布式Minio处于实验阶段,请悠着点使用。
-
- 基础知识
- 总结:
- ps:大家注意啊,如果你们自己玩的话,机器也不是怎么好的话(4G 8G内存而已),你们可以搞个单机模式嘛。纠删码呀,都可以,纠删码无非就是加几块磁盘嘛。集群模式的话,大家可以在虚拟机中docker容器里面去玩啊。其实,部署还是非常方便的,这也是minio能够普及的一个原因。
三 mc admin使用(用户CRUD、文件的权限控制(只读、可写))
- 概述
- MinIO Client(mc)提供了“ admin”子命令来对您的MinIO部署执行管理任务:
- service 服务重启并停止所有MinIO服务器
- update 更新更新所有MinIO服务器
- info 信息显示MinIO服务器信息
- user 用户管理用户
- group 小组管理小组
- policy MinIO服务器中定义的策略管理策略
- config 配置管理MinIO服务器配置
- heal 修复MinIO服务器上的磁盘,存储桶和对象
- profile 概要文件生成概要文件数据以进行调试
- top 顶部提供MinIO的顶部统计信息
- trace 跟踪显示MinIO服务器的http跟踪
- console 控制台显示MinIO服务器的控制台日志
- prometheus Prometheus管理Prometheus配置
- kms kms执行KMS管理操作
- MinIO Client(mc)提供了“ admin”子命令来对您的MinIO部署执行管理任务:
- 比较常用的命令
- 服务器信息显示
- info:信息显示MinIO服务器信息
- trace:跟踪显示MinIO服务器的http跟踪
- console:控制台显示MinIO服务器的控制台日志
- 服务器管理
- service:服务重启并停止所有MinIO服务器
- policy MinIO:服务器中定义的策略管理策略
- 文件及文件夹(桶)的权限控制(只读(桶的下载)、可写(桶的上传))
- config:配置管理MinIO服务器配置,如服务器地址
- 用户及小组crud
- user:用户管理用户
- group:小组管理小组
- 服务器信息显示
- 案例1:用户管理
#命令列表
mc admin
#命令列表mc admin user --help# 新建用户, 此时用户没有任何权限(甚至登录控制台的权限都没有),此时要做权限管理(策略管理)mc admin user add minio-server foxmc 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 - 案例2:策略管理
- 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 -
添加新的策略:
-
第一步:编写策略文件(权限脚本):/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这个桶和此桶的所有子桶]}]} - 第二步:将tulingmall.json添加到策略数据库
# 添加新的策略
# 这里定义一个“tulingmall-admin”角色,并指定采用的策略
mc admin policy add minio-server tulingmall-admin /root/tulingmall.json
# 查看策略信息时,会多出一个策略
mc admin policy list minio-server - 第三步: 给新建的用户添加绑定新的策略(添加某些权限)
mc admin user add minio-server fox03 12345678# 设置用户的访问策略mc admin policy set minio-server tulingmall-admin user = fox03
- 第四步:验证
-
测试: fox03/12345678 登录 minio 控制台 http://192.168.3.14:50000/ ,只能操作(上传文件、下载文件等等) tulingmall 的 bucket(桶,即文件夹)
-
- 附:行为列表
"Action": ["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject"]
-
- policy命令,用于添加,删除,列出策略,获取有关策略的信息并为MinIO服务器上的用户设置策略。
四 Minio客户端(minio client)使用
- 概述
- 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 输出版本信息。
- minio client提供了一套的类似于linux的命令,非常方便,如mc ls、mc mb等:
- 业务
- Minio客户端(MC)怎么去操作Minio呢?
- 详细步骤:英文官网文档:MINIO CLIENT目录下
- 第一步:查看Minio客户端的命令:linux 》cmd 》mc:
- 通过cp、ls、mb等等这些命令,完成:使用Minio客户端创建一个桶、删除一个桶等等的minio操作。
- 第二步:部署客户端
wget http://dl.minio.org.cn/client/mc/release/linux-amd64/mcchmod + x mc./mc --helpmv mc /usr/local/sbin/
注:为了方便使用mc+...命令,不用每次都要到mc所在的目录,我们可以把下载下来的可执行文件复制到sbin目录下。同理,windows的话把可把下载下来可执行文件(mc.exe)复制到system32下。 - 第三步:配置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
-
第四步:mc命令使用
-
mc coinfig
-
mc config host ls
-
连接某个minio服务器,查看里面的某些目录的文件信息:
-
ls tuling-minio:带上host(minio server的名称)
-
ls tuling-minio/springcloud:查看tuling-minio服务器中springcloud的文件信息
-
-
查看某个minio服务器的桶(目录)信息:
-
添加minio server到mc中,并取一个名称
-
mc ls 服务器名称
-
-
-
第五步:演示上传、下载 ,并在控制台验证
-
第1步:添加minio server到mc中(mc连接上minio server),并取一个名称
- 第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/
-
- 第六步:演示Bucket管理,并在控制台验证
# 创建 bucketmc mb minio-server/bucket01# 删除 bucketmc rb minio-server/bucket02# bucket 不为空,可以强制删除 慎用mc rb --force minio-server/bucket01# 查询bucket03磁盘使用情况
mc du minio-server 查看总共用了多少mc du minio-server/bucket03 查看bucket03用了多少
- 第一步:查看Minio客户端的命令:linux 》cmd 》mc:
五 Minio Java Client使用:查官网案例和api使用手册
- 概述
-
MinIO Java Client(客户端) SDK 提供简单的 API 来访问minio服务端
-
官方 demo: https://github.com/minio/minio-java
-
官方文档: https://docs.min.io/docs/java-client-api-reference.html英文官网 》MINIO SDKS 》Java Client Quickstart Guide(对java的支持)/ Java Client API Reference(API的具体用法(操作))
-
- 文件上传
- 第一步:引入依赖
<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>
- 第二步:连接上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()); } } }
- 第三步:登录控制台,找到桶,查看文件
- 第一步:引入依赖
- 文件下载
- 第一步:引入依赖
- 第二步:连接上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(); } } }
- 第三步:看到下载的文件
- Spring boot整合minio
- 业务需求:
- 上面例子的问题:我们都是通过api去操作的,而真正开发过程中我们创建的肯定是一个springboot的应用。而要想在springboot中去操作minio Server,关键点在于把“ 获取Minio Java client(客户端)对象 ”的这部分代码变成一个可重用的。最好的方法是,把“ Minio Java client(客户端)对象 ”交给spring容器去管理,后续我们可以直接使用它去调用api完成对服务端的操作。
- 可以对官网代码进一步封装,写出自己的一个Uitl.java工具类
- 官方并没有提供minio server和spingboot的整合包,需要我们自己去实现整合
- 原理
- 把MinioClient对象交给spring容器去管理:
- 方案1:自己写一个XxxConfigure.java的配置类。
- 方案2:可以自己写一个springboot-minio-starter的启动类(起步依赖),其中自己去实现一个自动配置类。自动配置类中配置minio的XxxFactory.java,XxxFactory.java生产的是自动配置类的实例。
- 备注:springboot无非就是对spring做进一步的封装,利用了自动配置类简化了许多的配置。
- 把MinioClient对象交给spring容器去管理:
- 方案1:自己写一个XxxConfigure.java的配置类,用于构建MinioClient对象,并交给spring管理。
- 第一步:依赖
<?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>
- 第二步:.yml:配置创建minio对象所需的3个参数:
minio: endpoint: http://192.168.32.133:9000 accesskey: admin secretKey: 12345678 bucketName: bucker03
- 第三步: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; //密码 }
- 第四步: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; } }
- 第五步: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; } }
- 第六步:测试
- 列表
- 上传
- 下载
- 删除
- 第一步:依赖
- 业务需求: