服务器运维之MinIO

标签: 无 分类: 未分类 创建时间:2023-12-17 04:36:05 更新时间:2024-11-24 10:04:01

1.前言

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

参考文章:
【1】.装在笔记本里的私有云环境:网络存储篇(上) 在我们熟悉的公有云平台上,网络存储类型一般会分为:块存储、对象存储、文件存储三类。其他更多的品类,则更多是基于这三类进行了一些不同侧重功能的场景定制,赋予了更强的业务能力。
【2】.一个docker容器搞定存储与图床——minio 这篇文章讲了使用docker部署minio的问题,还讲了一些坑的避免
【3】.开源分布式对象存储-MinIO
【4】.MinIO 教程 从简单搭建,到复杂的教程,基本上都能有一个大致的描述,是一个系列教程。
【5】.AI数据基础设施的对象存储
【6】. MinIO 介绍 与 FastDFS 对比 这里有一个简单的对比,FastDFS 暂时无法和 Minio 进行比较,毕竟很少有人去维护了。

2.名次解释

3.单机安装

(1) 下载

(2) 安装
下载解压之后,直接将 minio 程序放到 /usr/local/minio/bin 目录下

1
mkdir -p /data/server/minio/{bin,data,config,log}

(3) 启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 设置MinIO的配置参数
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=minioadmin
#设置MinIO端口
#S3-API端口
export MINIO_ADDRESS=":6900"
#Console端口
export MINIO_CONSOLE_ADDRESS=":6901"
#设置MinIO安装路径
export MINIO_PATH_DIR="/usr/local/minio"
#设置MinIO配置文件路径
export MINIO_CONFIG_DIR="/usr/local/minio/config"
# 设置数据存储路径
export MINIO_DATA_DIR="/home/data/minio"
# 启动MinIO服务器
nohup $MINIO_PATH_DIR/bin/minio server --address $MINIO_ADDRESS --console-address $MINIO_CONSOLE_ADDRESS --config-dir $MINIO_CONFIG_DIR $MINIO_DATA_DIR > $MINIO_PATH_DIR/log/minio.log 2>&1 &

(4) 关闭脚本

1
2
3
4
5
6
7
8
#!/bin/bash
echo "Stopping minio"
pid=`ps -ef | grep 'minio server' | grep -v grep | awk '{print $2}'`
if [ -n "$pid" ]
then
kill -9 $pid
fi
echo "Stop Success!"

(5) 自启动
有了开启和关闭脚本之后,我还想着要用自动启动的方式进行开机启动,但是好像写的总是不对。

经过多次尝试,最后修改成了 /usr/lib/systemd/system/minio.service 的启动脚本如下,其中 /bin/bash /usr/local/minio/bin/start.sh 比较关键

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=Minio Service

[Service]
User=root
Group=root
Type=forking
ExecStart=/bin/bash /usr/local/minio/bin/start.sh
ExecStop=/bin/bash /usr/local/minio/bin/shutdown.sh
PrivateTmp=true

[Install]
WantedBy=multi-user.target

有了自启动脚本,就可以实现开机启动了。

1
2
3
4
# 启动
systemctl start minio
# 停止
systemctl stop minio
参考文章:
【1】.linux配置minio通过服务单机启动 1.直接启动;2.后台启动;3.定制服务启动,加入系统自动启动。
【2】.linux 下安装minio并配置
【3】.Linux下MinIO单节点安装部署 这里提供了启动脚本和关闭脚本,就是我上面列出的东西
【4】.linux minio 安装 并设置开机自启动 这里主要是使用了 vim /usr/lib/systemd/system/minio.service 配置了开机启动,没有用启动脚本
【5】.编写systemctl启动脚本 编写了httpd、nginx、php-fpm脚本。
【6】.单机部署MinIo并设置开机自启 这里的启动脚本也是直接使用的:ExecStart=/home/minio/bin/minio server –address :9010 –console-address :9011 /home/minio/data
【7】.Linux系统如何设置开机自动运行脚本? 方法一:修改 /etc/rc.d/rc.local 文件;方法二:使用 crontab;方法三:使用 systemd 服务
【8】.Unable to start Minio Service 这里是官方的一个讨论,但是最后到底如何解决的,我没有看出来。
【9】.linux强行退出脚本执行,linux – Systemd退出bash脚本,执行导致失败的命令,而不是继续…

5.配置

早期使用MINIO_ACCESS_KEY 和 MINIO_SECRET_KEY 配置密钥,后来提示: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecated. Please use MINIO_ROOT_USER and MINIO_ROOT_PASSWORD。浏览器打开 http://192.168.1.8:6900/ 可以访问 minio web页面。

