在 Ubuntu 上搭建 MinIO 服务器

本文首发于博客园,原文链接:https://www.cnblogs.com/spcodhu/p/18635554
原文与本文的作者系同一人,因此投稿原创文章。


在日常开发时,如果有文件上传下载的需求(比如用户头像),但是又不想使用对象存储,那么自己搭建一个 MinIO 服务器是一个比较简单的解决方案。

MinIO 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从 几kb 到最大 5T 不等。

MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。


MinIO 中文网站:https://www.minio.org.cn/docs/minio/linux/operations/installation.html

部署 MinIO 并修改 minioadmin 的账户密码

本文主要介绍在 Ububtu 上单节点单硬盘部署 MinIO,步骤如下:

下载 MinIO 服务器

shell 复制代码
wget https://dl.min.io/server/minio/release/linux-amd64/minio

为 MinIO 二进制文件添加执行权限

shell 复制代码
chmod +x minio

在合适的位置创建一个文件夹,用于存储 MinIO 上传的文件数据

shell 复制代码
# 在根目录创建 minio-data 文件夹,存储 MinIO 上传的文件数据
mkdir ~/minio-data

安装 MinIO。将 MinIO 的二进制文件移到 /usr/local/bin/目录下,以使其全局可用

shell 复制代码
sudo mv minio /usr/local/bin/

使用持久化环境变量作为 MinIO console 的登录账户和密码。

编辑 .bashrc文件,这里使用 nano。

shell 复制代码
nano ~/.bashrc

在文件的最后加上环境变量

shell 复制代码
export MINIO_ROOT_USER=newrootuser
export MINIO_ROOT_PASSWORD=newrootpassword

重新加载.bashrc以使更改生效

shell 复制代码
source ~/.bashrc

启动 MinIO

shell 复制代码
nohup minio server --secure ~/minio-data

这里使用nohup确保会话关闭之后 MinIO 不会停止,也可以使用screen等会话技术,或者将 MinIO 作为一个服务启动。这里不做过多介绍。

启动 MinIO 之后,在浏览器访问 ip+9000 端口即可访问 MinIO 的 Web 控制台。如果访问不了,请先检查 MinIO 的两个端口是否已经开放,一个是 MinIO 的 WebUI 端口,这个是随机的;一个是 MinIO 的 API 端口,这个固定是 9000。

在浏览器访问 ip+9000 实际会跳转到 WebUI 的端口。但是在使用 API 上传下载文件需要使用 9000 端口。


给 MinIO 配置域名

如果不想直接暴露 MinIO 的地址和端口,则可以使用 Nginx 给 MinIO 配置域名访问。

在此之前,您需要先准备一个已备案的域名并解析到当前服务器。

步骤如下:

先安装 Nginx (如果没有的话)

shell 复制代码
sudo apt-get update
sudo apt-get install nginx

一般不建议直接更改位于/etc/nginx/nginx.conf的 nginx 主配置文件。采用如下的配置方式:

/etc/nginx/sites-available/创建新的配置文件,可以直接以当前配置的域名未文件名。我这里由于需要配置多个域名,文件名叫做minio.conf

shell 复制代码
cd /etc/nginx/sites-available/
touch minio.conf

书写配置文件

shell 复制代码
nano minio.conf

配置文件示例

