minio安装及使用实践

minio安装及使用实践

1.官网下载最新版本安装文件

当前minio更新发布很快,几乎一两周一个版本,建议下载最新版本;
官网地址:http://minio.org.cn/
下载地址:http://minio.org.cn/download.shtml#/linux
当前实践采用的版本为:RELEASE.2023-07-07T07-13-57Z (go1.19.10 linux/amd64)

2.安装启动minio

  • 创建一个目录,供minio存储数据,如minio_data
mkdir ~/minio_data   #创建数据存储目录
  • 给安装包执行权限
chmod +x minio  #给minio执行权限
  • 设置环境变量
vi ~/.bashrc
export MINIO_ROOT_USER=admin  #minio管理员账号
export MINIO_ROOT_PASSWORD=Dd123456 #minio管理员密码
  • 启动minio
./minio server minio_data/ --console-address :9090  #前台启动
./minio server minio_data/ --console-address :9090  2>&1>/dev/null & #后台启动
  • 校验是否启动成功
    前台启动后,出现如下信息则表示成功
    minio安装及使用实践_第1张图片
    后台启动后直接访问控制台测试
  • 访问控制台
    浏览器访问 http://192.168.212.9:9090 其中192.168.212.9为minio安装机器的IP
    minio安装及使用实践_第2张图片