(1)新建用户
通过控制台->Identity->Users可以创建用户。

参考文章:
【1】.MinIO的配置与安装 这里也是写成了服务的形式。
【2】.MinIO 自定义 Access Key 和 Secret Key在启动 MinIO 时指定自定义 Access Key 和 Secret Key; 使用 Docker secrets 进行 MinIO Access 和 Secret 密钥自定义
【3】.minio创建用户获取秘钥
【4】.minio中的安装启动地址问题 –address参数:用于指定MinIO服务器监听的S3 API访问地址。–console-address参数:用于指定MinIO服务器控制台的访问地址。
【5】.MinIO 服务器配置(区域) MinIO 中可以使用区域来表示当前服务器的位置。

6.文件上传

文件上传,很多的库都实现了这个功能,比如jeecgboot里面的,这里我把源码贴出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
public class MinioUtil {
private static String minioUrl;
private static String minioName;
private static String minioPass;
private static String bucketName;

public static void setMinioUrl(String minioUrl) {
MinioUtil.minioUrl = minioUrl;
}

public static void setMinioName(String minioName) {
MinioUtil.minioName = minioName;
}

public static void setMinioPass(String minioPass) {
MinioUtil.minioPass = minioPass;
}

public static void setBucketName(String bucketName) {
MinioUtil.bucketName = bucketName;
}

public static String getMinioUrl() {
return minioUrl;
}

public static String getBucketName() {
return bucketName;
}

private static MinioClient minioClient = null;

/**
* 上传文件
* @param file
* @return
*/
public static String upload(MultipartFile file, String bizPath, String customBucket) throws Exception {
String fileUrl = "";
//update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
bizPath = StrAttackFilter.filter(bizPath);
//update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击

//update-begin-author:liusq date:20210809 for: 过滤上传文件类型
SsrfFileTypeFilter.checkUploadFileType(file);
//update-end-author:liusq date:20210809 for: 过滤上传文件类型

String newBucket = bucketName;
if(oConvertUtils.isNotEmpty(customBucket)){
newBucket = customBucket;
}
try {
initMinio(minioUrl, minioName,minioPass);
// 检查存储桶是否已经存在
if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(newBucket).build())) {
log.info("Bucket already exists.");
} else {
// 创建一个名为ota的存储桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build());
log.info("create a new bucket.");
}
InputStream stream = file.getInputStream();
// 获取文件名
String orgName = file.getOriginalFilename();
if("".equals(orgName)){
orgName=file.getName();
}
orgName = CommonUtils.getFileName(orgName);
// String objectName = bizPath+"/"
// +( orgName.indexOf(".")==-1
// ?orgName + "_" + System.currentTimeMillis()
// :orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."))
// );
// 不进行重新命名
String objectName = bizPath+"/"+orgName;

// 使用putObject上传一个本地文件到存储桶中。
if(objectName.startsWith(SymbolConstant.SINGLE_SLASH)){
objectName = objectName.substring(1);
}
PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
.bucket(newBucket)
.contentType("application/octet-stream")
.stream(stream,stream.available(),-1).build();
minioClient.putObject(objectArgs);
stream.close();
fileUrl = minioUrl+newBucket+"/"+objectName;
}catch (Exception e){
log.error(e.getMessage(), e);
}
return fileUrl;
}

/**
* 文件上传
* @param file
* @param bizPath
* @return
*/
public static String upload(MultipartFile file, String bizPath) throws Exception {
return upload(file,bizPath,null);
}

/**
* 获取文件流
* @param bucketName
* @param objectName
* @return
*/
public static InputStream getMinioFile(String bucketName,String objectName){
InputStream inputStream = null;
try {
initMinio(minioUrl, minioName, minioPass);
GetObjectArgs objectArgs = GetObjectArgs.builder().object(objectName)
.bucket(bucketName).build();
inputStream = minioClient.getObject(objectArgs);
} catch (Exception e) {
log.info("文件获取失败" + e.getMessage());
}
return inputStream;
}

/**
* 删除文件
* @param bucketName
* @param objectName
* @throws Exception
*/
public static void removeObject(String bucketName, String objectName) {
try {
initMinio(minioUrl, minioName,minioPass);
RemoveObjectArgs objectArgs = RemoveObjectArgs.builder().object(objectName)
.bucket(bucketName).build();
minioClient.removeObject(objectArgs);
}catch (Exception e){
log.info("文件删除失败" + e.getMessage());
}
}

