docker部署minio

minio的单点搭建

# 拉取minio最新版
docker pull minio/minio
# 运行minio,密码设置有一定要求
docker run -d  -p 9000:9000 -p 9001:9001 --name minio -v /data/minio-data:/data -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=141421Hss"  minio/minio server /data --console-address ":9001"
# 查看日志
docker logs minio
# 开启服务器安全组规则中的9000和9001端口
# 访问minio控制台 http://ip:9001

创建桶

image-20230116110222123

在服务器中会生成一个和桶名称相同的文件夹

image-20230116110353980

设置桶规则;修改权限public,设置规则为readwrite

image-20230116110431693

image-20230116110450077

测试上传文件

image-20230116110539763

image-20230116110550092

上传完文件之后,在服务器的桶中会生成一个文件

image-20230116110639141

使用springboot对minio进行文件的上传

image-20230116155203262

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.13.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.hu</groupId>
    <artifactId>minio-01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <lomback.version>1.8.4</lomback.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!--引入springcloud的版本-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.6</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!--nacos配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <!--加入nocas-client 服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>mvn-releases</id>
            <name>Public Repositories</name>
            <url>https://artifacts.iflytek.com/artifactory/mvn-repo/</url>
        </repository>
        <repository>
            <id>aliyun-repos</id>
            <name>Aliyun Repository</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <profiles>
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <profile.active>dev</profile.active>
                <profile.namespace>74d06a53-0810-44fe-ab92-27603c1eecd3</profile.namespace>
            </properties>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <profile.active>test</profile.active>
                <profile.namespace>74d06a53-0810-44fe-ab92-27603c1eecd3</profile.namespace>
            </properties>
        </profile>
    </profiles>
</project>
package com.hu.entity;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @Author : sshu10
 * @create 2023/1/16 14:04
 */
@Data
@Configuration
public class MinioProp {
    /**
     * 连接url
     */
    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * 用户名
     */
    @Value("${minio.accesskey}")
    private String accesskey;

    /**
     * 密码
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 桶名称
     */
    @Value("${minio.bucketName}")
    private String bucketName;
}
package com.hu.controller;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.hu.entity.MinioProp;
import io.minio.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

/**
 * @Author : sshu10
 * @create 2023/1/16 14:30
 */
@RestController
@RequestMapping("/minio")
@Validated
@Slf4j
public class MinioController {

    @Autowired
    private MinioClient minioClient;
    @Autowired
    private MinioProp minioProp;

    /**
     * 判断桶存在不存在,不存在创建桶
     * @Author sshu
     * @Description
     * @param bucketName
     * @return void
     **/
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            return;
        }
        minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }

    @SneakyThrows
    public InputStream getObjectInputStream(String objectName, String bucketName){
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return minioClient.getObject(getObjectArgs);
    }

    /**
     * 上传
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping("/post/uploadFile")
    public JSONObject uploadFile(@RequestBody MultipartFile file, String fileName) throws Exception {
        JSONObject res = new JSONObject();
        res.put("code", 0);
        // 判断上传文件是否为空
        if (null == file || 0 == file.getSize()) {
            res.put("msg", "上传文件不能为空");
            return res;
        }
        InputStream is=null;
        try {
            // 判断存储桶是否存在
            createBucket(minioProp.getBucketName());
            // 文件名
            String originalFilename = file.getOriginalFilename();
            // 新的文件名 = 存储桶名称_时间戳.后缀名
            if(StringUtils.isEmpty(fileName)){
                fileName = minioProp.getBucketName() + "_" + UUID.fastUUID().toString().replaceAll("-", "") + originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            // 开始上传
            is=file.getInputStream();
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minioProp.getBucketName())
                    .object(fileName)
                    .contentType(file.getContentType())
                    .stream(is, is.available(), -1)
                    .build();
            minioClient.putObject(putObjectArgs);

            res.put("code", 1);
            res.put("msg",  minioProp.getBucketName() + "/" + fileName);
            res.put("bucket", minioProp.getBucketName());
            res.put("fileName", fileName);
            return res;
        }  catch (Exception e) {
            e.printStackTrace();
            log.error("上传文件失败:{}", e.getMessage());
        }finally {
            is.close();
        }
        res.put("msg", "上传失败");
        return res;
    }

    /**
     * 下载
     * @param fileName
     * @param realFileName
     * @param response
     * @param request
     */
    @GetMapping("/get/downloadFile")
    public void downloadFile(String fileName, String realFileName, HttpServletResponse response, HttpServletRequest request) {
        InputStream is=null;
        OutputStream os =null;
        try {
            is = getObjectInputStream(fileName, minioProp.getBucketName());
            if(is!=null){
                byte buf[] = new byte[1024];
                int length = 0;
                String codedfilename = "";
                String agent = request.getHeader("USER-AGENT");
                System.out.println("agent:" + agent);
                if ((null != agent && -1 != agent.indexOf("MSIE")) || (null != agent && -1 != agent.indexOf("Trident"))) {
                    String name = URLEncoder.encode(realFileName, "UTF8");
                    codedfilename = name;
                } else if (null != agent && -1 != agent.indexOf("Mozilla")) {
                    codedfilename = new String(realFileName.getBytes("UTF-8"), "iso-8859-1");
                } else {
                    codedfilename = new String(realFileName.getBytes("UTF-8"), "iso-8859-1");
                }
                response.reset();
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(realFileName.substring(realFileName.lastIndexOf("/") + 1), "UTF-8"));
                response.setContentType("application/octet-stream");
                response.setCharacterEncoding("UTF-8");
                os = response.getOutputStream();
                // 输出文件
                while ((length = is.read(buf)) > 0) {
                    os.write(buf, 0, length);
                }
                // 关闭输出流
                os.close();
            }else{
                log.error("下载失败");
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("错误:"+e.getMessage());
        }finally {
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除
     * @param objectName
     */
    @PostMapping("/post/deleteFile")
    public void deleteFile(String objectName) {
        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                    .bucket(minioProp.getBucketName())
                    .object(objectName)
                    .build();
            minioClient.removeObject(removeObjectArgs);
        }catch (Exception e){
            log.error("错误:"+e.getMessage());
        }
    }
}
package com.hu.config;

