分布式文件存储 minIO
文件系统
文件系统的作用:对磁盘空间进行统一规划,并提供接口给普通用户进行操作。用户通过文件名即可找到具体的数据而不用关心数据是怎么存储的。
本地文件系统
linux 常用 exts 系列,windows 使用 NTFS。只要搞清楚文件系统的作用,它们只不过换了个名字而已。
分布式文件系统
分布式文件系统最大的特点是多个客户端可以访问相同的服务端。 NFS(网络文件系统) 也属于分布式文件系统,用户可以像访问本地硬盘一样访问共享计算机上的文件。
对象存储服务(Object Storage Service,OSS)
在项目开发过程中,我们会产生大量的对象数据,包括:日志文件,数据库脚本文件、安装包,容器镜像,图像、视频等等,我们不仅仅是需要有一个集中的地方来存储,还需要能基于 Web 的方式来访问它们,以往我们有以下几种方法来解决:
- 阿里云、Azure 等云服务商提供的 SaaS 级别的 OSS 服务;
- 自己搭建对象存储软件(使用 minIO 实现,软件选型参考 常用的分布式文件系统);
- 自己搭建 NAS 网络存储通过 Samba 服务来访问;
- 自己搭建 FTP 服务器来存储(以容器方式实现,通过 FTP 上传文件,通过 HTTP 服务访问文件)
# 使用vsftpd搭建FTP服务器
docker run -d -p 2121:21 -p 2020:20 -p 21100-21110:21100-21110 -v /usr/local/wlhiot/mount/ftp:/home/vsftpd/ftp -e FTP_USER=ftp -e FTP_PASS=123456 -e PASV_ADDRESS=192.168.254.29 -e PASV_MIN_PORT=21100 -e PASV_MAX_PORT=21110 --name vsftpd fauria/vsftpd:latest
# 使用nginx映射文件,将ftp上传的目录也一并挂载到nginx容器中使其能被访问
docker run -d --name autoindex harbor.wlhiot.com:8080/library/nginx:1.21.1 # 为了将挂载文件复制到本地,到时候起了容器后能直接通过修改本地配置文件来实现容器配置的修改
docker cp autoindex:/etc/nginx /usr/local/wlhiot/mount/nginx/autoindex/conf
docker cp autoindex:/usr/share/nginx/html /usr/local/wlhiot/mount/nginx/autoindex/html
docker cp autoindex:/var/log/nginx /usr/local/wlhiot/mount/nginx/autoindex/logs
docker ps -a | grep autoindex | awk '{print $1}' | xargs docker rm -f # 停止指定容器并删除
docker run -d -p 8101:80 --name autoindex -v /usr/local/wlhiot/mount/nginx/autoindex/conf:/etc/nginx -v /usr/local/wlhiot/mount/nginx/autoindex/html:/usr/share/nginx/html -v /usr/local/wlhiot/mount/nginx/autoindex/logs:/var/log/nginx -v /usr/local/wlhiot/mount/ftp:/rsync harbor.wlhiot.com:8080/library/nginx:1.21.1
cat /usr/local/wlhiot/mount/nginx/autoindex/conf/conf.d/default.conf # 修改配置文件使其支持文件访问
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /rsync;
autoindex on;
autoindex_exact_size off;
}
}
# ftp://192.168.254.29:2121/ # 登录FTP服务器,剩下的操作看FTP文档
# http://192.168.254.29:8101/ # 浏览器访问
minIO
minIO 可以让你将多块硬盘(无论是否在同一机器)组成一个对象存储服务,通过对象存储服务实现文件上传下载及共享(可将应用程序所需的文件进行剥离,使其成为无状态应用),需关注如下几个注意点:
- 分布式 minIO 里所有的节点需要有同样的 access 密钥和 secret 密钥,这样这些节点才能建立联接。为了实现这个,建议在执行 minio server 命令之前,在所有节点上先将 access 密钥和 secret 密钥 export 成环境变量 MINIO_ROOT_USER 和 MINIO_ROOT_PASSWORD;
- minIO 可创建每组 4 到 16 个磁盘组成的纠删码集合。所以你提供的磁盘总数必须是其中一个数字的倍数;
- minIO 会根据给定的磁盘总数或者节点总数选择最大的纠删码集合大小,确保统一分布,即每个节点参与每个集合的磁盘数量相等;
在单机模式下,minIO 直接在/data 目录下存储,不会建立副本,也不会启用纠删码机制,一旦磁盘发生损坏及意味着磁盘丢失。
根据最佳实践,生产环境至少使用四块硬盘。这样可以做到挂掉一块硬盘集群依然可以读写,挂掉两块硬盘集群依然可读。在分布式模式下,minIO 将自动启用纠删码功能。
应用场景
minIO 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从 KB 到最大 TB 不等。
对于中小型企业,如果不选择存储上云,那么 minIO 是个不错的选择,麻雀虽小,五脏俱全。当然 minIO 除了直接作为对象存储使用,还可以作为云上对象存储服务的网关层,无缝对接到 Amazon S3 等。
基础概念
存储相关的概念
- 一个对象存储在一个 Set
- 一个集群划分为多个 Set
- 一个 Set 中的 Drive 尽可能分布在不同的节点上
- 一个 Set 包含的 Drive 数量是固定的,默认由系统根据集群规模自动计算
概念名称 | 对应含义解释 |
---|---|
Object | 存储到 MinIO 的基本对象,如文件、图片、日志等 |
Bucket | 用来存储 Object 的逻辑空间。每个 Bucket 之间的数据是相互隔离的 |
Drive | 部署 MinIO 时设置的磁盘,MinIO 中所有的对象数据都会存储到 Drive |
Set | 一组 Drive 的集合,MinIO 会自动根据 Drive 数量,将若干个 Drive 划分为多个 Set |
资源规划
关于容量计算:总空间只是数据磁盘的数量 * 每个磁盘的空间
minIO 以 N/2 数据和 N/2 奇偶校验磁盘的默认配置启动。因此,在默认配置中,假设您有 8 个磁盘,每个磁盘为 1 TiB,那么总可用空间为 数据盘数量 [4] * 每盘空间 [1 TiB] = 4 TiB
。
部署 - Docker 单机版
单机版本无法使用版本控制、对象锁定和存储桶复制等功能。如果需要使用,请部署带有纠删码的分布式 minIO。 对于一般的中小企业,Docker 单机版部署已经可以满足日常使用。
- 9000 端口为自带的 Web 网页(可通过该端口 + 存储的文件对象实现访问);
- 9001 端口为使用 API 和客户端的控制台;
docker run --name=minio -d \
-p 9000:9000 \
-p 9001:9001 \
-v /usr/local/wlhiot/mount/minio/data:/data \
-e "MINIO_ROOT_USER=master" \
-e "MINIO_ROOT_PASSWORD=wlh@2021" \
quay.io/minio/minio \
server /data --console-address ":9001"
部署 - Docker-Compose
services:
minio:
image: docker.io/minio/minio:latest
container_name: minio
restart: unless-stopped # 默认可使用 always
labels:
- "traefik.enable=true"
- "traefik.http.routers.minio-router.rule=Host(`minio.localhost`)"
- "traefik.http.services.minio-service.loadbalancer.server.port=9001"
ports:
- "9000:9000" # API端口
- "9001:9001" # 控制台端口
environment:
MINIO_ROOT_USER: [USER]
MINIO_ROOT_PASSWORD: [PASSWORD]
volumes:
- dhr2333-minio-data:/data
networks:
- shared-network
command: server /data --console-address ":9001"
volumes:
dhr2333-minio-data:
name: dhr2333-minio-data
external: true
networks:
shared-network:
external: true
部署 - Kubernetes
cat minio-pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: minio-data
namespace: basic
spec:
accessModes:
- ReadWriteMany
storageClassName: "general-data"
resources:
requests:
storage: 10Gi
cat minio-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio
namespace: basic
spec:
replicas: 1
selector:
matchLabels:
name: minio
template:
metadata:
name: minio
labels:
name: minio
spec:
containers:
- name: minio
image: 192.168.254.29:8080/library/minio:latest # 使用minio/minio镜像
args:
- server
- /data
- --console-address
- ":9001"
env:
- name: MINIO_ROOT_USER
value: master
- name: MINIO_ROOT_PASSWORD
value: wlh@2021
ports:
- containerPort: 9000
- containerPort: 9001
volumeMounts:
- name: minio-data
mountPath: /data
volumes:
- name: minio-data
persistentVolumeClaim:
claimName: minio-data
---
apiVersion: v1
kind: Service
metadata:
name: minio
namespace: basic
spec:
type: NodePort
ports:
- port: 9000
targetPort: 9000
nodePort: 30004
name: minio-9000
- port: 9001
targetPort: 9001
nodePort: 30009
name: minio-9001
selector:
name: minio
使用
使用 Python 对 minIO 进行操作(通过代码创建 bucket,将文件上传至 minIO )
from minio import Minio
from minio.error import S3Error
def main():
# Create a client with the MinIO server playground, its access key
# and secret key.
client = Minio(
"192.168.254.23:9000", # 服务地址
secure=False,
access_key="root", # docker单机部署的账号
secret_key="wlh@2022", # 密码
)
# Make 'poc' bucket if not exist.
found = client.bucket_exists("poc")
if not found:
client.make_bucket("poc")
else:
print("Bucket 'poc' already exists")
# Upload 'file.uploader.py' as object name
# 'poc.py' to bucket 'poc'.
client.fput_object(
"poc", "Prometheus.py", "Prometheus.py",
)
print(
"'file.uploader.py' is successfully uploaded as "
"object 'poc.py' to bucket 'poc'."
)
if __name__ == "__main__":
try:
main()
except S3Error as exc:
print("error occurred.", exc)
实现效果:
通过 http://ip:port/bucket/filename 的形式访问,例如 192.168.254.23:9000/poc/poc.py 但无法使用目录清单 (nginx autoindex) 的方式访问目录。
集成 OpenLDAP
通过集成 OpenLDAP 可以实现配置指定用户的权限 (关于 OpenLDAP 也参考我另一篇文章 http://www.dhr2333.cn/category/openldap.html),具体配置如下:
完成配置修改后需要重启 minio 服务,重启后就无法通过原账号密码登录,此时已经集成完成。但是还有个问题,minio 默认不允许匿名用户登录,所以此时控制台任何账号都无法登录。
通过 mc 客户端,将 OpenLDAP 的用户赋予权限(consoleAdmin&readonly&readwrite 均可),完成后可正常登录。
mc admin policy set minio consoleAdmin user=cn=root,ou=product,ou=wlhiot,dc=wlhiot,dc=com # 赋予该用户管理员权限
mc admin policy set minio consoleAdmin group=ou=wlhiot,dc=wlhiot,dc=com # 赋予该组管理员权限
也附上我另一个软件(sonarqube)集成 OpenLDAP 的配置