相关文章推荐

一 Minio简介

通常伴随着web项目开发, 很大可能会涉及到文件处理服务,再涉及文件转存方案的时候,需要涉及的方面有很多,涉及IO,接口开发,文件转存,文件权限,租户隔离,集群同步等实施方案,这个轮子建造还是需要很大力气的,因此有一套现成的解决方案,通过容器化部署即可实现整套的文件传输系统。
它的应用场景分为server端、Client端(内部服务)以及Console控制台端。Server端就是文件转存的服务端,除了默认配置,通常部署的Server会提供Client端和控制台,控制台是其内部可视化页面,Client端又细分为很多语言的驱动,主要包含Python、Java以及JS等。

  1. Centos7.9系统(有条件的就使用云产品或者内网穿透也可以,因为很多场景都是外网服务的坑比较多)
  2. docker部署
  3. Nginx安装与部署 快速部署Nginx

为什么用Nginx,这里有个小坑,可能我技术能力不够吧,后面会详细应用到。

Docker快速部署 Server(单点模式)

# 1、拉去Minio镜像
docker pull minio/minio
# 2、运行容器 采用运行容器的方式创建access_key和secret_key
# 这里的两个key可以自己设置
docker run -p 9000:9000 -p 9100:9100 \
--name MinioServer \
-d --restart=always \
-v /docker/minio/data:/data \
-v /docker/minio/config:/root/.minio \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=Changeme_123" \
minio/minio server /data --console-address ":9100"
# 3、检查容器是否启动成功,这里容器ID需要记录一下
docker ps -a 

参数解释:

MINIO_ROOT_USER 管理员用户的登录账号
MINIO_ROOT_PASSWORD 管理员用户的登录密码
9000端口是API 接口端口
9101端口是控制台访问端口(--console-address ":9100"   这个必须加上,不然启动是不能访问的)

基于Centos7环境,适配Linux环境,同时需要具备基本的docker容器化部署技术基础

docker启动后,我们根据容器ID查看启动日志

# 获取MinIO日志,使用 docker logs 命令。
docker logs <container_id>

如上图所示,这是MinioServer启动日志,但是我发现一个问题,无论是API还是Console的链接地址都是内网或者容器内地址。查看资料有人说可以配置环境变量,然并卵。网上大部门的资料都是部署在本地,如果本地的话,大家都是内网地址,因此不影响后面的功能使用。

配置Nginx进行转发代理

上面已经说过Nginx简易版本部署,差不多五分钟就搞好了,我们需要修改一下default.conf 文件配置