/**
* 获取文件外链
* @param bucketName
* @param objectName
* @param expires
* @return
*/
public static String getObjectUrl(String bucketName, String objectName, Integer expires) {
initMinio(minioUrl, minioName,minioPass);
try{
//update-begin---author:liusq Date:20220121 for:获取文件外链报错提示method不能为空,导致文件下载和预览失败----
GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName)
.bucket(bucketName)
.expiry(expires).method(Method.GET).build();
//update-begin---author:liusq Date:20220121 for:获取文件外链报错提示method不能为空,导致文件下载和预览失败----
String url = minioClient.getPresignedObjectUrl(objectArgs);
return URLDecoder.decode(url,"UTF-8");
}catch (Exception e){
log.info("文件路径获取失败" + e.getMessage());
}
return null;
}

/**
* 初始化客户端
* @param minioUrl
* @param minioName
* @param minioPass
* @return
*/
private static MinioClient initMinio(String minioUrl, String minioName,String minioPass) {
if (minioClient == null) {
try {
minioClient = MinioClient.builder()
.endpoint(minioUrl)
.credentials(minioName, minioPass)
.build();
} catch (Exception e) {
e.printStackTrace();
}
}
return minioClient;
}

/**
* 上传文件到minio
* @param stream
* @param relativePath
* @return
*/
public static String upload(InputStream stream,String relativePath) throws Exception {
initMinio(minioUrl, minioName,minioPass);
if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
log.info("Bucket already exists.");
} else {
// 创建一个名为ota的存储桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
log.info("create a new bucket.");
}
PutObjectArgs objectArgs = PutObjectArgs.builder().object(relativePath)
.bucket(bucketName)
.contentType("application/octet-stream")
.stream(stream,stream.available(),-1).build();
minioClient.putObject(objectArgs);
stream.close();
return minioUrl+bucketName+"/"+relativePath;
}

/**
* 批量删除文件
*
* @param bucketName bucket
* @param keys 需要删除的文件列表
*/
public static boolean removeObjects(String bucketName, List<String> keys) {
initMinio(minioUrl, minioName,minioPass);
try {
List<DeleteObject> objects = new LinkedList<>();
for (String objectName:keys){
objects.add(new DeleteObject(objectName));
}
Iterable<Result<DeleteError>> results =
minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
log.error("Error in deleting object " + error.objectName() + "; " + error.message());
}
return true;
}catch (Exception e){
log.error("removeObjects",e);
}
return false;
}

/** * 下载文件 * * @param fileUrl 文件绝对路径 * @param response * @throws IOException */
@GetMapping("downloadFile")
public void downloadFile(String fileUrl, HttpServletResponse response) throws IOException {

if (StringUtils.isBlank(fileUrl)) {

response.setHeader("Content-type", "text/html;charset=UTF-8");
String data = "文件下载失败";
OutputStream ps = response.getOutputStream();
ps.write(data.getBytes("UTF-8"));
return;
}
try {

// 拿到文件路径
String url = fileUrl.split("9000/")[1];
// 获取文件对象
InputStream object = minioUtils.getObject(MinioConst.MINIO_BUCKET, url.substring(url.indexOf("/") + 1));
byte buf[] = new byte[1024];
int length = 0;
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(url.substring(url.lastIndexOf("/") + 1), "UTF-8"));
response.setContentType("application/octet-stream");
response.setCharacterEncoding("UTF-8");
OutputStream outputStream = response.getOutputStream();
// 输出文件
while ((length = object.read(buf)) > 0) {

outputStream.write(buf, 0, length);
}
// 关闭输出流
outputStream.close();
} catch (Exception ex) {

response.setHeader("Content-type", "text/html;charset=UTF-8");
String data = "文件下载失败";
OutputStream ps = response.getOutputStream();
ps.write(data.getBytes("UTF-8"));
}
}

}
参考文章:
【1】.上传文件到minio文件大小限制
【2】.Minio工具类 这里基本上包括了所有的方法了,可以作为参考,这里很多的代码。
【3】.minio文件存储 删除多个文件
【4】.MinioUtils中removeObjects批量删除无效的解决办法 原来是因为没有遍历结果的原因,源码方法的上面有一句注释(但是我没找到这句注释),大致意思就是删除后一定要遍历结果,至于为啥这么做,我们稍后见。
【5】.一次恶心的删除minio文件之旅 1.最快的方式,一定是在服务器上用linux命令删除;2.写java代码,可是minio的java客户端只支持按完整的对象路径删除;3.
【6】.写给大忙人看的 – Java中从MinIO服务器中下载文件(3)[通俗易懂]