/**
 * @Author : sshu10
 * @create 2023/1/16 14:07
 */

import com.hu.entity.MinioProp;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MinioConfig {
    @Autowired
    private MinioProp minioProp;

    @Bean
    public MinioClient minioClient(){
        MinioClient minioClient = MinioClient.builder().endpoint(minioProp.getEndpoint()).
                credentials(minioProp.getAccesskey(), minioProp.getSecretKey()).region("china").build();
        return minioClient;
    }
}
server:
  port: 9999
  servlet:
    context-path: /minio
    encoding:
      enabled: true
      force: true
      charset: UTF-8
spring:
  profiles:
    active: @profile.active@
  application:
    name: minio
#配置中心
nacos:
  config:
    # 命名空间ID
    namespace: 74d06a53-0810-44fe-ab92-27603c1eecd3
    # nacos 服务器地址
    server-addr: localhost:8848
    # nacos 配置的 data-id
    data-ids: minio
    # 配置文件 Group
    group: dev
    # nacos 配置文件类型
    type: yaml
    # 是否启用动态刷新配置
    auto-refresh: true
    bootstrap:
      # 这个需要为 true, 否则启动项目时不设置 value默认值会报错,也不会自动更新,请查看 NacosConfigApplicationContextInitializer 文件
      enable: true

#服务发现中心
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: 74d06a53-0810-44fe-ab92-27603c1eecd3
        group: dev
spring:
  application:
    name: minio
  cloud:
    nacos:
      config:
        server-addr: ${system.active.nacos.dev.server-addr}
        namespace: 74d06a53-0810-44fe-ab92-27603c1eecd3
        file-extension: yml
        refresh-enabled: true
        group: dev
        encode: UTF-8
      discovery:
        server-addr: ${system.active.nacos.dev.server-addr}
        namespace: ${system.active.nacos.dev.namespace}
        group: dev

system.active.nacos:
  dev:
    server-addr: localhost:8848
    namespace: 74d06a53-0810-44fe-ab92-27603c1eecd3
  test:
    server-addr: localhost:8848
    namespace: 74d06a53-0810-44fe-ab92-27603c1eecd3

#日志
log:
  path: ${system.logging.dev.path}
system.logging:
  dev:
    path: /data/sshu/minio-01/logs
  test:
    path: logs

用apifox调用

image-20230116155517084

问题

docker没有用阿里云镜像加速器时,下载的minio与上图不一致

设置镜像加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://e45d12yg.mirror.aliyuncs.com"]
}
EOF
# 重新加载配置文件
sudo systemctl daemon-reload
# 重启docker
sudo systemctl restart docker

启动minio报错

ERROR Unable to initialize backend: format.json file: expected format-type: fs, found: xl-single
删除调挂载目录下的.minio.sys文件即可,因为之前挂载过

cd /data/minio-data
ls -a .minio.sys
rm -rf .minio.sys