介绍
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
Server服务端安装
- 二进制文件安装
(服务器文件可能下载比较慢,我本地下载完后上传到服务器的)
// 创建目录
mkdir /minio
mkdir /minio/data
// 下载
cd /minio
wget https://dl.min.io/server/minio/release/linux-amd64/minio
// 赋予可执行权限
chmod +x minio
// 启动服务
./minio server /minio/data
效果如下(ip是显示的内网的,可以用外网地址打开,如果打不开查看下端口是不没有开放):
默认生成的AccessKey和SecretKey如上图都是是minioadmin,最后一行提示我们应该立即修改账号和密码!!!)
- docker 安装
上传文件
进入系统后,我们先要点击右下角的“+”按钮,创建一个文件桶(输入名称后,回车即可),在上传文件到这个文件桶中。Create bucket(创建文件桶)、Upload file(上传文件)。
文件桶可以理解为目录,上传的文件必须要放到某个桶里。查看服务器我们看到相应的文件确实生成了,因为我们现在并不是分布式存储,没有使用纠删码的模式,所以直接是源文件。
操作文件
文件最右边有操作按钮,点击后会弹出分享、预览、下载和删除按钮。
分享会生成一个很长的链接,并可以指定有效期。默认最大是7天,可以更改文件桶(Bucket)的策略(Policy)
后台启动
我们的minio之前是通过命令行直接启动的,并没有指定后台运行,而且端口跟AccessKey和SecretKey都还是使用默认的,ctrl+c
关闭会话网址就访问不了了,所以我们需要在启动的时候指定。
(账号密码也可以修改 /minio/data
里面的 /.minio.sys/config/config.json
的credential
节点,修改 access_key 和 secret_key 后面value中的值就可以了。)
新建一个名为minio_start.sh脚本文件:
#!/usr/bin/env sh
# 设置用户名
export MINIO_ACCESS_KEY=minioadmin
# 设置用户密码
export MINIO_SECRET_KEY=123456
# 后台启动,将启动日志输出到/minio/minio_start.log,以1个本地节点启动minio单节点
nohup /minio/minio server /minio/data > /minio/minio_start.log 2>&1 &
echo 'minio is running'
赋予可执行权限chmod +x minio_start.sh
执行文件 ./minio_start.sh
我发现密码没有运行成功,是因为脚本文件修改并运行了好几次,可以用ps -ef | grep minio
查出进程,然后kill该进程。
关闭服务:
使用ps -aux | grep 'sh脚本文件nohub之后的第一个参数'
,我这里是ps -aux | grep '/minio/minio'
,查到相应进程,然后kill掉。
https 安全访问
虽然在官方文档中说明了如何使用HTTPS,但是通过Nginx更灵活,且后期调整也比较方便。这里参考的是官方实战秘籍-为MinIo设置Nginx代理。
- 将以下内容添加为文件/etc/nginx/sites-enabled,例如/etc/nginx/sites-enables/minio
我们代理的是所有请求,所以location 直接设置为 /,上面实战秘籍有指导单独代理某个存储桶,有需要的自己配置下。
# http 跳转到 https
server {
listen 80;
server_name example.com;
rewrite ^(.*)$ https://$host$1 permanent;
}
# 以下属性中以ssl开头的属性代表与证书配置有关,其他属性请根据自己的需要进行配置。
server {
listen 443 ssl; #SSL协议访问端口号为443。此处如未添加ssl,可能会造成Nginx无法启动。
server_name example.com; #将localhost修改为您证书绑定的域名,例如:www.example.com。
ssl_certificate cert/minio/domain name.pem; #将domain name.pem替换成您证书的文件名。
ssl_certificate_key cert/minio/domain name.key; #将domain name.key替换成您证书的密钥文件名。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #使用此加密套件。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。
ssl_prefer_server_ciphers on;
# To 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 1000m;
# To disable buffering
proxy_buffering off;
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;
# 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:9000; # If you are using docker-compose this would be the hostname i.e. minio
# Health Check endpoint might go here. See https://www.nginx.com/resources/wiki/modules/healthcheck/
# /minio/health/live;
}
}
注意:
- 用您自己的主机名替换
example.com
。 http://localhost:9000
用您自己的服务器名称替换。- 添加
client_max_body_size 1000m;
为了能够上传大文件,请在http上下文中进行操作-只需相应地调整该值即可。1m对于大多数情况,默认值太低。要禁用客户端请求正文大小的检查,请设置client_max_body_size
为0。 - Nginx默认缓冲响应。要禁止Nginx将MinIO响应缓冲到临时文件,请设置
proxy_buffering off;
。这将缩短到达客户请求的第一个字节的时间。 - Nginx默认情况下不允许特殊字符。设置
ignore_invalid_headers off;
为允许带有特殊字符的标题。
- 通过从服务器目录创建 symlink (指针)来激活服务器块。配置文件站点从sites-available目录移至sites-enabled目录,执行命令:
ln -s /etc/nginx/sites-available/minio /etc/nginx/sites-enabled/minio
。 - 重新启动Nginx服务,执行命令:
systemctl restart nginx
。
Clinet客户端安装
MinIO Client (mc)为ls,cat,cp,mirror,diff,find等UNIX命令提供了一种替代方案。它支持文件系统和兼容Amazon S3的云存储服务(AWS Signature v2和v4)。
流程基本和安装server端一致
- 二进制文件安装
// 下载
cd /minio
wget https://dl.min.io/client/mc/release/linux-amd64/mc
// 赋予可执行权限
chmod +x mc
2.添加一个云存储服务
添加一个或多个S3兼容的服务,mc将所有的配置信息都存储在~/.mc/config.json
文件中。别名就是给你的云存储服务起了一个短点的外号。S3 endpoint,access key和secret key是你的云存储服务提供的。API签名是可选参数,默认情况下,它被设置为"S3v4"。
mc config host add <ALIAS> <YOUR-S3-ENDPOINT> <YOUR-ACCESS-KEY> <YOUR-SECRET-KEY> [--api API-SIGNATURE]
示例:
./mc config host add minio192_168_1_1 http://192.168.1.1:9000 minioadmin minioadmin --api s3v4
- 验证
列出别名为 minio
的云存储服务上的所有存储桶
mc ls minio
- 删除一个主机
可以手动编辑
${HOME}/.mc/config.json
文,所有的配置信息都在这个文件里,我的完整路径是/root/.mc/config.json
。
这里我们使用命令 ./mc config host ls
列出所有主机(除了红色标注的其他的都是官方默认添加的,如play是官方演示服务,local是本地的服务,我也已经把账号密码都配置上了),然后使用./mc config host rm minio
删除
备份文件到 MinIO
上面是在 mac 电脑上安装了 client 端测试用的,实际上我们需要的是服务器到服务器的文件备份。
真实场景:这里我们以备份 mysql 数据文件为例,我们现在有两台服务器,一台主服务器A,一台服务器B。A服务器部署了我们的MinIo,B服务器放一些小项目,现在我们想把B服务器的 mysql 数据文件持续备份到MinIo上,一方面我们可以直接通过MinIo的web站点下载数据文件,不再需要 FTP 传输了。另一方面,我们对数据做了异地备份,一旦出事我们可以快速的恢复数据,这是很重的。
流程如下:
-
在B服务器部署 Client 端
安装Client端流程参考前面介绍。
添加A服务器主机连接,因为我们前面已经添加了https,所以直接使用域名的形式。主机连接名字不能加.
,所以使用了下划线。密码由于包含了特殊字符,所以需要用''
引号包裹。
./mc config host add minio_www_example_com https://www.example.com minioadmin 'minioadmin!@#' --api s3v4
-
定时自动备份 mysql
如何定时自动备份可以参考我的文章《debian9+mysqldump+crontab 定时自动完整备份》
-
创建一个存储桶
mb
是创建存储桶的指令,我们使用客户端 mc 的 mb 指令在A主服务器创建一个名为mysqlbkp-www.example.com
的存储桶,当然使用web页面创建也一样(好像不创建也是可以的)。
./mc mb minio_www_example_com/mysqlbkp-www.example.com
- 连续将本地文件镜像到A服务器
./mc mirror --overwrite --watch /本地目录 主机minio_www_example_com/存储桶mysqlbkp-www.example.com
这个是不能后台运行的,你ctrl+c
之后它就不再运行了。如果有需要的话可以用nohup后台启动,就像前面后台启动minio服务一样。
新建一个名为mc_mirror.sh脚本文件:
#!/usr/bin/env sh
# 后台启动 mc mirror,将启动日志输出到/minio/mc_mirror.log
nohup /minio/mc mirror --overwrite --watch /本地目录 minio_www_example_com/mysqlbkp-www.example.com > /minio/mc_mirror.log 2>&1 &
echo 'mc mirror is running'
赋予可执行权限chmod +x mc_mirror.sh
执行文件 ./mc_mirror.sh
- 关闭服务
使用ps -aux | grep 'sh脚本文件nohub之后的第一个参数'
,ps -aux | grep '/minio/mc'
,查到相应进程,然后kill掉。
最终效果图
编程上传文件
提供一个 egg.js 的实例,一定要仔细看备注,并结合前面写的内容才行。
'use strict';
const Minio = require('minio')
const Controller = require('./base');
class FileObsController extends Controller {
constructor(ctx) {
super(ctx);
// 初始化 minio 客户端
this.minioClient = new Minio.Client({
endPoint: 'www.example.com',
// port: 9000,
useSSL: true,
accessKey: 'minioadmin',
secretKey: '123456'
});
}
/**
* 上传图片
* @return {Promise<void>}
*/
async upload() {
const { ctx } = this;
try {
const accept = 'image'
const { name } = this.config.myConfig.private
const currentUser = ctx.request.user
const bucketName = name
/* 获取文件流 */
const stream = await ctx.getFileStream();
console.log('-----------获取数据 start--------------');
console.log(stream);
// formData中的其他字段
console.log(stream.fields);
console.log('-----------获取数据 end--------------');
/* 验证并创建存储桶 */
const exists = await this.minioClient.bucketExists(bucketName)
console.log('step 1')
if (!exists) {
// 创建项目的存储桶
await this.minioClient.makeBucket(bucketName)
// 设置存储桶策略(默认是私有,url 不能直接访问)
// 向匿名用户授予只读权限(其他策略请查阅官方文档)
const policy = {
Version: '2012-10-17',
Statement: [
{
Sid: 'PublicRead',
Effect: 'Allow',
Principal: '*',
Action: ['s3:GetObject', 's3:GetObjectVersion'],
Resource: [`arn:aws:s3:::${bucketName}/*`]
}
]
}
await this.minioClient.setBucketPolicy(bucketName, JSON.stringify(policy))
}
/* 上传文件 */
// 使用旧的文件名,允许被覆盖
// const objectName = stream.filename
// 使用新的文件名,防止被覆盖
const objectName = `${accept}/${Date.now()}_${stream.filename}`
const size = stream.readableLength
console.log(size)
// 设置 metaData
const metaData = {
// 默认是灰色不能预览,因为默认content-type 是 application/octet-stream
// 'Content-Type': 'application/octet-stream',
'Content-Type': stream.mimeType
}
const etag = await this.minioClient.putObject(bucketName, objectName, stream, size, metaData)
console.log('step 2', etag)
/* 组装文件地址 */
const { url: obsUrl } = 'https://www.example.com'
const url = `${obsUrl}/${bucketName}/${objectName}`
console.log('step 3', url)
this.success({ ctx, data: { url } });
} catch (err) {
console.log(err)
this.fail({ ctx, message: err });
}
}
}
module.exports = FileObsController;