7.其他

7.1.扩容

参考文章:
【1】.MinIO如何扩容

7.2.用户管理

7.3.压缩和解压

我有很多的小文件,但是一个个的上传感觉特别的浪费时间,我想着能不能实现先压缩然后到minio上再解压呢?或者有没有其他的方法,能解决大量小文件上传的问题呢?

7.4.多文件上传

我利用了 ffmpeg 切出来了很多的小文件,最后我还是用了多文件上传的技术进行了文件上传,这样可以保证上传的效率。

1
2
3
4
5
6
7
ExecutorService executorService= Executors.newFixedThreadPool(NUM_THREADS);
for(File f:fs){
executorService.submit(()->{
uploadMinio(f,bizPath);
});
}
executorService.shutdown();
参考文章:
【1】.多线程实战(多线文件上传)
【2】.Java 读取多个文件流合并操作
【3】.java实现大文件多线程上传案例 以上代码实现了将大文件分片上传的逻辑。通过使用线程池管理并发上传任务,每个任务负责上传一个片段。在上传过程中,通过随机访问文件方式,避免将整个文件加载到内存中,从而避免内存溢出的问题。
【4】.如何实现Java 多线程上传多文件的具体操作步骤 和上一篇文章差不多,用了 ExecutorService executorService= Executors.newFixedThreadPool(NUM_THREADS);

8.nginx配置

前置条件:在启动minio服务前指定以下环境变量,MINIO_SERVER_URL为 minio-api 的地址,MINIO_BROWSER_REDIRECT_URL为 minioconsole 的地址。可以按照实际需求配置。

(1) 配置启动参数
这里的 MINIO_SERVER_URL 为API接口地址,不能带二级域名,不能是 https://xxx.com/file。MINIO_BROWSER_REDIRECT_URL为浏览器浏览地址,可以带 二级目录。经过尝试,也就是说,其实这个 api 访问接口,不能配置子目录,只能配置域名加上端口,或者是子域名加端口,不能加后面的路径,但是网页管理端口就是可以的。

1
2
3
# 配置二级目录
export MINIO_SERVER_URL=https://xxx.com:10014
export MINIO_BROWSER_REDIRECT_URL=https://xxx.com:10014/filebrowser

(2) nginx配置
在nginx中配置,就要注意,下面给出了一个可以正常登录的 https 配置

  • 第一个就是 minio 的 api 端口,必须是一级目录,不能是二级目录

  • 第二个要注意的就是,api端口和console端口,要在同一个端口下面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    server {
    listen 10014 ssl;
    listen [::]:10014 ssl;
    server_name openmap.tech;

    ssl_certificate "./conf/xxx.com.pem";
    ssl_certificate_key "./conf/xxx.com.key";

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;

    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Allow special characters in headers
    ignore_invalid_headers off;
    # Allow any size file to be uploaded.
    # Set to a value such as 1000m; to restrict file size to a specific value
    client_max_body_size 0;
    # Disable buffering
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
    proxy_set_header Host $http_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;

    proxy_connect_timeout 300;
    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    chunked_transfer_encoding off;

    proxy_pass http://localhost:10012; # This uses the upstream directive definition to load balance
    }

    location /filebrowser/ {
    rewrite ^/filebrowser/(.*) /$1 break;
    proxy_set_header Host $http_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;
    proxy_set_header X-NginX-Proxy true;

    # This is necessary to pass the correct IP to be hashed
    real_ip_header X-Real-IP;

    proxy_connect_timeout 300;

    # To support websockets in MinIO versions released after January 2023
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    # Some environments may encounter CORS errors (Kubernetes + Nginx Ingress)
    # Uncomment the following line to set the Origin request to an empty string
    # proxy_set_header Origin '';

    chunked_transfer_encoding off;

    proxy_pass http://localhost:10013/; # This uses the upstream directive definition to load balance
    }
    }

