系列文章:
对象存储——Minio 初探
一 MinIO SDK
对象存储——Minio 初探中我们介绍了单机部署 MinIO 的过程,以及在控制台上的一些操作。因为在实际应用中,主要还是通过 sdk 进行操作,所以这里我们也开始介绍 MinIO SDK 的使用。MinIO SDK 的官网地址:https://min.io/docs/minio/linux/developers/minio-drivers.html?ref=docs。从中可以看出,MinIO 发布了.NET、Golang、Haskell、Java、JavaScript、Python 共 6 种语言的 SDK,接下来我们基于 Java SDK 来实现对 MinIO 的一些常规操作。
二 Java SDK
2.1 当前版本
截止目前(2023.12.22),Java SDK 的版本为 8.5.7,github 地址:minio/minio-java
与其他依赖相同,支持 maven、gradle 活 jar 包直接引入方式。我们以 Maven 为例:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.7</version>
</dependency>
复制代码
2.2 api 示例-文件上传
2.2.1 准备信息
这是一个官方示例。上传文件到 minio 服务器需要以下三个参数:
Endpoint : S3 服务的 Url
Access Key:minio 账号的 ak.
Secret Key:minio 的 sk.
ak、sk 创建/查询方法,可参考如下截图,在 Service Accounts 下,点击 Create service account 按钮创建账号。
在这个页面上,复制 Access Key 和 Secret Key 保存。
2.2.2 官方测试服务信息
注意,如果本地还没有搭建,可以先使用官方文档提供的两个测试服务地址:
MinIO:
MinioClient minioClient =
MinioClient.builder()
.endpoint("https://play.min.io")
.credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
.build();
复制代码
AWS S3:
MinioClient minioClient =
MinioClient.builder()
.endpoint("https://s3.amazonaws.com")
.credentials("YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY")
.build();
复制代码
2.2.3 文件上传代码示例
package com.freemark.demo.minio;
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 {
/**
* 这里配置自己的endpoint和ak sk
*/
public static String endPoint = "http://你的minio server ip:端口号";
public static String accessKey = "你的ak";
public static String secretKey = "你的sk";
public static void main(String[] args)
throws IOException, NoSuchAlgorithmException, InvalidKeyException {
try {
// 创建minioClient,使用官方提供的示例地址和ak sk
MinioClient minioClient =
MinioClient.builder()
.endpoint("https://play.min.io")
.credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
.build();
// 如果指定的bucket不存在,则创建,否则使用已有bucket
String bucketName = "asiatrip1";
boolean found =
minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} else {
System.out.println("Bucket '" + bucketName + "' already exists.");
}
String filePath = "/Users/lijingyong/Downloads/minio_test_text.txt";
String fileName = "minio_test_text.txt";
// 执行文件上传
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.filename(filePath)
.build());
System.out.println("'" + filePath + "' 成功上传对象 '" + fileName + "' 到 bucket '" + bucketName + "'.");
} catch (MinioException e) {
System.out.println("Error occurred: " + e);
System.out.println("HTTP trace: " + e.httpTrace());
}
}
}
复制代码
执行后打印如下信息:
如果使用的是自己搭建的 minio 服务地址及对应的 ak 和 sk,那么我们就能够看到在指定的 bucket 下有我们刚刚上传的文件。如下所示:
如果执行多次,会发现提示 bucket 已存在,不会重复创建,但文件会多次上传,覆盖上传。
2.3 完整 API 说明
其他完整的 API,我们也可以查看官方文档:https://min.io/docs/minio/linux/developers/java/API.html#bucketExists。下面以可能会经常用到的文件下载、删除完成本篇示例,其他可以查看文档,这里就不在赘述。
2.4 文件下载
2.4.1 文件下载
方法名:downloadObject
入参:DownloadObjectArgs,参数列表:
bucket: 要从哪个 bucket 下载文件
object: 要下载的对象名
filename:要保存的文件路径
使用如下代码,即可执行对指定 bucket 下指定对象的下载,下载的文件会保存在 filename 参数对应的路径下。
minioClient.downloadObject(
DownloadObjectArgs.builder()
.bucket("my-bucketname")
.object("my-objectname")
.filename("my-object-file")
.build());
复制代码
如果服务端文件进行了加密,那我们在下载时也需要增加 ssec 参数来做支持,
ServerSideEncryptionCustomerKey ssec =
new ServerSideEncryptionCustomerKey(
new SecretKeySpec(
"01234567890123456789012345678901".getBytes(StandardCharsets.UTF_8), "AES"));
minioClient.downloadObject(
DownloadObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.filename("/Users/xxx/Downloads/download_minio_test_text.txt")
.ssec(ssec)
.build());
System.out.println(fileName + "下载完毕");
复制代码
注意,如果我们使用的 minio 没有安装成带有 TLS 的服务,那么执行上述代码会报如下错误。
Minio 服务端加密是大部分文章都没有提到的,所以这里我们稍微展开说明一下。
2.5 Minio 服务端加密
参考Minio Cookbook 中文版 中的如何使用aws-cli调用Minio服务端加密,Minio 支持采用客户端提供的秘钥(SSE-C)进行 S3 服务端加密。客户端必须为 SSE-C 请求指定三个 HTTP 请求头:
1、算法标识符: X-Amz-Server-Side-Encryption-Customer-Algorithm 唯一的合法值是: AES256。
2、加密秘钥: X-Amz-Server-Side-Encryption-Customer-Key 加密秘钥必须是一个 256 位的 base64 编码的字符串。
3、加密密钥 MD5 校验和: X-Amz-Server-Side-Encryption-Customer-Key-MD5 加密密钥 MD5 校验和必须是秘钥的 MD5 和,注意是原始秘钥的 MD5 和,而不是 base64 编码之后的。
2.5.1 安全须知
根据 S3 规范,minio 服务器将拒绝任何通过不安全(非 TLS)连接进行的 SSE-C 请求。 这意味着 SSE-C 必须是 TLS / HTTPS。
SSE-C 请求包含加密密钥。 如果通过非 TLS 连接进行 SSE-C 请求,则必须将 SSE-C 加密密钥视为受损。
根据 S3 规范,SSE-C PUT 操作返回的 content-md5 与上传对象的 MD5-sum 不匹配。
Minio Server 使用防篡改加密方案来加密对象,并且不会保存加密密钥。 这意味着您有责任保管好加密密钥。 如果你丢失了某个对象的加密密钥,你将会丢失该对象。
Minio Server 期望 SSE-C 加密密钥是高熵的。加密密钥是不是密码。如果你想使用密码,请确保使用诸如 Argon2,scrypt 或 PBKDF2 的基于密码的密钥派生函数(PBKDF)来派生高熵密钥。
2.5.2 前提条件
minio 安装时需要安装成带有 TLS 的服务。从这里下载 Minio Server,安装方式参考文档Network Encryption (TLS) 生成证书。
这里需要注意的是,如果你使用的是自己签名的 TLS 证书,那么当你往 Minio Server 上传文件时,像 aws-cli 或者是 mc 这些工具就会报错。如果你想获得一个 CA 结构签名的 TLS 证书,请参考Let's Encrypt
。自己签名的证书应该仅做为内部开发和测试。
2.5.3 使用 SSE-C 和 aws-cli
从这里下载并安装 aws-cli。
假设你在本地运行了一个 Minio Server,地址是https://localhost:9000
,并且使用的是自己签名的证书。为了绕过 TLS 证书的验证,你需要指定—no-verify-ssl
。如果你的 Minio Server 使用的是一个 CA 认证的证书,那你永远永远永远不要指定`—no-verify-ssl,否则 aws-cli 会接受任何证书。
2.6 其他 SDK
2.6.1 对象删除
使用 removeObject 方法,支持删除单个对象、
// Remove object.
minioClient.removeObject(
RemoveObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build());
复制代码
删除指定的对象的某个版本:
// Remove versioned object.
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket("my-bucketname")
.object("my-versioned-objectname")
.versionId("my-versionid")
.build());
复制代码
绕过治理模式删除版本控制的对象:
// Remove versioned object bypassing Governance mode.
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket("my-bucketname")
.object("my-versioned-objectname")
.versionId("my-versionid")
.bypassRetentionMode(true)
.build());
复制代码
2.6.2 对象批量删除
使用 removeObjects,参数为对象 List:
List<DeleteObject> objects = new LinkedList<>();
objects.add(new DeleteObject("my-objectname1"));
objects.add(new DeleteObject("my-objectname2"));
objects.add(new DeleteObject("my-objectname3"));
Iterable<Result<DeleteError>> results =
minioClient.removeObjects(
RemoveObjectsArgs.builder().bucket("my-bucketname").objects(objects).build());
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
System.out.println(
"Error in deleting object " + error.objectName() + "; " + error.message());
}
复制代码
2.6.3 其他 api
其他常用的 API 还包括获取 bucket 下的文件列表:listObjects,设置 bucket 生命周期:setBucketLifecycle 等等。因为官方 API 文档和其他文章提供的工具类中都有描述,这里就不再赘述了。工具类代码大家可以查看https://gitee.com/flamingskyline/template-engine并下载获取。
评论