server {
    # Minio API
    listen       9002;
    server_name  公网IP;
    location / {
        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;
        proxy_set_header Host $http_host;
        proxy_connect_timeout  300;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://172.17.0.3:9000; 
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
server {
    # Minio Console
    listen       9001;
    server_name  公网IP;
    location / {
        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;
        proxy_set_header Host $http_host;
        proxy_connect_timeout  300;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://172.17.0.3:9101;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;

在第一个server里面,我加了一个<proxy_set_header Host $http_host;>参数,这里出现的问题,是因为我调用Java Minio Client 服务的时候,Client是可以链接的,但是无法获取文件,提示我请求头中的签名不能匹配,可能就是Nginx在这里转发的时候把请求头给丢了。
更改配置后,重启Nginx容器,并且要开发端口和安全组。
同时这里需要主要的时候这里的9001和9002是可以随便设置的,但是不能被占用

# 使用端口前需要查看一下是否被占用了,否则会导致启动失败的
ps -l | grep "端口号"

在这里插入图片描述
输入IP端口可以直接访问了,输入你上面登录和密码就可以进去了
在这里插入图片描述
这里对Minio 我简单研究了一下该控制台功能点,我们主要用到的功能

上传、下载,分享、删除、预览

在这里插入图片描述
重点看一下预览功能-share
在这里插入图片描述
你会发现这里IP地址是他妈的内网地址,这就很离谱,这个不是分享了一个寂寞。于是我开始百度,看资料~~~~发现网上给的方案几乎全部试了一遍,然并卵。
肯定是有办法的解决的,不然这个系统按理说是不完善的,只是 我还没有找到解决办法。目前只能开启匿名访问了。但是一旦开启了匿名访问,对文件预览下载直接通过固定IP地址去访问,可能就没办法做到安全问题。【就这样吧】
我会继续研究的,如果能解决的话,就会更新一下 // TODO

Minio Client 使用以Java为例

Maven依赖引入

		<dependency>
			<groupId>io.minio</groupId>
			<artifactId>minio</artifactId>
			<version>7.1.0</version>
		</dependency>

Minio Client 配置以及使用

import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
public class MinioUtils {
     * 配置自己服务的IP与端口号 这里设置就是上面Nginx中 Minio API 里面的端口别搞混了
    private static final String server = "http://1公网IP:9002";
     * access_key
    private static final String accessKey = "申请的key";
     * secret_key
    private static final String secretKey = "申请的key";
     * MinioClient客户端
    private static MinioClient client;
     * 初始化连接
    public static void initClient() {
        try {
            client = MinioClient
                    .builder()
                    .endpoint(server)
                    .credentials(accessKey, secretKey)
                    .build();
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * 获取桶列表
     * @return 桶列表
    public static List<Bucket> getAllBucketList() {
        try {
            return client.listBuckets();
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * 创建桶或者文件夹
     * @param bucketName 桶名
     * @param prefix     文件夹名称
    public static void createBucketOrFolder(String bucketName, String prefix) {
        try {
            // 首先查看当前桶是否存在
            if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            if (!isFolderExits(bucketName, prefix)) {
                client.putObject(PutObjectArgs.builder().bucket(bucketName).object(prefix)
                        .stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * <p>文件上传</p>
     *     <li>桶的概念就类似我们PC的“此电脑”,在“此电脑”下面才会存在我们不同的盘符,不同的盘符中有不同文件夹或者文件</li>
     *     <li>在桶里面的文件的objectName与文件夹的objectName显示存在差异,具体可以调试桶列表查看</li>
     *     <li>桶里面的文件夹实际就是前缀,它后面跟随的文件夹分割符号往往与我们部署的系统环境有关</li>
     * </ul>
     * @param bucketName     桶名称
     * @param prefix         桶内文件路径 例如: Demo桶下存在文件夹 它的objectName则为 folder/
     * @param in             文件流
     * @param fileFormatType 文件后缀 例如: .png .svg .xlsx 等
     * @return 范围服务器端的文件随机名称 例如:35ecae61-d6a6-4ce0-8175-e506dcdbc07a.png
    public static String putObject(String bucketName, String prefix, InputStream in, String fileFormatType) {
        try {
            // 设置UUID主要原因
            String key = UUID.randomUUID().toString() + fileFormatType;
            client.putObject(
                    PutObjectArgs
                            .builder()
                            .bucket(bucketName)
                            .object(prefix + key)
                            .stream(in, in.available(), -1)
                            .contentType("application/octet-stream")
                            .build());
            return key;
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * 获取文件信息 这里就用Minio原生模板类展示
     * <p>如果是存在文件路径下的文件,例如objectName = "demo/avatar.png" </p>
     * @param bucketName 桶名
     * @param objectName 文件名称
     * @return StatObjectResponse
    public static StatObjectResponse getObjectInfo(String bucketName, String objectName) {
        try {
            return client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * 获取文件下载链接,此链接是Minio提供的链接
     * @param bucketName 桶名
     * @param objectName 文件名称,如果存在文件路径下的文件,例如objectName = "demo/avatar.png"
     * @return String 下载链接
    public static String getObjectUrl(String bucketName, String objectName) {
        try {
            return client.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(bucketName)
                            .object(objectName)
                            .build());
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * 读取文件流的方式获取文件
     * @param bucketName 桶名
     * @param objectName 文件名称,如果存在文件路径下的文件,例如objectName = "demo/avatar.png"
     * @return InputStream 字节输入流
    public static InputStream getObjectStream(String bucketName, String objectName) {
        try {
            return client.getObject(
                    GetObjectArgs
                            .builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build());
        } catch (Throwable e) {
            throw new RuntimeException(e);
     * 判断桶和文件夹是否存在
     * @param bucketName 桶名称
     * @param prefix     文件夹 格式: folder/
     * @return boolean 是否存在
    public static boolean isFolderExits(String bucketName, String prefix) {
        try {
            if (null != prefix && !"".equals(prefix)) {
                Iterable<Result<Item>> results = client.listObjects(ListObjectsArgs.builder().bucket(bucketName)
                        .prefix(prefix).recursive(false).build());
                for (Result<Item> result : results) {
                    Item item = result.get();
                    if (item.isDir()) {
                        return true;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        return false;
  • 由于桶下面包含文件和文件夹,它们的区别就是存在文件夹分割符号,Linux / window \,具体区别可以通过上面getAllBucketList() 方法查看差异
  • 上传文件最好追加文件后缀,不然获取下载链接的时候,就需要前端工作人员对流文件进行明明,由于前端不一定知道文件的类型,所以尽量还是跟上后缀比较方便
  • 在业务层面要注意参数的判空处理,提升代码的质量性
  • 因为我使用的是Nginx代理转发,关于前面说到的$http_host配置问题,如果不加上的话,可能转发的时候直接把URL后面的签名给丢了,导致上面的utils中的方法不可用了。
CReSCENT:CanceR单细胞表达工具包(Web应用程序)-开发人员文档 有关用户手册,请转到CReSCENT文档: ://pughlab.github.io/crescent-frontend/ Git(克隆此仓库) 克隆此minio/download并创建文件夹results , minio/download和minio/upload (错误修复)。 将sample.env复制到.env然后将react/sample.env复制到react/.env并根据需要进行自定义。 npm install安装服务器依赖项。 docker-compose up以启动服务器后端。 如果您使用的是Windows或Mac,请确保GRAPHENE_DEV中的GRAPHENE_DEV变量设置为True ,并在文件共享中从.env共享/var/lib/toil .env 。
mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现,采用Docker容器部署。前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。 开发环境: JDK 1.8 Mysql 5.7 Redis 5.0 MongoDB 4.2.5 RabbitMQ 3.7.14 Nginx 1.10 Elasticsearch 7.6.2 Logstash 7.6.2 Kibana 7.6.2 搭建步骤: 1、Windows环境部署 Windows环境搭建请参考:mall在Windows环境下的部署; 注意:只启动mall-admin,仅需安装Mysql、Redis即可; 克隆mall-admin-web项目,并导入到IDEA中完成编译:前端项目地址; mall-admin-web项目的安装及部署请参考:mall前端项目的安装与部署。 2、Docker环境部署 使用虚拟机安装CentOS7.6请参考:虚拟机安装及使用Linux,看这一篇就够了; Docker环境的安装请参考:开发者必备Docker命令; 本项目Docker镜像构建请参考:使用Maven插件为SpringBoot应用构建Docker镜像; 本项目在Docker容器下的部署请参考:mall在Linux环境下的部署(基于Docker容器); 本项目使用Docker Compose请参考: mall在Linux环境下的部署(基于Docker Compose); 本项目在Linux下的自动化部署请参考:mall在Linux环境下的自动化部署(基于Jenkins); 3、相关环境部署 ELK日志收集系统的搭建请参考:SpringBoot应用整合ELK实现日志收集; 使用MinIO存储文件请参考:前后端分离项目,如何优雅实现文件存储; 读写分离解决方案请参考:你还在代码里做读写分离么,试试这个中间件吧; Redis集群解决方案请参考:Docker环境下秒建Redis集群,连SpringBoot也整上了!。
docker-compose使用示例 利用docker搭建一个mysql + java service + nginx,总共4个docker容器,如果采用docker run的方式一个一个容器去创建十分麻烦。为了能更高效的批量创建容器docker推出了docker-compose工具,只需要定义一个docker-compose.yml文件即可快速搞定一组容器的创建, mysql: image: daocloud.io/yjmyzz/mysql-osx:latest volumes: - ./mysql/db:/var/lib/mysql ports: - 3306:330
docker-compsose 搭建minio集群(2021-10月-11月左右的版本)+nginx反向代理及负载均衡(配置超详细讲解) 本文章适合有一定docker基础的朋友观看,如果觉得博主创作的好,麻烦点个赞和关注下,更多内容关注动态。最好大家版本同一,避免不必要的麻烦(镜像版本在compose文件里面有,下载即可) 首先我们需要配置docker-compse文件,配置文件的路径自选(我自己的放在/home目录下的)。并且由于官方的文件地址打不开,所以我会放到我的gitee上,链接统一的放到最后
 
推荐文章