(3)单独配置API接口
还有一种情况,就是单独配置api接口的https,至于console控制台,可以不用配置。关闭配置 MINIO_SERVER_URL 和 MINIO_BROWSER_REDIRECT_URL,然后将 location 配置为桶的名字,然后去掉 proxy_pass 下的斜杠,如下所示,其中 drone 为我的桶的名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server {
listen 10014 ssl;
listen [::]:10014 ssl;
server_name openmap.tech;

ssl_certificate "./conf/9254477_www.openmap.tech.pem";
ssl_certificate_key "./conf/9254477_www.openmap.tech.key";

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Allow special characters in headers
ignore_invalid_headers off;
# Allow any size file to be uploaded.
# Set to a value such as 1000m; to restrict file size to a specific value
client_max_body_size 0;
# Disable buffering
proxy_buffering off;
proxy_request_buffering off;

location /drone {
proxy_set_header Host $http_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;

proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;

proxy_pass http://localhost:10012; # This uses the upstream directive definition to load balance
}
}
参考文章:
【1】.为MinIO Server设置Nginx代理 所使用的路径(在本例中为files)按照惯例,应设置为minio所使用的存储桶的名称。
【2】.通过nginx二级目录反向代理访问minio管理界面 在启动minio服务前指定以下环境变量,MINIO_SERVER_URL为minio-api的地址,MINIO_BROWSER_REDIRECT_URL为minioconsole
【3】.minio分布式搭建,并用nginx代理
【4】.线上Minio部署+反向代理控制台+Java调用
【5】. 线上Minio部署+反向代理控制台+Java调用
【6】.解决Nginx代理MinIO出现Access Denied 这里提到了将 location 的名字改为 桶的名字。

9.https配置

刚开始的时候,我使用的是nginx进行的配置,结果总是报错 502 ,各种问题,后来我尝试使用 minio 进行配置,结果竟然一集就搞定了。
(1)申请ssl证书
我这里因为使用的是和 nginx 同一个证书,也就不用这么麻烦了,就将 nginx 的证书 .pem 和 .key 改为了 public.crt 和 private.key

(2)创建目录
我创建一个certs目录,存储这两个证书。

(3)修改启动脚本
把 MINIO_SERVER_URL 和 MINIO_BROWSER_REDIRECT_URL 删除,然后添加了一个 –certs-dir /$MINIO_PATH_DIR/certs/ 配置就可以了。

1
nohup $MINIO_PATH_DIR/bin/minio server --certs-dir /$MINIO_PATH_DIR/certs/ --address $MINIO_ADDRESS --console-address $MINIO_CONSOLE_ADDRESS --config-dir $MINIO_CONFIG_DIR $MINIO_DATA_DIR > $MINIO_PATH_DIR/log/minio.log 2>&1 &

(4)最后的启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 设置MinIO的配置参数

export MINIO_ROOT_USER=xxx

export MINIO_ROOT_PASSWORD=xxx

#设置MinIO端口

#S3-API端口

export MINIO_ADDRESS=":6900"

#Console端口

export MINIO_CONSOLE_ADDRESS=":6901"

#设置MinIO安装路径

export MINIO_PATH_DIR="/usr/local/minio"

#设置MinIO配置文件路径

export MINIO_CONFIG_DIR="/usr/local/minio/config"

# 设置数据存储路径

export MINIO_DATA_DIR="/home/data/minio"

# 配置二级目录
#export MINIO_SERVER_URL=https://openmap.tech:10014
#export MINIO_BROWSER_REDIRECT_URL=https://openmap.tech:10014/filebrowser

# 启动MinIO服务器

nohup $MINIO_PATH_DIR/bin/minio server --certs-dir /$MINIO_PATH_DIR/certs/ --address $MINIO_ADDRESS --console-address $MINIO_CONSOLE_ADDRESS --config-dir $MINIO_CONFIG_DIR $MINIO_DATA_DIR > $MINIO_PATH_DIR/log/minio.log 2>&1 &