3.创建bucket,设置访问策略

  • 进入minio控制台,Administrator->Buckets->Create Bucket, 创建一个test的桶
  • 给创建的bucket设置访问策略
    点击创建的bucket,然后点击 Summary->Access Policy,选择Custom,设置如下,注意,其中桶名(Resource块中的test)需根据实际情况修改为当前设置的桶名
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [                    "*"
                ]
            },
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::test/*" 
            ]
        }
    ]
}
  • 创建普通上传账户
    点击Administrator->Identity->Users->Createt User
    输入账户名和密码,如test/Dd123456
    Policy选择 readwrite
  • 为账户创建AccessKey
    Administrator->Identity->Users,点击创建的用户->Service Accounts->Create Access Key->create,然后复制保存创建的Access Key和Secret Key
  • 验证
    1)先通过控制台上传一个测试图片,如测试图片1.png,操作:User->Object Browser->点击要上传的bucket->Upload->Upload File
    2)然后通过地址直接访问,如http://192.168.212.9:9000/test/测试图片1.png,若浏览器能直接访问改图片则表示安装成功;
    3)删除链接中的文件名,直接访问桶,若出现Access Denied则表示桶权限配置成功,如果列出桶下所有的文件,则权限设置失败,下图是直接访问桶名后权限设置成功的示例:
    minio安装及使用实践_第3张图片

4.minio上传实践

这里只做了Java后端通过Access Key,Secret Key获取预签名URL,返回给前端,前端再通过URL直接上传文件到minio,包括单文件上传和大文件分片上传再合并。minio提供了许多的JDK,如JavaScriptSDK,前端可以完全不经过后端直接通过JDK进行上传 ,但是该方式需要暴露Access Key,Secret Key到前端,安全性不高;也可以采用传统的方式,前端先将文件发送给后端,后端再调用SDK上传到minio,该种方式效率要低一些,且需占用后端服务的内存。

  • 引入依赖
<dependency>
    <groupId>io.miniogroupId>
    <artifactId>minioartifactId>
    <version>8.5.4version>
dependency>
  • 单文件上传
//初始化客户端
MinioClient minioClient =
        MinioClient.builder()
                .endpoint("http://127.0.0.1:9000")//注意端口,与控制台的端口区分
                //ak,sk
                .credentials("kFNmQEVItm6SsqPnFYuj", "6DJj6EgU7K2vFXLmxmjQiEhBykGMPxaWh0g70jw3")
                .build();
//获取文件上传URL                                
String url =
        minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.PUT) //必须为PUT方法
                        .bucket("test") //桶名
                        .object("测试图1.jpg")//上传的文件名
                        .expiry(10, TimeUnit.SECONDS) //上传链接过期实际
                        .build());
System.out.println(url) //输出,将得到的URL返回给前端即可,前端通过该URL进行文件上传
  • 大文件分片上传
    大文件分片上传需要用到 io.minio.MinioAsyncClient 这个类中的几个方法,但是这个几个方法都是protected的,在我们自己的工程包中将无法调用,因此在需要使用的包下新建一个同样的类MinioAsyncClient,并继承minio中的 io.minio.MinioAsyncClient,然后再重写下面几个方法即可:
  1. completeMultipartUploadAsync
  2. listPartsAsync
  3. listPartsAsync
    重新定义一个MinioAsyncClient类,并覆写其中的方法
import com.google.common.collect.Multimap;
import io.minio.CreateMultipartUploadResponse;
import io.minio.ListPartsResponse;
import io.minio.ObjectWriteResponse;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
import io.minio.errors.XmlParserException;
import io.minio.messages.Part;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.CompletableFuture;

public class MinioAsyncClient extends io.minio.MinioAsyncClient {

    public MinioAsyncClient(io.minio.MinioAsyncClient client) {
        super(client);
    }

    @Override
    protected CompletableFuture<CreateMultipartUploadResponse> createMultipartUploadAsync(String bucketName, String region, String objectName, Multimap<String, String> headers, Multimap<String, String> extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException {
        return super.createMultipartUploadAsync(bucketName, region, objectName, headers, extraQueryParams);
    }

    @Override
    protected CompletableFuture<ObjectWriteResponse> completeMultipartUploadAsync(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException {
        return super.completeMultipartUploadAsync(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams);
    }

    @Override
    protected CompletableFuture<ListPartsResponse> listPartsAsync(String bucketName, String region, String objectName, Integer maxParts, Integer partNumberMarker, String uploadId, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException {
        return super.listPartsAsync(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams);
    }
}

分片上传逻辑

io.minio.MinioAsyncClient minioAsyncClient = MinioAsyncClient.builder()
        .endpoint("http://127.0.0.1:9000")
        .credentials("kFNmQEVItm6SsqPnFYuj", "6DJj6EgU7K2vFXLmxmjQiEhBykGMPxaWh0g70jw3")
        .build();
MinioAsyncClient minioAsyncClient1 = new MinioAsyncClient(minioAsyncClient);
//创建分片上传,获取上传ID
CompletableFuture<CreateMultipartUploadResponse> result = minioAsyncClient1.createMultipartUploadAsync("dev", null, "测试视频2.mp4", null, null);
String uploadId = result.get().result().uploadId();
//获取各个分片的上传URL
for (int i = 1; i <= 3; i++) {//该处的3为实际的分片数,实际可由前端传入
    Map<String, String> extraQueryParams = new HashMap<>();
    //注意!!!! 此处的partNumber必须从1开始,否则得到的上传URL将无法上传分片
    extraQueryParams.put("partNumber", String.vavueOf(i))valueOf);
    extraQueryParams.put("uploadId", uploadId); 
    GetPresignedObjectUrlArgs args1 = GetPresignedObjectUrlArgs.builder()
            .bucket("test")//桶名
            .method(Method.PUT)//必须为PUT方法
            .object("测试视频2.mp4")//上传文件名
            .extraQueryParams(extraQueryParams)//查询参数
            .expiry(1, TimeUnit.HOURS)//URL失效时间
            .build();
    //当前分片的上传URL
    String presignedObjectUrl = minioAsyncClient1.getPresignedObjectUrl(args1);
    System.out.println(presignedObjectUrl);
}

//当前端将所有的分片都上传完成后,需对上传的分片进行合并
//1.先根据uploadId,得到所有分片信息
CompletableFuture<ListPartsResponse> parts = minioAsyncClient1.listPartsAsync("test", null, "测试视频2.mp4", null, null, uploadId, null, null);
List<Part> partList = parts.get().result().partList();
Part[] partAry = new Part[partList.size()];
partList.toArray(partAry);
//2.然后将所有的分片信息进行合并,合并为一个文件
CompletableFuture<ObjectWriteResponse> dev = minioAsyncClient1.completeMultipartUploadAsync("dev", null, "测试视频2.mp4", uploadId, partAry, null, null);
ObjectWriteResponse objectWriteResponse = dev.get();
System.out.println(objectWriteResponse.etag() + objectWriteResponse.versionId());

5.大文件分片

可利用git bash对文件进行分片,其有个split命令,可对文件进行分片,命令使用如下:

split -b 52428800 测试视频2.mp4  #-b表示设置分片的大小

在这里插入图片描述
上述命令实现的时,将文件测试视频2.mp4,以50M的大小进行分片,当前文件的大小为121M,因此会得到2个50M的分片和1个21M的分片,得到的分片如下:
minio安装及使用实践_第4张图片

得到分片文件后,然后通过ApiPost或者Posttman,利用前面得到的上传链接将分片逐一上传,上传完后再进行合并即可。

6.前端如何进行分片上传

前端实践时,可利用vue-simple-uploader进行改造,注意mino上传时不能采用multi的方式,需要采用octet的方式,minio只支持octet的方式,虽然multi的方式可以进行上传,但是合并后的文件将无法打开。同时使用octet的方法进行上传时,不要给上传链接加额外的参数,否则上传也会不成功。

7.遇到的一些问题

  1. 将桶的策略设置为public时,直接访问bucket名,将泄露bucket下所有的文件列表,从而泄露所有的文件
    解决方案见第3点,将桶的策略设置为Custom,并仅留下s3:GetObject权限。

  2. 获取的presignedUrl无发上传文件,或上传出错
    1)检查获取URL时,设置的方法是否为PUT;
    2)调用上传链接时,是否是使用PUT方法;
    3)如果是分片上传,则检查partNumber设置是否是从1开,注意一定不能从0开始,我卡在这里许久找不到问题。

  3. 后端如何限制分片上传时文件的类型,和上传的大小
    限制文件类型:在文件上传时,前端需要向后端请求上传链接,此时前端需传入文件名,可通过判断文件的后缀进行类型限制
    限制文件大小:1)通过nginx限制单个请求的的reqest enttity,例如10M,2)然后在前端向后端请求分片上传链接时,对分片数进行限制,如限制为100个分片,则可将文件上传大小限制在1G左右。

你可能感兴趣的:(minio,对象存储,文件上传,java,其他,中间件)