Minio快速入门
MinIO 是一个 高性能、Kubernetes 原生、完全兼容 Amazon S3 API 的对象存储服务器。采用 Go 语言编写,单一二进制文件即可启动,支持 Windows、Linux、macOS 以及 Docker/Kubernetes 环境。MinIO 的设计目标是为云原生工作负载提供轻量、快速、可扩展的对象存储,既可以单机运行(用于开发/测试),也可以部署成分布式集群(用于生产环境,实
文章目录
一、文件存储方案
在现代应用开发中,文件(图片、视频、文档、日志等)的存储和管理是一个基础需求。常见的文件存储方案有以下几种:
- 本地文件存储:直接将文件保存在应用服务器的本地磁盘(如 ./uploads/ 目录)。实现简单、无额外依赖、读写速度快,但不易扩展
- 网络附属存储(NAS / 共享文件系统):使用 NFS、SMB/CIFS 等协议,将文件存储在专用的网络存储设备上,多台应用服务器共享同一目录。解决了多服务器共享文件的问题;容量可扩展;但性能受网络和 NAS 设备限制,仍存在中心化瓶颈,配置和维护相对复杂。
- 云对象存储(OSS / S3):使用云厂商提供的对象存储服务(如 AWS S3、阿里云 OSS、腾讯云 COS、华为云 OBS 等),通过 HTTP REST API 存取文件。可以无限容量,按量付费,具有高可用、高持久性;但依赖公网或专线,每次读写有网络延迟和费用
- 自建对象存储(MinIO、Ceph RGW、Swift):在私有云或本地数据中心部署对象存储系统,提供 S3 兼容的 API。数据完全自主可控,安全合规,且无厂商锁定,可部署在任意 Linux/Windows 服务器或 Kubernetes 上,但需要自行运维,有硬件投资和机房环境要求。
二、MinIO 简介
MinIO 是一个 高性能、Kubernetes 原生、完全兼容 Amazon S3 API 的对象存储服务器。
- 采用 Go 语言编写,单一二进制文件即可启动,支持 Windows、Linux、macOS 以及 Docker/Kubernetes 环境。
- MinIO 的设计目标是为云原生工作负载提供轻量、快速、可扩展的对象存储,既可以单机运行(用于开发/测试),也可以部署成分布式集群(用于生产环境,实现数据冗余和高可用)。
- 由于其 S3 兼容性,任何为 AWS S3 编写的 SDK(Java、Python、Go、Node.js 等)和工具(如 awscli、s3cmd、rclone)都可以无缝对接 MinIO。
1.核心特性
- S3 兼容:完整实现 Amazon S3 API,包括 Bucket、Object、Multipart Upload、Presigned URL、Bucket Policy 等
- 高性能:在合适硬件上可达到 每秒数百 GB 的读写吞吐;利用 SIMD 指令集加速纠删码(Erasure Coding)计算
- 轻量 & 简单:单个二进制文件(约 100MB),无外部依赖(不依赖数据库),配置简单(环境变量或命令行参数)
- 分布式支持:支持分布式模式(多个磁盘/多台服务器),使用纠删码提供数据冗余和自动修复,无需 RAID
- 云原生友好:提供 Kubernetes Operator,可轻松在 K8s 上部署;支持 Prometheus 监控指标;与 CSI(容器存储接口)集成
- 安全:支持 TLS/HTTPS、服务器端加密(SSE-S3、SSE-C、SSE-KMS)、IAM 身份管理、Bucket 策略和临时凭证(STS)
- 生命周期管理:支持对象过期、转换到冷存储层(需配合其他系统)
- 事件通知:支持将 Bucket 事件(上传、删除等)发送到 Kafka、AMQP、Redis、Webhook 等目标
- 多租户:通过多个 MinIO 实例或 Bucket 策略实现租户隔离
2.适用场景
- 开发与测试环境:在本地或 CI/CD 管道中快速搭建一个 S3 兼容的存储,避免连接真实云服务带来的网络延迟和费用。
- 私有云/企业内部文件存储:替代传统的文件服务器(NFS/SMB),为内部应用提供统一的对象存储接口,支持海量小文件或大文件的稳定存储。
- 大数据与 AI 训练:作为数据湖的存储底座,存储日志、Parquet/ORC 格式数据,供 Spark、Presto、TensorFlow 等计算框架直接读取。MinIO 对 Hadoop S3A 有良好支持。
- 容器化应用的持久化存储:在 Kubernetes 中作为 PVC 后端(通过 CSI 或 S3 兼容的 FUSE 工具),为无状态应用提供持久卷。
- 备份与归档:使用 rclone、Velero、Dell EMC Networker 等备份工具将数据直接备份到 MinIO,并通过生命周期管理转储至冷存储层。
- 边缘计算 / IoT:由于单二进制部署极其轻量,可以运行在树莓派、边缘网关等设备上,收集并存储传感器数据,再通过同步功能汇总到中心云。
- 混合云架构中的缓存层:在本地部署 MinIO 作为高速缓存,通过异步复制将数据最终同步到公有云对象存储,平衡访问延迟和成本。
三、访问控制台与基本操作
1.Web端基础操作
可以登录 Web 控制台创建存储桶(Bucket),注意创建桶名时必须介于 3 到 63 个字符之间;桶名称只能由小写字母、数字、句点 (.) 和连字符 (-) 组成;桶名称必须以字母或数字开头和结尾;且名称不得采用 IP 地址格式,否则会报错。
可以上传、下载、删除文件
2.共享访问链接
①可以选中文件生成共享访问链接,但是这种方式生成的链接,有效期最长只能设置到12小时,无法延长。


②可以使用 mc 命令行客户端生成永久共享链接(推荐),下载 mc 并配置连接别名
mc alias set myminio http://127.0.0.1:9000 YOUR_USERNAME YOUR_PASSWORD
将整个存储桶设为公开只读,即任何人都可以列出并下载桶内的所有文件(即永久共享)。
mc anonymous set download myminio/my-bucket-name
③也可以通过SDK编程实现永久访问配置,MinIO 所有官方 SDK 都兼容 AWS S3 的 Bucket Policy。以下以 Java 和 Python 为例,演示如何将存储桶设置为公开只读(永久共享)。
Java代码如下
import io.minio.*;
import io.minio.messages.*;
public class MakeBucketPublic {
public static void main(String[] args) throws Exception {
MinioClient minioClient = MinioClient.builder()
.endpoint("http://127.0.0.1:9000")
.credentials("YOUR_USERNAME", "YOUR_PASSWORD")
.build();
// 设置 bucket 策略为 "public-read"(允许所有人下载)
String policy = "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": [\"s3:GetObject\"],\n" +
" \"Resource\": [\"arn:aws:s3:::my-bucket-name/*\"]\n" +
" }\n" +
" ]\n" +
"}";
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder()
.bucket("my-bucket-name")
.config(policy)
.build());
System.out.println("Bucket is now public. Permanent URL: http://127.0.0.1:9000/my-bucket-name/your-file.jpg");
}
}
Python 示例如下
from minio import Minio
client = Minio(
"127.0.0.1:9000",
access_key="YOUR_USERNAME",
secret_key="YOUR_PASSWORD",
secure=False
)
policy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::my-bucket-name/*"]
}
]
}
client.set_bucket_policy("my-bucket-name", json.dumps(policy))
print("永久共享链接格式:http://127.0.0.1:9000/my-bucket-name/文件名")
④如果你不希望将整个桶公开,但又需要生成一个有效期很长(例如 1 年) 的分享链接,可以通过 SDK 生成自定义有效期的预签名 URL。不过请注意,MinIO 官方建议最长不超过 7 天,但通过代码可以设置更大的值(如 365 天)。示例(Java):
String url = minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.bucket("my-bucket-name")
.object("my-file.pdf")
.method(Method.GET)
.expiry(3600 * 24 * 365) // 365 天,单位秒
.build()
);
System.out.println("Long-term URL: " + url);
四、客户端工具(mc)简介
MinIO 官方命令行客户端 mc(MinIO Client)提供了类似 UNIX 命令(如 ls、cp、mb 等),用于管理对象存储和兼容 S3 的服务。与直接操作文件系统不同,mc 通过 S3 API 与服务端交互,确保元数据一致性。
1.mc 的安装与配置
- Windows:下载 mc.exe,放入任意目录。
- macOS:brew install minio/stable/mc
- Linux:
wget https://dl.min.io/client/mc/release/linux-amd64/mc chmod +x mc sudo mv mc /usr/local/bin/ - Docker:docker pull minio/mc
配置别名(Alias)
mc alias set myminio http://127.0.0.1:9000 YOUR_ACCESS_KEY YOUR_SECRET_KEY
注意端口必须为 API 端口(默认 9000),不是 Web 控制台端口。
2.常用 mc 命令(ls、mb、cp、rm、policy)
| 命令 | 说明 | 示例 |
|---|---|---|
| ls | 列出存储桶或对象 | mc ls myminio mc ls myminio/mybucket |
| mb | 创建存储桶 | mc mb myminio/new-bucket |
| cp | 复制(上传/下载) | 上传:mc cp ./file myminio/mybucket/ 下载:mc cp myminio/mybucket/file ./ |
| rm | 删除对象 | mc rm myminio/mybucket/file.txt mc rm --force myminio/mybucket/ |
| policy/anonymous | 设置桶的匿名访问策略 | mc anonymous set download myminio/mybucket(公开只读) |
五、Java 快速集成示例
1.添加 MinIO Java SDK 依赖(Maven/Gradle)
在项目中引入 MinIO Java SDK 的 Maven 依赖,当前官方推荐的稳定版本为 8.6.0(建议使用最新稳定版)。部分场景下,SDK 内部依赖 HTTP 客户端,如项目中缺少相关依赖,可一并添加 Apache HttpClient5:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.6.0</version>
</dependency>
<!-- 可选:Apache HttpClient5,部分场景可能依赖 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>
若使用 Gradle
dependencies {
implementation("io.minio:minio:8.6.0")
}
提示:引入依赖后,MinioClient 对象建议在项目中作为单例使用,不要每次操作都重新创建客户端实例。
2.连接 MinIO 服务器
所有操作都通过 MinioClient 对象执行,初始化时需传入 MinIO 服务的核心配置:服务地址、访问密钥和秘密密钥。MinioClient 使用建造者模式进行实例化,支持灵活配置 endpoint、region 及 HTTP 客户端设置。
import io.minio.MinioClient;
import io.minio.errors.MinioException;
public class MinioConfig {
// 配置参数(可根据需要提取到配置文件)
private static final String MINIO_ENDPOINT = "http://127.0.0.1:9000";
private static final String MINIO_ACCESS_KEY = "your_access_key";
private static final String MINIO_SECRET_KEY = "your_secret_key";
/**
* 获取 MinIO 客户端实例(单例模式)
*/
public static MinioClient getMinioClient() {
try {
MinioClient client = MinioClient.builder()
.endpoint(MINIO_ENDPOINT)
.credentials(MINIO_ACCESS_KEY, MINIO_SECRET_KEY)
.build();
// 验证客户端可用性
client.listBuckets();
return client;
} catch (Exception e) {
throw new RuntimeException("MinIO客户端初始化失败:" + e.getMessage(), e);
}
}
}
- endpoint:MinIO 服务地址(API 端口,如 http://127.0.0.1:9000)
- accessKey:访问密钥(即登录用户名)
- secretKey:秘密密钥(即登录密码)
在 Spring Boot 项目中集成,推荐将连接参数配置到 application.yml 中,通过 @ConfigurationProperties 读取并初始化客户端 Bean,方便后续维护和依赖注入。
# application.yml
minio:
endpoint: http://127.0.0.1:9000
access-key: your_access_key
secret-key: your_secret_key
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MinioConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.access-key}")
private String accessKey;
@Value("${minio.secret-key}")
private String secretKey;
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}
3.创建存储桶、上传文件
MinIO 将存储桶(Bucket)作为顶层容器,所有文件都存放在存储桶中。在上传文件之前,最好先检查目标存储桶是否存在,若不存在则创建。
判断存储桶是否存在并创建
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.UploadObjectArgs;
public class MinioFileService {
private final MinioClient minioClient;
public MinioFileService(MinioClient minioClient) {
this.minioClient = minioClient;
}
/**
* 确保存储桶存在,若不存在则创建
*/
public void ensureBucketExists(String bucketName) throws Exception {
boolean exists = minioClient.bucketExists(
BucketExistsArgs.builder().bucket(bucketName).build()
);
if (!exists) {
minioClient.makeBucket(
MakeBucketArgs.builder().bucket(bucketName).build()
);
}
}
}
上传文件(从本地文件系统)uploadObject 方法支持通过本地文件路径上传文件到 MinIO:
import io.minio.UploadObjectArgs;
/**
* 上传本地文件到 MinIO
*
* @param bucketName 存储桶名称
* @param objectName 对象名称(即文件在桶中的路径,例如 "images/photo.jpg")
* @param filePath 本地文件绝对路径
*/
public void uploadFile(String bucketName, String objectName, String filePath) throws Exception {
ensureBucketExists(bucketName);
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(filePath)
.build()
);
}
提示:objectName 可以包含路径,例如 files/2025/photo.jpg,会在 MinIO 中模拟目录结构(实际上所有对象仍以扁平结构存储,只是按前缀组织)。
上传文件(从 InputStream):若文件来自其他来源(如用户上传的 MultipartFile),可使用 putObject 方法(Java 中也提供了 putObject 方法用于上传对象):
import io.minio.PutObjectArgs;
import java.io.InputStream;
/**
* 从输入流上传文件到 MinIO
*/
public void uploadStream(String bucketName, String objectName, InputStream inputStream,
String contentType, long size) throws Exception {
ensureBucketExists(bucketName);
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(inputStream, size, -1)
.contentType(contentType)
.build()
);
}
4.获取文件 URL 或下载对象
- 方式一:获取预签名 URL(带有效期):通过 getPresignedObjectUrl 方法可生成一个带有签名和有效期的临时下载链接,适用于为外部用户提供有时间限制的安全访问。MinIO Web 控制台生成的分享链接有效期最长 12 小时,而通过 SDK 可以自定义过期时间
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.http.Method;
import java.util.concurrent.TimeUnit;
/**
* 获取预签名 URL(适用于私有桶的文件临时访问)
*
* @param bucketName 存储桶名称
* @param objectName 对象名称
* @param expiry 过期时长(单位:秒)
* @return 预签名 URL(超期后自动失效)
*/
public String getPresignedUrl(String bucketName, String objectName, int expirySeconds) throws Exception {
return minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(expirySeconds)
.build()
);
}
// 使用示例:生成一个 7 天有效的下载链接
String url = getPresignedUrl("my-bucket", "myfile.jpg", (int) TimeUnit.DAYS.toSeconds(7));
- 方式二:直接下载文件到本地:当需要在后端读取文件内容时(例如 Java 程序需要处理文件数据),直接下载比使用预签名 URL 更合适
import io.minio.DownloadObjectArgs;
/**
* 从 MinIO 下载文件到本地
*/
public void downloadFile(String bucketName, String objectName, String destinationPath) throws Exception {
minioClient.downloadObject(
DownloadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(destinationPath)
.build()
);
}
- 方式三:获取文件的 InputStream(浏览器下载):在 Web 应用中,可以将文件内容直接写入 HTTP 响应流,供用户下载或预览
import io.minio.GetObjectArgs;
import jakarta.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 获取文件输入流并返回给客户端
*/
public void downloadToResponse(String bucketName, String objectName, HttpServletResponse response) throws Exception {
try (InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
OutputStream os = response.getOutputStream()) {
// 设置响应头(根据文件类型调整 Content-Type)
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + objectName + "\"");
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = stream.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
}
说明:getObject 方法返回文件内容的 InputStream,可以灵活地处理(如转换格式、边读边处理等),比直接下载到本地文件更适用于内存处理场景。
完整示例代码
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.UploadObjectArgs;
import io.minio.DownloadObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.http.Method;
public class MinIODemo {
public static void main(String[] args) throws Exception {
// 1. 初始化客户端
MinioClient minioClient = MinioClient.builder()
.endpoint("http://127.0.0.1:9000")
.credentials("admin", "your_secure_password")
.build();
String bucketName = "my-demo-bucket";
String objectName = "hello.txt";
String sourceFile = "C:/temp/hello.txt";
String destFile = "C:/temp/hello_downloaded.txt";
// 2. 确保存储桶存在
boolean found = minioClient.bucketExists(
BucketExistsArgs.builder().bucket(bucketName).build()
);
if (!found) {
minioClient.makeBucket(
MakeBucketArgs.builder().bucket(bucketName).build()
);
System.out.println("Bucket created: " + bucketName);
}
// 3. 上传文件
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(sourceFile)
.build()
);
System.out.println("File uploaded: " + objectName);
// 4. 生成预签名 URL
String url = minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.expiry(7 * 24 * 3600) // 7 days
.build()
);
System.out.println("Presigned URL: " + url);
// 5. 下载文件到本地
minioClient.downloadObject(
DownloadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(destFile)
.build()
);
System.out.println("File downloaded to: " + destFile);
}
}
实际开发建议
- 配置分离:将 endpoint、accessKey、secretKey 等参数提取到配置文件中,便于不同环境切换(开发/测试/生产),也避免将敏感信息硬编码在代码中。
- 封装 Service 层:将 MinIO 操作封装成独立的 Service(如 MinioFileService),提供统一的上传、下载、删除等接口,配合 Spring 的 @Service 注解便于业务层调用。
- 异常处理:MinIO SDK 的调用可能会抛出 MinioException、InvalidKeyException 等异常,建议在封装层统一处理并转换为业务异常。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)