(4)nginx
这是一个可选的项,只是作为记录,开始的时候,我总是无法用 nginx 进行 minio 的 https 配置,弄了很久都不行,最后只能通过配置 minio 的certs 选项才可以吼。后来我再次尝试的时候,竟然可以使用了,还真是奇怪,下面是 nginx 的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
## minio 的 https 配置
server {
listen 10003 ssl;
server_name openmap.tech;

ssl_certificate cert/openmap.tech.pem;
ssl_certificate_key cert/openmap.tech.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

add_header X-Frame-Options SAMEORIGIN;


proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
## 保持长时间连接
proxy_read_timeout 600s;

proxy_set_header Host $host;#保留代理之前的host
proxy_set_header X-Real-IP $remote_addr;#保留代理之前的真实客户端ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header HTTP_X_FORWARDED_FOR $remote_addr;#在多级代理的情况下,记录每次代理之前的客户端真实ip
proxy_set_header X-Forwarded-Proto $scheme; #表示客户端真实的协议(http还是https)
proxy_set_header Referer $scheme://$server_name$request_uri;


include conf.d/*.conf;

#去除多斜杠的配置
merge_slashes off;
rewrite (.*)//(.*) $1/$2 permanent;


index index.html;
location / {
proxy_pass http://127.0.0.1:10005/;
}
}
参考文章:
【1】.在 CentOS 上搭建 MinIO 对象存储服务并配置 HTTPS 这里还有安装之类的方法。
【2】.踩坑记录之MinIO添加HTTPS访问 这里也有些其他的问题,可以作为参考,如果已经有了域名的情况下,可能就不是问题了。
【3】.minio将http改为https方式访问 这里增加了websocket支持
【4】.nginx 反向代理minio错误排查

10。Docker安装

配置 http 访问,端口设置为 9000 和 9090

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn"
]
}
EOF

## 下载镜像
docker pull minio/minio

## 创建目录
mkdir -p /home/hj/minio/config
mkdir -p /home/hj/minio/data

## 启动新的容器
docker run -p 9000:9000 -p 9090:9090 \
--net=host \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=minioadmin" \
-e "MINIO_SECRET_KEY=minioadmin" \
-v /home/minio/data:/data \
-v /home/minio/config:/root/.minio \
minio/minio server \
/data --console-address ":9090" -address ":9000"

## 查询全部容器
docker ps
## 关闭
docker stop 容器id
## 启动
docker start 容器id
## 删除
docker rm 容器id
## 配置ssl,创建一个certs目录,存储下载的nginx两个证书 .crt 和 .key,然后指定 --certs-dir 配置

我将 nginx 的证书 xxx.pem 改为了 public.crt, xxx.key 改为了 private.key,拷贝到 /home/hj/mimio/config/certs 目录下,配置了 https 访问

1
2
3
4
5
6
7
8
9
10
11
## 配置 https 访问
docker run -p 10005:10005 -p 10006:10006 \
--net=host \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=xxx" \
-e "MINIO_SECRET_KEY=xxx" \
-v /home/hj/minio/data:/data \
-v /home/hj/minio/config:/root/.minio \
minio/minio server \
/data --console-address ":10005" -address ":10006"
参考文章:
【1】.Docker 搭建 Minio 容器 (完整详细版) 这里还是很详细的,包括了api操作。
【2】.记一下docker启动minio 这里大部分的都是 docker 的简单操作。
【3】.全网最全,基于docker 创建的Minio容器配置Https 访问,不使用第三方服务 将证书配置挂载到minio容器的/root/.minio/certs目录下
【4】.minio docker https 配置 踩坑 私钥需要命名为:private.key 公钥需要命名为:public.crt (如果公钥是以pem格式结尾,可直接改为crt格式),这里还有其他注意事项。
【5】.在Docker中快速部署MinIO

11.查询

minio控制台提供的搜索,只能进行文件名的搜索,而且只能是当前文件夹才有效,深一层的文件夹就无效了。

参考文章:
【1】.如何实现对存储在MinIO上的数据的高效搜索与查询 1.对象元数据索引;2.Elasticsearch集成;3.日志分析工具;4.对象标签(Object Tags);5.文件命名规范;
【2】.minio查询桶中文件,桶目录中文件 这里是用了代码实现的
【3】.minio 支持object搜索方案 因此我们打算将object的对象的数据放到数据库。在数据库中对object进行筛选。

12.问题汇总

本章主要就是写了关于 minio 使用过程中的一些问题,后来其实也是解决了。

(1) Unable to parse STS response.

MINIO_ADDRESS 地址是 API 监听地址,改为API监听地址就可以了。

参考文章:
【1】.Bad Request with STS in minio

(2)STS service failed with HTTP status code 403

报错的代码主要是下面的代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
 public CredentialsToken getCredentials() {
try {
AssumeRoleProvider provider = new AssumeRoleProvider(DroneOssConfiguration.endpoint,
DroneOssConfiguration.accessKey,
DroneOssConfiguration.secretKey, Math.toIntExact(DroneOssConfiguration.expire),
null, DroneOssConfiguration.region, null, null, null, null);
return new CredentialsToken(provider.fetch(), DroneOssConfiguration.expire);
} catch (NoSuchAlgorithmException e) {
log.debug("Failed to obtain sts.");
e.printStackTrace();
}
return null;
}

【尝试方法】
这里除了检查用户名密码之外,还要检查 区域 设置 , 因为我在安装的时候没有配置 区域,于是我就用了默认的 region: us-east-1,就算我不写这个区域,其实也不会出现这个403错误的。

【解决方法】
有一种情况,那就是 关于这个 用户名密码 配置,是启动minio的MINIO_ROOT_USER 用户名 和 MINIO_ROOT_PASSWORD 密码,而不是 在管理客户端配置的 access-key 和 secret-key。我在官方上看到了这么一句话:By default, MinIO denies access to actions or resources not explicitly allowed by an attached or inherited policy. A user with no explicitly assigned or inherited policies cannot perform any S3 or MinIO administrative API operations.

或者是直接创建一个新的用户

参考文章:
【1】.minio报错 403 Forbidden 在minio中,设置桶的访问策略,Buckets -> Manage -> Summary -> Access Policy。
【2】.MinIO安装配置和使用 S3地区: 就填写默认的us-east-1,因为之前创建joplin存储桶的时候没有指定,所以默认地区就是这个,S3访问密钥: 用户名,密钥: 密码
【3】.Invalid Login 403 Forbidden for root user after initial configuration
【4】.User Management 这里是关于用户策略的描述:MinIO by default denies access to all actions or resources not explicitly allowed by a user’s assigned or inherited policies. You must either explicitly assign a policy describing the user’s authorized actions and resources or assign the user to groups which have associated policies. See Access Management for more information.
【5】.Identity and Access Management
【6】.HTTP status code 403

(3)控制台登陆 401 问题

配置了nginx之后,登录结果出现了401错误。

【解决方法】
正确的配置了 nginx 就可以了。

(4)Unsupported or unrecognized SSL message
配置了 nginx 反向代理之后,结果调用 API 的时候,就出现了这个问题。

【解决方法】
正确的配置了 https 就可以了。

参考文章:
【1】.政务外网部署 minio上传下载报错 javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 全局搜索MinioClient,查看在哪里初始化给secure赋值false即可
【2】.解决springboot2.X整合minio出现SSLException: Unrecognized SSL message问题 将之前配置的 secure参数由true改成了false,使用给定的endpoint、port、access key、secret key和一个secure选项(表示的是是否使用https)创建一个Minio client对象。
【3】.踩坑记录之MinIO添加HTTPS访问
【4】.endpoint does not allow path No you cannot - hosting S3 APIs other / is not allowed.
【5】.Minio+Nginx+Docker 控制台登陆 401 问题,请问如何解决?

(4)配置了 https 访问,导致 minio 总是出现 502 错误

我配置了 MINIO_SERVER_URL 和 MINIO_BROWSER_REDIRECT_URL,在访问的时候,总是出现 502 网关错误。

【尝试方案】
(1)我删除了 MINIO_SERVER_URL 和 MINIO_BROWSER_REDIRECT_URL 配置,然后只把 api 接口使用了 nginx 进行了 https 配置,控制台通过 ip 地址进行访问。但是这样的方式只能进行读取,不能进行上传了。

(2)还有就是我的nginx配置的使用的 frp 进行内网穿透做的,猜测会是这样的问题。如果使用 minio 配置https ,还有 nginx 再配置https,这是不是就是两个https解析呢,特别是在我阿里云服务转发到内网的情况下,导致速度更低了。

【解决方案】
最终的解决方案其实就是不要用 nginx 进行 https 的配置,通过minio进行https的配置最好了,方法参照 https 配置。

参考文章:
【1】.nginx 反向代理 minio 的 9090 端口的控制台,报 502 错误 这里也有这个问题

(5)STS service failed with HTTP status code 405

(6) Response code: 400, Content-Type: null, body: Client sent an HTTP request to an HTTPS server.

我配置了 minio 的https访问,结果使用http请求的时候,就出现了这个问题。

【解决方案】
经过尝试,最后我通过配置了nginx解决了这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# minio
server {
listen 10012;

# 文件上传大小
client_max_body_size 5G;

location / {
root html;
index index.html index.htm;

proxy_set_header Host $http_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;
proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass https://localhost:6900; # This uses the upstream directive definition to load balance
}
}

(7) 上传慢

我在使用内网上传的时候,比如使用 127.0.0.1 上传,结果也还是很慢。我在想,是不是 rclone 的问题,还是minio本身的问题。

参考文章:
【1】.Minio上传文件慢优化

(8) Invalid Request (request has multiple authentication types, please use one)

【解决方案】
这个问题是因为我在 url 中进行了鉴权,在 header 中由进行了一遍鉴权。

(9) error pulling image configuration: download failed after attempts=6: dial tcp 108.160.169.46:443: i/o timeout

在阿里云的服务器上安装的时候,没有出现问题,但是在电信云上安装minio总是拉取不下来镜像。

1
docker pull minio/minio

【尝试方法】
(1)修改为阿里云的镜像
(2)修改下面的源,不行

1
2
3
4
5
6
7
8
9
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn"
]
}
EOF

(3)修改为163的源:http://hub-mirror.c.163.com,结果不行
(4)尝试了 bitnami/minio 镜像,不行

参考文章:
【1】.Podman 介绍,安装,基本操作 这是docker替代方案
【2】.docker 拉取镜像失败 这里用了 https://docker.m.daocloud.io 这个镜像地址,解决了问题。
【3】.Docker pull国内无法拉取镜像解决办法(代理) 配置了代理:Environment=”HTTP_PROXY=http://10.24.20.201:7890"
【4】.Docker测试运行hello-world镜像 测试 hello-world 镜像
【5】.国内无法访问下载Docker镜像的解决方案
【6】.Docker Hub 镜像加速器 这里三个源,都不行
【7】.全网最细Docker安装Minio,填满最新版大坑(强烈推荐收藏)
【8】.docker离线部署minio
【9】.『MinIO』在Docker中快速部署MinIO

(10). Write failed. Insufficient number of drives online

在我将 minio 进行对外映射之后,数据始终都写入不进去,后来我看了看日志,结果大部分的错误都是这个 Insufficient number of drives online。刷新页面:We encountered an internal error, please try again.: cause(listPathRaw: 0 drives provided),Storage resources are insufficient for the write operation .minio.sys/config/iam/sts/X2KJSM160IUJO1O7XKBU/identity.json (cmd.InsufficientWriteQuorum)

【尝试方案】
(1)查了很久,没有好的解决方案,只能升级minio版本了,但是这个好像不是根本,因为现在只不过是因为我用了 cpolar 进行数据上传导致的问题,但是我以前用 frp 进行处理的时候,类型选择了 tcp 也没有这个问题出现。
(2)测试本地内网控制台上传,和内网java上传,都是没有问题的
(3)修改了minio配置,升级之后,又出现了:Error: unexpected EOF (*errors.errorString)
(4)设置了 MINIO_API_REMOTE_TRANSPORT_DEADLINE:在联合实例之间进行代理时,设置远程传输上的 API 请求的截止日期,例如“2h”(默认值:“2h”)

1
2
3
4
5
6
# set the deadline for API requests waiting to be processed (default: ‘10s’)
export MINIO_API_REQUESTS_DEADLINE="2h"
# set the number of transition workers (default: ‘100’)
export MINIO_API_TRANSITION_WORKERS="2000"
# set the deadline for API requests on remote transports while proxying between federated instances e.g. “2h” (default: ‘2h’)
export MINIO_API_REMOTE_TRANSPORT_DEADLINE="24h"

(5) 修改了 MINIO_SERVER_URL 结果无效

参考文章:
【1】.minio报错:Unable to use the drive /data: invalid argument
【2】.Error: Write failed. Insufficient number of disks online (*errors.errorString)
【3】.Storage resources are insufficient for the write operation after adding additional disk pool. 这里说空间不足导致的
【4】.自建minio上传失败
【5】.The Error “EOF” is occurred in Minio console login 这里解决EOF的问题,配置了 MINIO_SERVER_URL
【6】.媒体文件一直在上传minio 这里和我的问题很像,就是说遇到了 媒体文件一直在上传,媒体文件上传失败是:Error: unexpected EOF (*errors.errorString)
【7】.MinIo报错记录及解决方法 防火墙问题,需开发端口或者关闭防火墙.
【8】.关于Minio性能优化 A timeout exceeded while waiting to proceed with the request, please reduce your request 这里有多个环境变量可以配置 MINIO_API_REQUESTS_DEADLINE、MINIO_API_REMOTE_TRANSPORT_DEADLINE、MINIO_API_TRANSITION_WORKERS
【9】.unexpected EOF (*errors.errorString)
【10】.After setting environment variable “MINIO_SERVER_URL”, some interface errors occur.

(11).Access denied

不知道minio抽了什么风,结果就是登陆进去之后,直接显示空白,控制台显示 Access denied 错误,到底哪里出现了问题。我已经开始觉得崩溃了,明明就是好的

【尝试方案】
(1)同步时间,结果我查了服务器的时间,就是正确的时区
(2)对 minio 的数据文件夹实行 chmod 755 -R ,结果数据太多,导致特别的慢,但是最后也没有用
(3)当我重新用docker安装和启动的时候,结果也还是一样的问题。

【解决方案】
我不断的变换端口,不断的尝试,最后竟然是因为换了一个浏览器,才解决了这个问题。开始用的谷歌浏览器,后来换成了火狐浏览器,结果就是好的。

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。