xml 复制代码
# WebUI 配置
server {
    listen 80;
    server_name yourdomain.com; # 替换为您的域名

    location / {
        proxy_pass http://localhost:44366;  # 替换为实际的端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# API 配置
server {
    listen 80;
    server_name api.yourdomain.com; # 替换为您的API域名

    location / {
        proxy_pass http://localhost:9000;   # 替换为实际的端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启用新创建的配置文件。将/etc/nginx/sites-available/minio.conf链接到/etc/nginx/sites-enabled/目录

shell 复制代码
sudo ln -s /etc/nginx/sites-available/minio.conf /etc/nginx/sites-enabled/

可以先检查一下 nginx,确认没有语法错误

shell 复制代码
nginx -t

重启 nginx 服务

shell 复制代码
sudo systemctl restart nginx

此时,在本机浏览器上应该可以用域名访问 Minio console 了。


MinIO 调用示例

在 SpringBoot 中调用

先添加依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>8.4.3</version>
    </dependency>
</dependencies>

然后创建一个服务类来实现文件的上传下载

java 复制代码
import io.minio.*;
import io.minio.messages.Item;

import java.io.InputStream;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;

@Service
public class MinIOService {

    private final MinioClient minioClient;

    public MinIOService() {
        try {
            // 配置更改成自己的,建议写在配置文件中
            this.minioClient = MinioClient.builder()
                    .endpoint("http://localhost:9000")
                    .credentials("minioadmin", "minioadmin")
                    .build();
        } catch (MinioException e) {
            throw new RuntimeException("Failed to create MinioClient", e);
        }
    }

    public String uploadFile(String bucketName, String objectName, InputStream stream, long size) {
        try {
            minioClient.putObject(bucketName, objectName, stream, size);
            return "File uploaded successfully.";
        } catch (MinioException | IOException e) {
            throw new RuntimeException("File upload failed.", e);
        }
    }

    public InputStream downloadFile(String bucketName, String objectName) {
        try {
            return minioClient.getObject(bucketName, objectName);
        } catch (MinioException | IOException e) {
            throw new RuntimeException("File download failed.", e);
        }
    }
}

并为其书写对应的 Controller

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

@RestController
@RequestMapping("/minio")
public class MinIOController {

    @Autowired
    private MinIOService minIOService;

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) {
        String bucketName = "my-bucket";
        String objectName = UUID.randomUUID().toString();
        try (InputStream stream = file.getInputStream()) {
            return minIOService.uploadFile(bucketName, objectName, stream, file.getSize());
        } catch (IOException e) {
            return "Failed to upload file.";
        }
    }

    @GetMapping("/download/{objectName}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String objectName) {
        String bucketName = "my-bucket";
        InputStream stream = minIOService.downloadFile(bucketName, objectName);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + objectName + "\"")
                .body(new InputStreamResource(stream));
    }
}

在 Flask 中调用

下载依赖

shell 复制代码
pip install minio

然后创建一个 Flask 来集成 MinIO

python 复制代码
from flask import Flask, request, send_file, jsonify
from minio import Minio
from minio.error import S3Error

app = Flask(__name__)

# MinIO配置
minio_client = Minio(
    # 更改成自己的
    "localhost:9000",
    access_key="minioadmin",
    secret_key="minioadmin",
    secure=False
)

@app.route('/upload', methods=['POST'])
def upload_file():
    file = request.files['file']
    bucket_name = 'my-bucket'
    object_name = file.filename
    try:
        with open('/tmp/' + object_name, 'wb') as f:
            f.write(file.read())
        minio_client.fput_object(bucket_name, object_name, '/tmp/' + object_name)
        return jsonify({'message': 'File uploaded successfully'}), 200
    except S3Error as exc:
        return jsonify({'error': str(exc)}), 500

@app.route('/download/<object_name>', methods=['GET'])
def download_file(object_name):
    bucket_name = 'my-bucket'
    try:
        response = minio_client.get_object(bucket_name, object_name)
        return send_file(
            response.stream,
            as_attachment=True,
            attachment_filename=object_name,
            mimetype=response.headers['content-type']
        )
    except S3Error as exc:
        return jsonify({'error': str(exc)}), 500

if __name__ == '__main__':
    app.run(debug=True)

推荐阅读

MinIO Plus:https://mp.weixin.qq.com/s/kSkC3X-SQqo5GzXt-H66xw

相关推荐
AI人H哥会Java7 分钟前
【Spring】Spring DI(依赖注入)详解——自动装配——手动装配与自动装配的区别
java·开发语言·后端·spring·架构
helloasimo12 分钟前
Rocky Linux 下安装Liboffice
linux·rocky·安装liboffice
GGBondlctrl12 分钟前
【SpringBoot】深度解析 Spring Boot 拦截器:实现统一功能处理的关键路径
java·spring boot·后端·拦截器
计算机学姐21 分钟前
基于SpringBoot+Vue的旅游推荐系统
java·vue.js·spring boot·后端·mysql·tomcat·旅游
果粒陈爱写代码23 分钟前
Linux day 11 28
linux·运维·服务器
陈随易40 分钟前
Nodejs的竞争者Bun又整活了,Bun.s3预告
前端·后端·程序员
myNameGL41 分钟前
Linux SVN下载安装配置客户端
linux·运维·svn
张敬之、1 小时前
Ribbon
后端·spring cloud·ribbon
WongKyunban1 小时前
向bash shell脚本传参
linux·开发语言·bash
Lx3521 小时前
Pandas时间序列处理:日期与时间
后端·python·pandas