搭建MinioOSS存储服务
Minio + Docker 搭建属于自己的OSS存储服务
为什么要自己搭建呢
其实个人小项目为了图方便,完全可以去使用阿里云或者腾讯云的OSS的服务,现在几大厂商的OSS服务已经都比较成熟了。但是接踵而来的有一个致命的问题。虽说云厂商的OSS非常方便,引入SDK即可使用,但是你被人恶意刷流量所带来的费用,你真的承担的起吗!!!
虽然说你暂时可能没被刷,但是如果哪天到我们头上,那可是毁灭性打击,毕竟自己写项目一毛钱还没赚到,流量被刷了几万块,想想就难受。
所以自己搭建的一个文件存储服务便可以让我们的压力变为最小化。
为什么选择Minio
MinIO 是一个高性能的轻量级对象存储服务器。它具有分布式,高可用性和水平扩展的特点,它非常适合用于大规模数据存储和分析。其优点包括低延迟、高吞吐量、易于部署和管理。
如果担心一台可能也会垮掉,我们甚至可以去做分布式集群。
目前在Github也是有46k的Star了。
好了,不卖关子,下面直接开整。
上手实践
在官网介绍了很多种搭建方式,本文使用Docker部署为主,如果你对Docker还不熟悉,可以移步到我 这篇文章 进行学习。
创建目录
首先我们需要创建几个目录,用来将主机上的 目录挂载到容器内的 /data
目录。容器内的 MinIO 服务会将存储的数据保存到这个挂载的目录中,确保数据持久化。
mkdir -p /opt/sofware/data/minio/data
mkdir -p /opt/sofware/data/minio/conf
拉取Minio镜像
近期很多镜像源都不能使用, 这里给大家推荐一个稳定好用的镜像源,也是我找了挺久, ubuntu,centos系统都可以用,直接复制即可。
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://dockerpull.com",
"https://docker.anyhub.us.kg",
"https://dockerhub.jobcher.com",
"https://dockerhub.icu",
"https://docker.awsl9527.cn"
]
}
EOF
sudo systemctl daemon-reload && sudo systemctl restart docke
通过以下命令拉取Minio镜像。
docker pull minio/minio
启动Minio容器
docker run --name minio --restart=always \
-p 9000:9000 -p 9090:9090 \
-e "MINIO_ROOT_USER=minio" \
-e "MINIO_ROOT_PASSWORD=minioadmin" \
-v /opt/sofware/data/minio/data:/data \
-v /opt/sofware/data/minio/conf:/root/.minio \
-d minio/minio server \
/data --console-address ":9090" -address ":9000"
命令详细解释:
docker run --name minio --restart=always
- 作用:启动一个名为
minio
的容器,并配置它在容器退出时自动重启(--restart=always
)。这意味着即使容器崩溃或主机重启,Docker 会自动尝试重新启动该容器。
-p 9000:9000 -p 9090:9090
作用
:将容器的端口映射到主机的端口上:
9000:9000
:将主机的9000
端口映射到容器的9000
端口,这是 MinIO 服务的主要访问端口。9090:9090
:将主机的9090
端口映射到容器的9090
端口,这是 MinIO 管理控制台的访问端口。
-e "MINIO_ROOT_USER=minio"
- 作用:设置 MinIO 的根用户名为
minio
。该用户名用于访问 MinIO 的管理界面和 API。
-e "MINIO_ROOT_PASSWORD=minioadmin"
- 作用:设置 MinIO 的根密码为
minioadmin
。该密码用于与MINIO_ROOT_USER
一起登录 MinIO 的管理界面和 API。
-v /opt/sofware/data/minio/data:/data
- 作用:将主机上的
/opt/sofware/data/minio/data
目录挂载到容器内的/data
目录。容器内的 MinIO 服务会将存储的数据保存到这个挂载的目录中,确保数据持久化。
-v /opt/sofware/data/minio/conf:/root/.minio
- 作用:将主机上的
/opt/sofware/data/minio/conf
目录挂载到容器内的/root/.minio
目录。容器内的 MinIO 服务的配置文件将存储在这个目录中。
-d minio/minio
- 作用:在后台(
-d
)启动一个基于minio/minio
镜像的容器。
server /data --console-address ":9090" --address ":9000"
作用
:这是 MinIO 服务启动的具体命令:
server /data
:告诉 MinIO 服务要使用/data
目录来存储对象数据(这正好对应挂载的主机目录/opt/sofware/data/minio/data
)。--console-address ":9090"
:指定 MinIO 控制台界面将运行在9090
端口上。--address ":9000"
:指定 MinIO API 将监听9000
端口。
最后在浏览器中访问 http://服务器IP:9090,即可访问到MinIO的控制台。
使用刚自己设置的密码登录即可。
Minio配置
创建一个 Bucket 存储桶,用于稍后文件的上传操作。
创建用于远程操作的AccessKey 和 SecretKey。
创建并保存好生成Access Key 和 Secret Key。
修改Access Policy的访问策略。
默认配置下,访问存储桶是需要请求授权的。但是在实际场景下,我们往往希望允许直接访问,此时就需要添加一条 readonly 访问规则。
本地测试
完成以上步骤之后,我们来进行一个测试。
首先在我们的桶里面上传一张图片。
然后同意以下规则在浏览器进行访问:
http://你的ip:9000/你的桶名称/上传的文件名 ,笔者这里是 http://192.168.4.101:9000/leocoder/121411-1692072851884b.jpg 大家替换为自己的实际地址就可以了。
可以看到浏览器可以直接访问到我们刚上传的图片,到这里测试完毕,大功告成!
SpringBoot整合
上面我们知道了如果通过手动上传图片并在浏览器访问。但是在实际开发中,我们需要通过Javaapi进行操作图片文件上传等操作。接下来我们在我们的SpringBoot项目整合minio。
创建SpringBoot项目
这个对于大家来说那就是小菜一碟了,我就不细讲了。
引入依赖
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.9</version>
</dependency>
编写Minio配置
minio:
endpoint: http:ip + 端口号
accessKey: accessKey
secretKey: secretKey
bucketName: 桶名称
@Configuration
public class MinioConfig {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient() {
// 构建 Minio 客户端
return MinioClient.builder()
.endpoint(minioProperties.getEndpoint())
.credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
.build();
}
}
@ConfigurationProperties(prefix = "minio")
@Component
@Data
public class MinioProperties {
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
}
编写工具类
@Component
@Slf4j
public class MinioUtil {
@Autowired
private MinioProperties minioProperties;
@Autowired
private MinioClient minioClient;
/**
* 上传文件
* @param file
* @return
* @throws Exception
*/
public String uploadFile(MultipartFile file) throws Exception {
// 判断文件是否为空
if (file == null || file.getSize() == 0) {
log.error("==> 上传文件异常:文件大小为空 ...");
throw new RuntimeException("文件大小不能为空");
}
// 文件的原始名称
String originalFileName = file.getOriginalFilename();
// 文件的 Content-Type
String contentType = file.getContentType();
// 生成存储对象的名称(将 UUID 字符串中的 - 替换成空字符串)
String key = UUID.randomUUID().toString().replace("-", "");
// 获取文件的后缀,如 .jpg
String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
// 拼接上文件后缀,即为要存储的文件名
String objectName = String.format("%s%s", key, suffix);
log.info("==> 开始上传文件至 Minio, ObjectName: {}", objectName);
// 上传文件至 Minio
minioClient.putObject(PutObjectArgs.builder()
.bucket(minioProperties.getBucketName())
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(contentType)
.build());
// 返回文件的访问链接
String url = String.format("%s/%s/%s", minioProperties.getEndpoint(), minioProperties.getBucketName(), objectName);
log.info("==> 上传文件至 Minio 成功,访问路径: {}", url);
return url;
}
}
编写controller
@RestController
public class AdminFileController {
@Autowired
private AdminFileService fileService;
/**
* 文件上传
*
* @param file 上传的文件
* @return Result
*/
@PostMapping("/file/upload")
public Result uploadFile(@RequestParam MultipartFile file) {
return fileService.uploadFile(file);
}
}
测试
启动项目,进行接口测试。
访问浏览器,可以看到可以直接进行访问。说明我们已经完成了SpringBoot整合Minio。
简单易用,兄弟们赶紧学起来吧。