跳至主要內容

搭建MinioOSS存储服务

Leo服务搭建服务搭建约 1973 字大约 7 分钟

Minio + Docker 搭建属于自己的OSS存储服务

为什么要自己搭建呢

其实个人小项目为了图方便,完全可以去使用阿里云或者腾讯云的OSS的服务,现在几大厂商的OSS服务已经都比较成熟了。但是接踵而来的有一个致命的问题。虽说云厂商的OSS非常方便,引入SDK即可使用,但是你被人恶意刷流量所带来的费用,你真的承担的起吗!!!

虽然说你暂时可能没被刷,但是如果哪天到我们头上,那可是毁灭性打击,毕竟自己写项目一毛钱还没赚到,流量被刷了几万块,想想就难受。

所以自己搭建的一个文件存储服务便可以让我们的压力变为最小化。

为什么选择Minio

MinIOopen in new window 是一个高性能的轻量级对象存储服务器。它具有分布式,高可用性和水平扩展的特点,它非常适合用于大规模数据存储和分析。其优点包括低延迟、高吞吐量、易于部署和管理

如果担心一台可能也会垮掉,我们甚至可以去做分布式集群。

目前在Github也是有46k的Star了。

CleanShot 2024-09-04 at 16.43.56@2x
CleanShot 2024-09-04 at 16.43.56@2x

好了,不卖关子,下面直接开整。

上手实践

在官网介绍了很多种搭建方式,本文使用Docker部署为主,如果你对Docker还不熟悉,可以移步到我 这篇文章open in new window 进行学习。

创建目录

首先我们需要创建几个目录,用来将主机上的 目录挂载到容器内的 /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"

命令详细解释:

  1. docker run --name minio --restart=always
  • 作用:启动一个名为 minio 的容器,并配置它在容器退出时自动重启(--restart=always)。这意味着即使容器崩溃或主机重启,Docker 会自动尝试重新启动该容器。
  1. -p 9000:9000 -p 9090:9090
  • 作用

    :将容器的端口映射到主机的端口上:

    • 9000:9000:将主机的 9000 端口映射到容器的 9000 端口,这是 MinIO 服务的主要访问端口。
    • 9090:9090:将主机的 9090 端口映射到容器的 9090 端口,这是 MinIO 管理控制台的访问端口。
  1. -e "MINIO_ROOT_USER=minio"
  • 作用:设置 MinIO 的根用户名为 minio。该用户名用于访问 MinIO 的管理界面和 API。
  1. -e "MINIO_ROOT_PASSWORD=minioadmin"
  • 作用:设置 MinIO 的根密码为 minioadmin。该密码用于与 MINIO_ROOT_USER 一起登录 MinIO 的管理界面和 API。
  1. -v /opt/sofware/data/minio/data:/data
  • 作用:将主机上的 /opt/sofware/data/minio/data 目录挂载到容器内的 /data 目录。容器内的 MinIO 服务会将存储的数据保存到这个挂载的目录中,确保数据持久化。
  1. -v /opt/sofware/data/minio/conf:/root/.minio
  • 作用:将主机上的 /opt/sofware/data/minio/conf 目录挂载到容器内的 /root/.minio 目录。容器内的 MinIO 服务的配置文件将存储在这个目录中。
  1. -d minio/minio
  • 作用:在后台(-d)启动一个基于 minio/minio 镜像的容器。
  1. 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:9090open in new window,即可访问到MinIO的控制台。

CleanShot 2024-09-04 at 17.05.02@2x
CleanShot 2024-09-04 at 17.05.02@2x

使用刚自己设置的密码登录即可。

Minio配置

  1. 创建一个 Bucket 存储桶,用于稍后文件的上传操作。

    CleanShot 2024-09-04 at 19.07.02@2x
    CleanShot 2024-09-04 at 19.07.02@2x
  2. 创建用于远程操作的AccessKey 和 SecretKey

    CleanShot 2024-09-04 at 19.18.31@2x
    CleanShot 2024-09-04 at 19.18.31@2x
  3. 创建并保存好生成Access Key 和 Secret Key

    CleanShot 2024-09-04 at 19.19.04@2x
    CleanShot 2024-09-04 at 19.19.04@2x
  4. 修改Access Policy的访问策略。

    CleanShot 2024-09-04 at 19.17.04@2x
    CleanShot 2024-09-04 at 19.17.04@2x
  5. 默认配置下,访问存储桶是需要请求授权的。但是在实际场景下,我们往往希望允许直接访问,此时就需要添加一条 readonly 访问规则。

CleanShot 2024-09-04 at 19.22.24@2x
CleanShot 2024-09-04 at 19.22.24@2x

本地测试

完成以上步骤之后,我们来进行一个测试。

首先在我们的桶里面上传一张图片。

CleanShot 2024-09-04 at 19.25.11@2x
CleanShot 2024-09-04 at 19.25.11@2x

然后同意以下规则在浏览器进行访问:

http://你的ip:9000/你的桶名称/上传的文件名open in new window ,笔者这里是 http://192.168.4.101:9000/leocoder/121411-1692072851884b.jpgopen in new window 大家替换为自己的实际地址就可以了。

CleanShot 2024-09-04 at 19.28.40@2x
CleanShot 2024-09-04 at 19.28.40@2x

可以看到浏览器可以直接访问到我们刚上传的图片,到这里测试完毕,大功告成!

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);
    }
}

测试

启动项目,进行接口测试。

CleanShot 2024-09-04 at 19.42.00@2x
CleanShot 2024-09-04 at 19.42.00@2x
CleanShot 2024-09-04 at 19.43.50@2x
CleanShot 2024-09-04 at 19.43.50@2x

访问浏览器,可以看到可以直接进行访问。说明我们已经完成了SpringBoot整合Minio。

简单易用,兄弟们赶紧学起来吧。