本教程minio 版本:RELEASE.2021-07-*及以上
1. 分布式文件系統應用場景
互聯網海量非結構化數據的存儲需求
- 電商網站:海量商品圖片
- 視頻網站:海量視頻文件
- 網盤 : 海量文件
- 社交網站:海量圖片
1.1 Minio介紹
MinIO 是一個基于Apache License v2.0開源協議的對象存儲服務。它兼容亞馬遜S3云存儲服務接口,非常適合于存儲大容量非結構化的數據,例如圖片、視頻、日志文件、備份數據和容器/虛擬機鏡像等,而一個對象文件可以是任意大小,從幾kb到最大5T不等。
MinIO是一個非常輕量的服務,可以很簡單的和其他應用的結合,類似 NodeJS, Redis 或者 MySQL。
官網:https://min.io/?http://www.minio.org.cn/
對象存儲服務(Object Storage Service,OSS)是一種海量、安全、低成本、高可靠的云存儲服務,適合存放任意類型的文件。容量和處理能力彈性擴展,多種存儲類型供選擇,全面優化存儲成本。
對于中小型企業,如果不選擇存儲上云,那么 Minio 是個不錯的選擇,麻雀雖小,五臟俱全。當然Minio 除了直接作為對象存儲使用,還可以作為云上對象存儲服務的網關層,無縫對接到 Amazon S3、MicroSoft Azure。
在中國:阿里巴巴、騰訊、百度、中國聯通、華為、中國移動等等9000多家企業也都在使用MinIO產品。
Minio優點
- 部署簡單: 一個single二進制文件即是一切,還可支持各種平臺。
- minio支持海量存儲,可按zone擴展(原zone不受任何影響),支持單個對象最大5TB;
- 兼容Amazon S3接口,充分考慮開發人員的需求和體驗;
- 低冗余且磁盤損壞高容忍,標準且最高的數據冗余系數為2(即存儲一個1M的數據對象,實際占用磁盤空間為2M)。但在任意n/2塊disk損壞的情況下依然可以讀出數據(n為一個糾刪碼集合(Erasure Coding Set)中的disk數量)。并且這種損壞恢復是基于單個對象的,而不是基于整個存儲卷的。
- 讀寫性能優異
1.2 MinIO的基礎概念
- Object:存儲到 Minio 的基本對象,如文件、字節流,Anything...
- Bucket:用來存儲 Object 的邏輯空間。每個 Bucket 之間的數據是相互隔離的。對于客戶端而言,就相當于一個存放文件的頂層文件夾。
- Drive:即存儲數據的磁盤,在 MinIO 啟動時,以參數的方式傳入。Minio 中所有的對象數據都會存儲在 Drive 里。
- Set?:即一組 Drive 的集合,分布式部署根據集群規模自動劃分一個或多個 Set ,每個 Set 中的Drive 分布在不同位置。一個對象存儲在一個 Set 上。(For example: {1...64} is divided into 4 sets each of size 16.)
- 一個對象存儲在一個Set上
- 一個集群劃分為多個Set
- 一個Set包含的Drive數量是固定的,默認由系統根據集群規模自動計算得出
- 一個SET中的Drive盡可能分布在不同的節點上
1.3 糾刪碼EC(Erasure Code)
MinIO 使用糾刪碼機制來保證高可靠性,使用 highwayhash 來處理數據損壞( Bit Rot Protection )。
關于糾刪碼,簡單來說就是可以通過數學計算,把丟失的數據進行還原,它可以將n份原始數據,增加m份數據,并能通過n+m份中的任意n份數據,還原為原始數據。即如果有任意小于等于m份的數據失效,仍然能通過剩下的數據還原出來。
1.4 存儲形式
文件對象上傳到 MinIO ,會在對應的數據存儲磁盤中,以 Bucket 名稱為目錄,文件名稱為下一級目錄,文件名下是 part.1 和 xl.meta(老版本,最新版本如下圖),前者是編碼數據塊及檢驗塊,后者是元數據文件。
linux 在指定目錄下執行?tree?命令(yum install tree 先安裝下)
1.5 存儲方案
2. Minio環境搭建
官方文檔:https://docs.min.io/docs/
中文文檔:http://docs.minio.org.cn/docs/?(沒有及時更新,容易被坑)
minio支持多種server啟動模式:
2.0 官方推薦
磁盤文件格式
官方文檔推薦磁盤文件格式使用?xfs
多磁盤
磁盤需要保持一致
- 文件格式一致
- 容量一致
- 每個區使用偶數數量的磁盤,便于糾刪碼模式
- 每個區的磁盤數量需要一致,所以擴展后新的區和原始區的磁盤的數量、容量、格式都是一致的
擴展
官方文檔:Expand a Distributed MinIO Deployment — MinIO Object Storage for Linux
中文文檔:擴展一個分布式MinIO部署 — MinIO中文文檔 | MinIO Linux中文文檔
2.1 單機部署
minio server的standalone模式,即要管理的磁盤都在host本地。該啟動模式一般僅用于實驗環境、測試環境的驗證和學習使用。在standalone模式下,還可以分為non-erasure code mode和erasure code mode。
non-erasure code mode
在此啟動模式下,對于每一份對象數據,minio直接在data下面存儲這份數據,不會建立副本,也不會啟用糾刪碼機制。因此,這種模式無論是服務實例還是磁盤都是“單點”,無任何高可用保障,磁盤損壞就表示數據丟失。
erasure code mode
此模式為minio server實例傳入多個本地磁盤參數。一旦遇到多于一個磁盤參數,minio server會自動啟用erasure code mode。erasure code對磁盤的個數是有要求的,如不滿足要求,實例啟動將失敗。 erasure code啟用后,要求傳給minio server的endpoint(standalone模式下,即本地磁盤上的目錄)至少為4個。
基于 centos
操作系統 | CPU 架構 | 地址 |
GNU/Linux | 64-bit Intel | http://dl.minio.org.cn/server/minio/release/linux-amd64/minio |
wget -q http://dl.minio.org.cn/server/minio/release/linux-amd64/minio
chmod +x minio
#啟動minio server服務,指定數據存儲目錄/mnt/data
./minio server /mnt/data
默認用戶名密碼minioadmin:minioadmin,修改默認用戶名密碼可以使用:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
默認的配置目錄是 ${HOME}/.minio (比如root 用戶則配置目錄在 /root/.minio),可以通過--config-dir命令自定義配置目錄:
./minio server --config-dir /mnt/config /mnt/data
控制臺監聽端口是動態生成的,可以通過--console-address ":port"指定靜態端口
./minio server --console-address ":50000" /mnt/data
訪問minio控制臺:?http://192.168.3.14:50000/dashboard
基于docker
docker run -d -p 9000:9000 --name minio \ -v /mnt/data:/data \ -v /mnt/config:/root/.minio \ minio/minio server /data
存在問題: 瀏覽器無法訪問minio控制臺,因為沒有對外暴露控制臺端口
對外暴露minio控制臺的端口,通過--console-address ":50000"指定控制臺端口為靜態端口
docker run -p 9000:9000 -p 50000:50000 --name minio \ -v /mnt/data:/data \ -v /mnt/config:/root/.minio \ minio/minio server --console-address ":50000" /data
MinIO自定義用戶名密碼
docker run -d -p 9000:9000 -p 50000:50000 --name minio \ -e "MINIO_ROOT_USER=admin" \ -e "MINIO_ROOT_PASSWORD=12345678" \ -v /mnt/data:/data \ -v /mnt/config:/root/.minio \ minio/minio server --console-address ":50000" /data
訪問minio控制臺:?http://192.168.3.14:50000/
基于 docker-compose
docker-compose.yml
version: '3.5'services:minio:container_name: miniorestart: alwaysimage: minio/minioports:- "9000:9000"- "50000:50000"environment:MINIO_ROOT_USER: adminMINIO_ROOT_PASSWORD: yh@miniIOtestvolumes:- ./data:/data- ./config:/root/.miniocommand: server --console-address ":50000" /data
單機擴容
單機也是可以參考集群的方案來進行擴容,核心就是再添加一個區。
但是單節點擴展后隨著數據量的增加對于性能必然時會有影響的(我猜的),畢竟它不像分布式的擴展是由新節點來管理擴展容量的。
如果是那種一開始磁盤不夠大導致容量滿了,后續倒是可以進行單機擴容的。
docker-compose.yml
version: '3.7'# Settings and configurations that are common for all containers
x-minio-common: &minio-commonimage: quay.io/minio/minio:RELEASE.2024-03-15T01-07-19Zcommand: server --console-address ":50000" http://minio1/data{1...2} # http://minio1/data{3...4}ports:- "9000:9000"- "50000:50000"
# environment:# MINIO_ROOT_USER: minioadmin# MINIO_ROOT_PASSWORD: minioadminhealthcheck:test: ["CMD", "mc", "ready", "local"]interval: 5stimeout: 5sretries: 5# starts 4 docker containers running minio server instances.
# using nginx reverse proxy, load balancing, you can access
# it through port 9000.
services:minio1:<<: *minio-commonhostname: minio1volumes:- ./data-test2-1:/data1- ./data-test2-2:/data2#- ./data-test2-3:/data3#- ./data-test2-4:/data4- ./config-test2:/root/.minio
docker-compse 啟動容器 -> 訪問后臺 -> 添加 bucket -> 上傳文件
docker-compose down 關閉容器 -> 將 docker-compose.yml 中的?http://minio1/data{3...4} 和 volumes 中的 data3 和 data4 放出來 -> 重新啟動容器 -> 訪問后臺 -> 上傳文件
可以看到新加的磁盤 data3和data4(一個區) 中的文件和 data1\data2(另一個區) 是不同的,說明實現了擴容
2.2 minio糾刪碼模式
Minio使用糾刪碼 erasure code 和校驗和 checksum 來保護數據免受硬件故障和無聲數據損壞。 即便您丟失一半數量(N/2)的硬盤,您仍然可以恢復數據。
糾刪碼是一種恢復丟失和損壞數據的數學算法, Minio采用Reed-Solomon code將對象拆分成N/2數據和N/2 奇偶校驗塊。 這就意味著如果是12塊盤,一個對象會被分成6個數據塊、6個奇偶校驗塊,你可以丟失任意6塊盤(不管其是存放的數據塊還是奇偶校驗塊),你仍可以從剩下的盤中的數據進行恢復。
DATA BLOCK:數據塊,針對的是對象,1個BLOCK 10M,當對象大小超過 10M 的時候就拆分存放在 DATABLOCK 中
上傳文件(小于1M、大于 1M),查看編碼文件的情況,可以看到當對象大于 1M 時才會有 part.1 這個編碼文件
使用Minio Docker鏡像,在8塊盤中啟動Minio服務:
docker run -d -p 9000:9000 -p 50000:50000 --name minio \-v /mnt/data1:/data1 \-v /mnt/data2:/data2 \-v /mnt/data3:/data3 \-v /mnt/data4:/data4 \-v /mnt/data5:/data5 \-v /mnt/data6:/data6 \-v /mnt/data7:/data7 \-v /mnt/data8:/data8 \minio/minio server /data{1...8} --console-address ":50000"
2.3 分布式集群部署
分布式 Minio 可以讓你將多塊硬盤(甚至在不同的機器上)組成一個對象存儲服務。由于硬盤分布在不同的節點上,分布式Minio避免了單點故障。
分布式存儲可靠性常用方法
分布式存儲,很關鍵的點在于數據的可靠性,即保證數據的完整,不丟失,不損壞。只有在可靠性實現的前提下,才有了追求一致性、高可用、高性能的基礎。而對于在存儲領域,一般對于保證數據可靠性的方法主要有兩類,一類是冗余法,一類是校驗法。
冗余
冗余法最簡單直接,即對存儲的數據進行副本備份,當數據出現丟失,損壞,即可使用備份內容進行恢復,而副本備份的多少,決定了數據可靠性的高低。這其中會有成本的考量,副本數據越多,數據越可靠,但需要的設備就越多,成本就越高。可靠性是允許丟失其中一份數據。當前已有很多分布式系統是采用此種方式實現,如 Hadoop 的文件系統(3個副本),Redis 的集群,MySQL 的主備模式等。
校驗
校驗法即通過校驗碼的數學計算的方式,對出現丟失、損壞的數據進行校驗、還原。注意,這里有兩個作用,一個校驗,通過對數據進行校驗和( checksum )進行計算,可以檢查數據是否完整,有無損壞或更改,在數據傳輸和保存時經常用到,如 TCP 協議;二是恢復還原,通過對數據結合校驗碼,通過數學計算,還原丟失或損壞的數據,可以在保證數據可靠的前提下,降低冗余,如單機硬盤存儲中的 RAID技術,糾刪碼(Erasure Code)技術等。MinIO 采用的就是糾刪碼技術。
分布式Minio優勢
數據保護
分布式Minio采用 糾刪碼來防范多個節點宕機和位衰減 bit rot 。
分布式Minio至少需要4個硬盤,使用分布式Minio自動引入了糾刪碼功能。
高可用
單機Minio服務存在單點故障,相反,如果是一個有N塊硬盤的分布式Minio,只要有N/2硬盤在線,你的數據就是安全(讀)的。不過你需要至少有N/2+1個硬盤來創建(寫)新的對象。
例如,一個16節點的Minio集群,每個節點16塊硬盤,就算8臺服務器宕機,這個集群仍然是可讀的,不過你需要9臺服務器才能寫數據。
一致性
Minio在分布式和單機模式下,所有讀寫操作都嚴格遵守read-after-write一致性模型。
運行分布式Minio
官方文檔:部署 MinIO:多節點多驅動器 — 適用于 Linux 的 MinIO 對象存儲
啟動一個分布式Minio實例,你只需要把硬盤位置做為參數傳給minio server命令即可,然后,你需要在所有其它節點運行同樣的命令。
- 分布式Minio里所有的節點需要有同樣的access秘鑰和secret秘鑰,這樣這些節點才能建立聯接。為了實現這個,你需要在執行minio server命令之前,先將access秘鑰和secret秘鑰export成環境變量。新版本使用MINIO_ROOT_USER&MINIO_ROOT_PASSWORD。
- 分布式Minio使用的磁盤里必須是干凈的,里面沒有數據。
- 下面示例里的IP僅供示例參考,你需要改成你真實用到的IP和文件夾路徑。
- 分布式Minio里的節點時間差不能超過3秒,你可以使用 NTP 來保證時間一致。
- 在Windows下運行分布式Minio處于實驗階段,請悠著點使用。
8個節點,每節點1塊盤
啟動分布式Minio實例,8個節點,每節點1塊盤,需要在8個節點上都運行下面的命令:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
# http://192.168.1.11/export1 這些是磁盤掛載路徑
minio server http://192.168.1.11/export1 http://192.168.1.12/export2 \http://192.168.1.13/export3 http://192.168.1.14/export4 \http://192.168.1.15/export5 http://192.168.1.16/export6 \http://192.168.1.17/export7 http://192.168.1.18/export8
4節點,每節點4塊盤
啟動分布式Minio實例,4節點,每節點4塊盤,需要在4個節點上都運行下面的命令
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
minio server http://192.168.1.11/export1 http://192.168.1.11/export2 \http://192.168.1.11/export3 http://192.168.1.11/export4 \http://192.168.1.12/export1 http://192.168.1.12/export2 \http://192.168.1.12/export3 http://192.168.1.12/export4 \http://192.168.1.13/export1 http://192.168.1.13/export2 \http://192.168.1.13/export3 http://192.168.1.13/export4 \http://192.168.1.14/export1 http://192.168.1.14/export2 \http://192.168.1.14/export3 http://192.168.1.14/export4
通過腳本方式啟動
#!/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
MINIO_HOME=/root
MINIO_HOST=192.168.0.105
for i in {01..04}; do# --address ":9001" 這個選項指定了MinIO服務器監聽的地址和端口(就是 api 的端口 - 原 9000)# http://${MINIO_HOST}:9001/mnt/export01 這塊是磁盤掛載路徑nohup ${MINIO_HOME}/minio server --address ":90${i}" --console-address ":500${i}" http://${MINIO_HOST}:9001/mnt/export01 http://${MINIO_HOST}:9002/mnt/export02 > ${MINIO_HOME}/minio-90${i}.log 2>&1 &
done
執行腳本后查看日志和進程
但是我這里因為都是在同一臺機器操作的原因,所以啟動報錯了:Unable to use the drive?http://192.168.0.105:9001/mnt/export1:?drive is part of root drive, will not be used,原因是:
minio 集群部署被強制性安裝在獨占的磁盤分區,不能在 root 根盤符下建立目錄
docker-compose 部署集群
要在Docker Compose上部署分布式MinIO,請下載?docker-compose.yaml?和?nginx.conf?到你當前的工作目錄。
我這里就用了單機來模擬集群部署,多機的話(還是 4節點2硬盤,加入現是2臺機器),docker-compose.yml 就得修改成只有2個minio 容器,http://minio{1...4}/data{1...2} 這塊也得修改,minio 是推薦使用 hostname 的方式的,添加 hosts 映射,具體還得測試怎么配(我這里就不去測試了)。
實際生產環境看情況到底要不要用 docker-compose 方式吧。
docker-compose.yml
version: '3.7'# Settings and configurations that are common for all containers
x-minio-common: &minio-commonimage: quay.io/minio/minio:RELEASE.2024-03-30T09-41-56Zcommand: server --console-address ":50000" http://minio{1...4}/data{1...2} # http://minio{5...8}/data{1...2} # minio5~8 用于分布式擴展測試 - 以區的方式進行擴展expose:- "9000"- "50000"# environment:# MINIO_ROOT_USER: minioadmin# MINIO_ROOT_PASSWORD: minioadminhealthcheck:test: ["CMD", "mc", "ready", "local"]interval: 5stimeout: 5sretries: 5# starts 4 docker containers running minio server instances.
# using nginx reverse proxy, load balancing, you can access
# it through port 9000.
services:minio1:<<: *minio-commonhostname: minio1volumes:- ./data1-1:/data1- ./data1-2:/data2minio2:<<: *minio-commonhostname: minio2volumes:- ./data2-1:/data1- ./data2-2:/data2minio3:<<: *minio-commonhostname: minio3volumes:- ./data3-1:/data1- ./data3-2:/data2minio4:<<: *minio-commonhostname: minio4volumes:- ./data4-1:/data1- ./data4-2:/data2# minio5 ~ minio8 是為了測試分布式擴展用的 #minio5:# <<: *minio-common# hostname: minio5# volumes:# - ./data5-1:/data1# - ./data5-2:/data2##minio6:# <<: *minio-common# hostname: minio6# volumes:# - ./data6-1:/data1# - ./data6-2:/data2##minio7:# <<: *minio-common# hostname: minio7# volumes:# - ./data7-1:/data1# - ./data7-2:/data2##minio8:# <<: *minio-common# hostname: minio8# volumes:# - ./data8-1:/data1# - ./data8-2:/data2nginx:image: nginx:1.19.2-alpinehostname: nginxvolumes:- ./nginx.conf:/etc/nginx/nginx.conf:roports:- "9000:9000"- "50000:50000"depends_on:- minio1- minio2- minio3- minio4# - minio5# - minio6# - minio7# - minio8## By default this config uses default local driver,
## For custom volumes replace with volume driver configuration.
# 磁盤掛載
#volumes:
# data1-1:
# data1-2:
# data2-1:
# data2-2:
# data3-1:
# data3-2:
# data4-1:
# data4-2:
nginx.conf 基于nginx 對集群進行 loadbalancer
user nginx;
worker_processes auto;error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;events {worker_connections 4096;
}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;keepalive_timeout 65;# include /etc/nginx/conf.d/*.conf;upstream minio {server minio1:9000;server minio2:9000;server minio3:9000;server minio4:9000;# server minio5:9000;# server minio6:9000;# server minio7:9000;# server minio8:9000;}upstream console {ip_hash;server minio1:50000;server minio2:50000;server minio3:50000;server minio4:50000;# server minio5:50000;# server minio6:50000;# server minio7:50000;# server minio8:50000;}server {listen 9000;listen [::]:9000;server_name localhost;# To allow special characters in headersignore_invalid_headers off;# Allow any size file to be uploaded.# Set to a value such as 1000m; to restrict file size to a specific valueclient_max_body_size 0;# To disable bufferingproxy_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.1proxy_http_version 1.1;proxy_set_header Connection "";chunked_transfer_encoding off;proxy_pass http://minio;}}server {listen 50000;listen [::]:50000;server_name localhost;# To allow special characters in headersignore_invalid_headers off;# Allow any size file to be uploaded.# Set to a value such as 1000m; to restrict file size to a specific valueclient_max_body_size 0;# To disable bufferingproxy_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_set_header X-NginX-Proxy true;# This is necessary to pass the correct IP to be hashedreal_ip_header X-Real-IP;proxy_connect_timeout 300;# To support websocketproxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";chunked_transfer_encoding off;proxy_pass http://console;}}
}
執行 docker-compose 命令輸出類似如下:
訪問控制臺查看 metrics 信息
測試上傳
可以看到上傳后,集群每個節點數據都是一致的
擴展現有的分布式集群
例如我們是通過區的方式啟動MinIO集群,命令行如下:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
minio server http://host{1...32}/export{1...32}
MinIO支持通過命令,指定新的集群來擴展現有集群(糾刪碼模式),命令行如下:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
# 推薦使用 go 的這種擴展方式的寫法
# 問題:http://ip:port/export1 這種寫死 ip 的方式,擴展時再將新的ip:port/export 加進來能實現擴展嗎?? ===> 待測試
minio server http://host{1...32}/export{1...32}http://host{33...64}/export{1...32}
現在整個集群就擴展了1024個磁盤,總磁盤變為2048個,新的對象上傳請求會自動分配到最少使用的集群上。通過以上擴展策略,您就可以按需擴展您的集群。重新配置后重啟集群,會立即在集群中生效,并對現有集群無影響。如上命令中,我們可以把原來的集群看做一個區,新增集群看做另一個區,新對象按每個區域中的可用空間比例放置在區域中。在每個區域內,基于確定性哈希算法確定位置。
說明: 您添加的每個區域必須具有與原始區域相同的磁盤數量(糾刪碼集)大小,以便維持相同的數據冗余SLA。 例如,第一個區有8個磁盤,您可以將集群擴展為16個、32個或1024個磁盤的區域,您只需確保部署的SLA是原始區域的倍數即可。
docker-compose 中擴展
將上面的 docker-compose.yml 和 nginx.conf 的 minio5~minio8 放開,重新啟動。
訪問控制臺,查看 metric 信息:
測試上傳
我們可以看到,新添加的集群(區)和舊的集群數據是不同的(合起來組成全部數據),新上傳的對象會優先往空閑空間較多的集群添加
2.4 minio 客戶端使用
MinIO Client (mc)為ls,cat,cp,mirror,diff,find等UNIX命令提供了一種替代方案。它支持文件系統和兼容Amazon S3的云存儲服務(AWS Signature v2和v4)。
ls 列出文件和文件夾。
mb 創建一個存儲桶或一個文件夾。
cat 顯示文件和對象內容。
pipe 將一個STDIN重定向到一個對象或者文件或者STDOUT。
share 生成用于共享的URL。
cp 拷貝文件和對象。
mirror 給存儲桶和文件夾做鏡像。
find 基于參數查找文件。
diff 對兩個文件夾或者存儲桶比較差異。
rm 刪除文件和對象。
events 管理對象通知。
watch 監視文件和對象的事件。
policy 管理訪問策略。
config 管理mc配置文件。
update 檢查軟件更新。
version 輸出版本信息。
部署客戶端mc
平臺 | CPU架構 | URL |
GNU/Linux | 64-bit Intel | http://dl.minio.org.cn/client/mc/release/linux-amd64/mc |
wget http://dl.minio.org.cn/client/mc/release/linux-amd64/mc
chmod +x mc
./mc --help
mv mc /usr/local/sbin/
平臺 | CPU架構 | URL |
MicrosoftWindows | 64-bit Intel | http://dl.minio.org.cn/client/mc/release/windows-amd64/mc.exe |
配置mc
mc 將所有的配置信息都存儲在 ~/.mc/config.json 文件中
# 查詢mc host配置
mc config host ls
# 添加minio服務
# 上面的集群模式由 nginx 進行負載均衡,所以這里的 url 是要用 nginx 的 url
mc config host add minio-server http://192.168.0.105:9000 admin 12345678
# 刪除host
mc config host remove minio-server
mc命令使用
ls - 列出存儲桶和對象 | mb - 創建存儲桶 | cat - 合并對象 |
cp - 拷貝對象 | rm - 刪除對象 | pipe - Pipe到一個對象 |
share - 共享 | mirror - 存儲桶鏡像 | find - 查找文件和對象 |
diff - 比較存儲桶差異 | policy - 給存儲桶或前綴設置訪問策略(已改為 anonymous) | |
config - 管理配置文件(官方文檔沒找到 mc config --help 查看使用) | watch - 事件監聽 | event - 管理存儲桶事件 |
update - 管理軟件更新 | version - 顯示版本信息 |
上傳下載
# 查詢minio服務上的所有buckets(文件和文件夾)
mc ls minio-server
# 下載文件
mc cp minio-server/tulingmall/fox/fox.jpg /tmp/
#刪除文件
mc rm minio-server/tulingmall/fox/fox.jpg
#上傳文件
mc cp zookeeper.out minio-server/tulingmall/
# 批量上傳(目錄下的所有子目錄和文件都會上傳上去)
mc cp --recursive /your_dir/ minio-server-name/bucketName
Bucket管理
# 創建bucket
mc mb minio-server/bucket01
# 刪除bucket
mc rb minio-server/bucket02
# bucket不為空,可以強制刪除 慎用
mc rb --force minio-server/bucket01
# 查詢bucket03磁盤使用情況
mc du minio-server/bucket03
mc admin使用
MinIO Client(mc)提供了“ admin”子命令來對您的MinIO部署執行管理任務。
service 服務重啟并停止所有MinIO服務器
update 更新更新所有MinIO服務器
info 信息顯示MinIO服務器信息
user 用戶管理用戶
group 小組管理小組
policy MinIO服務器中定義的策略管理策略
config 配置管理MinIO服務器配置
heal 修復MinIO服務器上的磁盤,存儲桶和對象
profile 概要文件生成概要文件數據以進行調試
top 頂部提供MinIO的頂部統計信息
trace 跟蹤顯示MinIO服務器的http跟蹤
console 控制臺顯示MinIO服務器的控制臺日志
prometheus Prometheus管理Prometheus配置
kms kms執行KMS管理操作mc admin user --help
#新建用戶
mc admin user add minio-server fox
mc admin user add minio-server fox02 12345678
#查看用戶
mc admin user list minio-server
#禁用用戶
mc admin user disable minio-server fox02
#啟用用戶
mc admin user disable minio-server fox02
#查看用戶信息
mc admin user info minio-server fox
#刪除用戶
mc admin user remove minio-server fox02
策略管理
policy命令,用于添加,刪除,列出策略,獲取有關策略的信息并為MinIO服務器上的用戶設置策略。
mc admin policy --help
#列出MinIO上的所有固定策略
mc admin policy list minio-server
# 查看plicy信息
mc admin policy info minio-server readwrite
控制臺查看每個 bucket 的訪問策略
查看每個策略的規則
添加新的策略
如果這個策略的 json 不知道怎么寫的話讓 ChatGpt 來寫
編寫策略文件:/root/tulingmall.json
{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": ["s3:GetBucketLocation","s3:GetObject"],"Resource": ["arn:aws:s3:::tulingmall"]},{"Effect": "Allow","Action": ["s3:*"],"Resource": ["arn:aws:s3:::tulingmall/*"]}]
}
將 tulingmall.json 添加到策略數據庫
# 添加新的策略
# add 已過期 mc admin policy add minio-server tulingmall-admin /root/tulingmall.json
mc admin policy create minio-server tulingmall-admin /root/tulingmall.json
mc admin policy list minio-server
新建用戶并賦予 tulingmall-admin 策略
mc admin user add minio-server world 12345678
# 設置用戶的訪問策略
# set 命令已過期 --> attach mc admin policy set minio-server tulingmall-admin user=fox03
# 指定 user 也過期了 -> --user
# 最新命令可以去官網查看
mc admin policy attach minio-server tulingmall-admin --user world
測試:world/12345678 登錄minio控制臺http://192.168.3.14:50000/,只能操作tulingmall的bucket
3. springboot 整合 minio
MinIO Java Client SDK提供簡單的API來訪問任何與Amazon S3兼容的對象存儲服務。
官方demo:?https://github.com/minio/minio-java
官方文檔:https://docs.min.io/docs/java-client-api-reference.htm
3.1 引入依賴
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.3.0</version>
</dependency>
<dependency><groupId>me.tongfei</groupId><artifactId>progressbar</artifactId><version>0.5.3</version>
</dependency>
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.8.1</version>
</dependency>
3.1.1 MinIO依賴沖突問題
8.3.x 會有依賴沖突的問題
An attempt was made to call a method that does not exist. The attempt was made from the following location:io.minio.S3Base.<clinit>(S3Base.java:98)The following method did not exist:okhttp3.RequestBody.create([BLokhttp3/MediaType;)Lokhttp3/RequestBody;The calling method's class, io.minio.S3Base, was loaded from the following location:jar:file:/D:/Soft/apache-maven-3.8.4/repository/io/minio/minio/8.3.7/minio-8.3.7.jar!/io/minio/S3Base.classThe called method's class, okhttp3.RequestBody, is available from the following locations:jar:file:/D:/Soft/apache-maven-3.8.4/repository/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar!/okhttp3/RequestBody.class
原因
spring-boot 默認引入了 okhttp3依賴,兩者版本不一致導致有些方法的缺失或不一致
解決
1. 在父工程pom.xml里的properties中指定 okhttp3 版本號?(不知道為啥我這樣寫了沒用)
<!--父pom-->
<properties><!-- 覆蓋SpringBoot中okhttp3的舊版本聲明,解決MinIO 8.3.x的依賴沖突 --><okhttp3.version>4.8.1</okhttp3.version>
</properties
2. 可以的話修改 spring-boot 版本(不推薦)
3. 修改 minio 版本為 8.2.x?(方案1 不行的話就用這個)
3.2 minio 配置
3.2.1 配置類
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
@ConditionalOnProperty(value = "oss.name", havingValue = "minio")
public class MinioConfiguration {@Autowiredprivate MinioProperties ossProperties;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(ossProperties.getEndpoint()).credentials(ossProperties.getAccessKey(), ossProperties.getSecretKey())// 當 minio server 使用了 https,那么將該代碼放出來,不然會報 ssl trust 相關的錯誤哦// .httpClient(getUnsafeOkHttpClient()).build();}public static OkHttpClient getUnsafeOkHttpClient() {return new OkHttpClient.Builder().readTimeout(60, TimeUnit.SECONDS).connectTimeout(60, TimeUnit.SECONDS).sslSocketFactory(getSSLSocketFactory(), getX509TrustManager()).hostnameVerifier(getHostnameVerifier()).build();}public static SSLSocketFactory getSSLSocketFactory() {try {SSLContext sslContext = SSLContext.getInstance("SSL");sslContext.init(null, getTrustManager(), new java.security.SecureRandom());return sslContext.getSocketFactory();} catch (Exception e) {throw new RuntimeException(e);}}private static TrustManager[] getTrustManager() {return new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) {}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}}};}public static X509TrustManager getX509TrustManager() {X509TrustManager trustManager = null;try {TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init((KeyStore) null);TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));}trustManager = (X509TrustManager) trustManagers[0];} catch (Exception e) {e.printStackTrace();}return trustManager;}public static HostnameVerifier getHostnameVerifier() {return (s, sslSession) -> true;}
}
3.2.2 參數配置類
@Data
@ConfigurationProperties(prefix = MinioProperties.PREFIX)
public class MinioProperties {/*** 配置前綴*/public static final String PREFIX = "oss";/*** 對象存儲名稱*/private String name;/*** 對象存儲服務的URL*/private String endpoint;/*** Access key 賬戶ID*/private String accessKey;/*** Secret key 密碼*/private String secretKey;
}
3.2.3 yml 配置
oss:name: minioaccessKey: 123456secretKey: 123456endpoint: http://192.168.0.105:9000
3.3 封裝 minio 相關方法
public interface OssTemplate {/*** 存儲桶是否存在** @param bucketName 存儲桶名稱* @return boolean*/boolean bucketExists(String bucketName);/*** 獲取文件信息** @param objectName 存儲桶對象名稱* @param bucketName 存儲桶名稱* @return OssResponse*/OssResponse getOssInfo(String bucketName, String objectName);/*** 上傳文件** @param folderName 上傳的文件夾名稱* @param file 上傳的文件* @return OssResponse*/OssResponse upLoadFile(String bucketName, String folderName, MultipartFile file);/*** 刪除文件** @param objectName 存儲桶對象名稱* @param bucketName 存儲桶名稱*/boolean removeFile(String bucketName, String objectName);/*** 批量刪除文件** @param objectNames 存儲桶對象名稱集合*/boolean removeFiles(String bucketName, List<String> objectNames);/*** @Description: 下載文件* @Param response: 響應* @Param fileName: 文件名* @Param filePath: 文件路徑* @return: void*/void downloadFile(HttpServletResponse response, String bucketName, String objectName);/*** 獲取文件外鏈 - 默認過期時間為2小時** @param bucketName 存儲桶名稱* @param objectName 存儲桶對象名稱* @param expires 過期時間,-1 則時默認2小時* @return String*/String getPresignedObjectUrl(String bucketName, String objectName, int expires);
}
實現類
@Slf4j
@Component
public class MinioTemplate implements OssTemplate {/*** MinIO客戶端*/@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinioProperties minioProperties;@Overridepublic boolean bucketExists(String bucketName) {try {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());} catch (Exception e) {log.error("minio bucketExists Exception: ", e);}return false;}public void makeBucket(String bucketName) {try {if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());log.info("minio makeBucket success bucketName:{}", bucketName);}} catch (Exception e) {log.error("minio makeBucket Exception: ", e);}}@Overridepublic OssResponse getOssInfo(String bucketName, String objectName) {try {// 獲取對象信息StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());// 獲取文件流InputStream in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());Headers headers = stat.headers();// headers 轉 mapMap<String, List<String>> headersMap = headers.toMultimap();OssObjectResponse ossObjectResponse = new OssObjectResponse();ossObjectResponse.setEtag(stat.etag());ossObjectResponse.setSize(stat.size());ossObjectResponse.setLastModified(stat.lastModified().toInstant().toEpochMilli());ossObjectResponse.setContentType(stat.contentType());ossObjectResponse.setHeaders(headersMap);ossObjectResponse.setBucket(bucketName);ossObjectResponse.setRegion(stat.region());ossObjectResponse.setObject(objectName);ossObjectResponse.setInputStream(in);return ossObjectResponse;} catch (Exception e) {log.error("minio getOssInfo Exception:{}", e.getMessage());}return null;}@Overridepublic OssResponse upLoadFile(String bucketName, String folderName, MultipartFile multipartFile) {// TODO 校驗文件大小、文件類型、文件是否為空、bucket、最終文件名String fileName = multipartFile.getOriginalFilename();String suffix = fileName.substring(fileName.lastIndexOf("."));// 對象名String objectName = folderName + "/" + fileName;try {//文件上傳InputStream in = multipartFile.getInputStream();minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(in, multipartFile.getSize(), -1).contentType(multipartFile.getContentType()).build());in.close();} catch (Exception e) {log.error("minio upLoadFile Exception:{}", e);}OssUploadResponse response = new OssUploadResponse();// TODO 返回自己需要的數據response.setObjectName(objectName);response.setBucketName(bucketName);response.setFileName(fileName);response.setUrl(minioProperties.getEndpoint() + "/" + bucketName + "/" + objectName);return response;}@Overridepublic boolean removeFile(String bucketName, String objectName) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());log.info("minio removeFile success, fileName:{}", objectName);return true;} catch (Exception e) {log.error("minio removeFile fail, fileName:{}, Exception:{}", objectName, e.getMessage());}return false;}@Overridepublic boolean removeFiles(String bucketName, List<String> objectNames) {try {List<DeleteObject> list = objectNames.stream().map(DeleteObject::new).collect(Collectors.toList());/*** lazy - 不是立即刪除,而是異步刪除*/Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(list).build());log.info("minio removeFiles success, fileNames:{}", objectNames);return true;} catch (Exception e) {log.error("minio removeFiles fail, fileNames:{}, Exception:{}", objectNames, e.getMessage());}return false;}@Overridepublic void downloadFile(HttpServletResponse response, String bucketName, String objectName) {InputStream in = null;try {OssObjectResponse downloadObjectResponse = (OssObjectResponse) getOssInfo(bucketName, objectName);Assert.notNull(downloadObjectResponse, "文件下載獲取文件流失敗");in = downloadObjectResponse.getInputStream();response.setContentType(downloadObjectResponse.getContentType());response.setHeader("Content-Disposition", "attachment;filename=" +URLEncoder.encode(objectName, "UTF-8"));IOUtils.copy(in, response.getOutputStream());} catch (Exception e) {log.error("文件下載失敗" + e.getMessage(), e);} finally {if (in != null) {try {in.close();} catch (IOException e) {log.error("文件下載文件流關閉失敗" + e.getMessage());}}}}@Overridepublic String getPresignedObjectUrl(String bucketName, String objectName, int expires) {expires = expires == -1 ? 2 * 60 * 60 : expires;try {GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName).bucket(bucketName).expiry(expires).method(Method.GET).build();String url = minioClient.getPresignedObjectUrl(objectArgs);return URLDecoder.decode(url, "UTF-8");} catch (Exception e) {log.info("文件路徑獲取失敗" + e.getMessage());}return null;}
}
controller
@Api(tags = "文件oss服務")
@RestController
@RequestMapping("/oss")
@Slf4j
public class OssController {@Autowiredprivate OssTemplate ossTemplate;@PostMapping("/upload")@ApiOperation("上傳文件")@ApiImplicitParams({@ApiImplicitParam(name = "file", value = "文件", required = true, dataType = "MultipartFile"),@ApiImplicitParam(name = "bizDir", value = "業務目錄", required = false, dataType = "String"),@ApiImplicitParam(name = "bucketName", value = "bucket名稱", required = true, dataType = "String"),})public R<OssUploadResponse> upload(MultipartFile file,@RequestParam(required = false) String bizDir,@RequestParam(required = true) String bucketName) {OssUploadResponse uploadResponse = (OssUploadResponse) ossTemplate.upLoadFile(bucketName, bizDir, file);return R.ok(uploadResponse);}@GetMapping("/download")@ApiOperation("下載文件")public void download(HttpServletResponse response, String bucketName, String objectName) {ossTemplate.downloadFile(response, bucketName, objectName);}@GetMapping("/view/{bucketName}/**")@ApiOperation("預覽 - 主要用于桶,需要帶token")public void view(HttpServletResponse response, HttpServletRequest request, @PathVariable String bucketName) {InputStream in = null;String objectName = RequestUtils.extractPathFromPattern(request);try {OssObjectResponse objectResponse =(OssObjectResponse) ossTemplate.getOssInfo(bucketName, objectName);Assert.notNull(objectResponse, "獲取文件流失敗");in = objectResponse.getInputStream();response.setContentType(objectResponse.getContentType());// cache - 圖片瀏覽器緩存response.setDateHeader(LAST_MODIFIED, objectResponse.getLastModified());response.setHeader(ETAG, objectResponse.getEtag());IOUtils.copy(in, response.getOutputStream());} catch (Exception e) {log.error("文件流獲取失敗" + e.getMessage(), e);} finally {if (in != null) {try {in.close();} catch (IOException e) {log.error("文件流關閉失敗" + e.getMessage());}}}}@DeleteMapping("/removeObject")@ApiOperation("刪除文件")public R removeObject(String bucketName, String objectName) {ossTemplate.removeFile(bucketName, objectName);return R.ok();}@DeleteMapping("/removeBatch")@ApiOperation("批量刪除文件")public R removeBatch(String bucketName, String[] objectNames) {List<String> objectNameList = Arrays.asList(objectNames);ossTemplate.removeFiles(bucketName, objectNameList);return R.ok();}@GetMapping("/getPresignedObjectUrl")@ApiOperation("獲取文件外鏈")public R<String> getPresignedObjectUrl(String bucketName, String objectName) {String url = ossTemplate.getPresignedObjectUrl(bucketName, objectName, -1);return R.ok(url);}
}
4. 拓展
4.0 minio 接入 Prometheus 監控
Prometheus官網下載地址:Download | Prometheus
4.0.0 官方文檔參考
中文文檔:使用Prometheus進行監控和報警 — MinIO中文文檔 | MinIO Linux中文文檔
官方文檔:Monitoring and Alerting using Prometheus — MinIO Object Storage for Linux
4.0.1 安裝 Prometheus
1. 下載適合自己的版本
2. 將下載好的安裝包放到服務器上解壓,進入目錄修改配置文件?prometheus.yml
# scrape_configs 下增加如下配置
- job_name: "minio-job"metrics_path: /minio/v2/metrics/clusterscheme: httpstatic_configs:- targets: ['192.168.0.105:9000'] #更改為自己的minio地址
配置不知道怎么寫可以使用如下命令
mc admin prometheus generate minio-server
輸出類似如下:
scrape_configs:
- job_name: minio-job# bearer_token 如果不配置的話# 就要修改 minio 的docker-compose.yml 添加環境變量 MINIO_PROMETHEUS_AUTH_TYPE: public bearer_token: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJwcm9tZXRoZXVzIiwic3ViIjoibWluaW9hZG1pbiIsImV4cCI6NDg2NjU5ODU1MH0.I5nYSNEUiHaUPRm6OeF6VBXFh-PckHDzIzV2OaTiy46Lf5BkjdNrfRWjIIREyNeIJhMUMZZj8q967BYF3w904Qmetrics_path: /minio/v2/metrics/clusterscheme: httpstatic_configs:- targets: ['192.168.0.105:9000']
注意:bearer_token 如果不配置的話就要修改 minio 的docker-compose.yml,添加環境變量?MINIO_PROMETHEUS_AUTH_TYPE: public
3. 注冊系統管理服務
vim /etc/systemd/system/prometheus.service# 添加如下內容
# ExecStart 這塊改成自己的路徑
[Unit]
Description=Prometheus Monitoring
Wants=network-online.target
After=network-online.target[Service]
User=root
Group=root
Type=simple
ExecStart=/usr/local/prometheus-2.45.4/prometheus \--config.file=/usr/local/prometheus-2.45.4/prometheus.yml \--storage.tsdb.path=/usr/local/prometheus-2.45.4/data \--web.console.templates=/usr/local/prometheus-2.45.4/consoles \--web.console.libraries=/usr/local/prometheus-2.45.4/console_libraries
Restart=always[Install]
WantedBy=multi-user.target
4. 啟動并設置服務開機自動啟動
systemctl enable prometheus.service --now
# 查看狀態
systemctl status prometheus.service
5. 開放服務器端口,訪問 Prometheus?http://123.60.150.23:9090
如下圖:minio-job 就是我創建 minio 的監控 job
4.0.2 minio docker-compose.yml 配置文件修改
主要是添加了幾個環境變量?environment
- MINIO_PROMETHEUS_AUTH_TYPE
開放 PROMETHEUS 訪問,配置后 prometheus.yml 中 bearer_token 就可以不配置
- MINIO_PROMETHEUS_URL
PROMETHEUS 的地址
注意:http 不要漏寫了,不然控制臺訪問 metric 頁面的時候會報錯:Prometheus URL is unreachable
- MINIO_PROMETHEUS_JOB_ID
prometheus.yml 中配置的 job_name
version: '3.7'# Settings and configurations that are common for all containers
x-minio-common: &minio-commonimage: quay.io/minio/minio:RELEASE.2024-03-15T01-07-19Zcommand: server --console-address ":50000" http://minio1/data{1...2} http://minio1/data{3...4}ports:- "9000:9000"- "50000:50000"############ 在這里添加了 # MINIO_PROMETHEUS_AUTH_TYPE 開放 PROMETHEUS 訪問# MINIO_PROMETHEUS_URL 是 PROMETHEUS 的地址 - http 一定要寫不要會報錯environment:MINIO_PROMETHEUS_AUTH_TYPE: publicMINIO_PROMETHEUS_URL: http://192.168.0.105:9090MINIO_PROMETHEUS_JOB_ID: minio-job# MINIO_ROOT_USER: minioadmin# MINIO_ROOT_PASSWORD: minioadminhealthcheck:test: ["CMD", "mc", "ready", "local"]interval: 5stimeout: 5sretries: 5# starts 4 docker containers running minio server instances.
# using nginx reverse proxy, load balancing, you can access
# it through port 9000.
services:minio1:<<: *minio-commonhostname: minio1volumes:- ./data-test2-1:/data1- ./data-test2-2:/data2- ./data-test2-3:/data3- ./data-test2-4:/data4- ./config-test2:/root/.minio
重新啟動 minio 容器訪問控制臺,就能查看 metric 監控數據了
4.1 使用備份數據恢復 minio 服務
測試:config 和 data 復制到另外一個目錄下,然后修改 docker-compose.yml 的掛載路徑,重啟 minio,數據能正常訪問
4.2 數據遷移
4.2.1 本地文件遷移到 minio
1. 使用 minio 的 mc client 工具
文件批量遷移上傳到 minio
# --recursive 表示會將指定目錄下(不包括 yourDir)下的所有資源(包括目錄)都復制到 minio 對應的 bucket 下
mc cp --recursive ./yourDir minio-server-name/bucketName
# 將 2024 目錄下的所有資源都復制到 minio 的 bucket - service-wrapper 的historyTrack 目錄下
mc cp --recursive ./2024 minio-server-name/service-wrapper/historyTrack# 我的文件沒有后綴名所以上傳后的content-type 默認是application/octet-stream
# 使用 getObject 沒法讀取數據流,只能下載 -> 所以需要加上 content-type
# 如果需要指定 content-type 就增加 --attr="content-type=text/plain" (當然:content-type 根據自己的實際情況進行修改)
mc cp --attr="content-type=text/plain" --recursive ./yourDir minio-server-name/bucketName
文件遷移從 minio 遷移回本地
mc cp minio-server-name/bucketName 本地目錄
2. 使用 rclone 工具 - 自行百度吧
4.3 bucket 公桶\私桶
公桶:所有用戶都能訪問資源
私桶:獲取外鏈(有時間限制,url 會帶驗簽信息)-> 過期就需要重新生成外鏈
4.4 訪問策略問題
參考上面?2.4 minio 客戶端使用?-> 策略管理
說白了就是抄 minio 自帶的,有額外的需求的話就問 chatgpt阿里云等云存儲中的文件遷移到 minio
4.5 子網掩碼
/32
舉例:192.168.0.100
/32 表示這是一個單個的IP地址,沒有子網。換句話說,這個CIDR表示法指定了一個單一的IP地址,即 192.168.0.100,沒有包含任何其他IP地址
/24
- /24 表示子網掩碼的前24位是網絡部分,后8位是主機部分。
- 轉換為傳統的子網掩碼表示法,它等于 255.255.255.0。
- 在這個子網中,有?256 個可能的IP地址(從 192.168.0.0 到 192.168.0.255),但其中兩個(192.168.0.0 和 192.168.0.255)通常分別作為網絡地址和廣播地址,不可用于分配給主機。
- 因此,實際可用于主機的IP地址有 254 個(從 192.168.0.1 到 192.168.0.254)。