分布式對象存儲minio

本教程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

多磁盤

磁盤需要保持一致

  1. 文件格式一致
  2. 容量一致
  3. 每個區使用偶數數量的磁盤,便于糾刪碼模式
  4. 每個區的磁盤數量需要一致,所以擴展后新的區和原始區的磁盤的數量、容量、格式都是一致的

擴展

官方文檔: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/Linux64-bit Intelhttp://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/Linux64-bit Intelhttp://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
MicrosoftWindows64-bit Intelhttp://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)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/45479.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/45479.shtml
英文地址,請注明出處:http://en.pswp.cn/web/45479.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ubuntu服務器部署vue springboot前后端分離項目

上傳構建好的vue前端文件 vscode構建vue項目&#xff0c;會生成dist目錄 npm run build在服務器root目錄新建/projects/www目錄&#xff0c;把dist目錄下的所有文件&#xff0c;上傳到此目錄中 上傳ssl證書 上傳ssl證書到/projects目錄中 配置nginx 編輯 /etc/nginx/site…

微服務邊界守衛:Eureka中服務隔離策略的實現

微服務邊界守衛&#xff1a;Eureka中服務隔離策略的實現 在微服務架構中&#xff0c;服務隔離是一項關鍵策略&#xff0c;用于確保服務之間的故障不會相互影響&#xff0c;同時提供更加安全和穩定的運行環境。Eureka作為Netflix開源的服務發現框架&#xff0c;提供了一些機制來…

Java 網絡協議面試題答案整理,最新面試題

TCP和UDP的主要區別是什么? TCP(傳輸控制協議)和UDP(用戶數據報協議)的主要區別在于TCP是面向連接的協議,而UDP是無連接的協議。這導致了它們在數據傳輸方式、可靠性、速度和使用場景方面的不同。 1、連接方式: TCP是面向連接的協議,數據傳輸前需要三次握手建立連接。U…

區塊鏈與云計算的融合:新時代數據安全的挑戰與機遇

隨著信息技術的迅猛發展&#xff0c;云計算和區塊鏈技術作為兩大前沿技術在各自領域內展示出了巨大的潛力。而它們的結合&#xff0c;即區塊鏈與云計算的融合&#xff0c;正在成為數據安全領域的新趨勢。本文將探討這一融合對數據安全帶來的挑戰和機遇&#xff0c;以及其在企業…

平替ChatGPT的多模態智能體來了

在人工智能領域&#xff0c;多模態技術的融合與應用已成為推動技術革新的關鍵。今天&#xff0c;我們用智匠AI實現了完全由國產模型驅動的多模態智能體——智醬v0.1.0&#xff0c;它不僅能夠媲美ChatGPT的多模態能力&#xff0c;更在聯網搜索、圖片識別、畫圖及圖表生成等方面展…

redis原理之底層數據結構(二)-壓縮列表

1.緒論 壓縮列表是redis最底層的結構之一&#xff0c;比如redis中的hash&#xff0c;list在某些場景下使用的都是壓縮列表。接下來就讓我們看看壓縮列表結構究竟是怎樣的。 2.ziplist 2.1 ziplist的組成 在低版本中壓縮列表是由ziplist實現的&#xff0c;我們來看看他的結構…

Stable Diffusion AI繪畫全攻略:從理論到實戰,解鎖創意圖畫的魔法之門

在科技的飛速發展中&#xff0c;Stable Diffusion AI繪畫技術為藝術創作帶來了前所未有的革命性變化。這項技術由CompVis、Stability AI和LAION聯合研發&#xff0c;通過深度學習模型&#xff0c;將文字描述轉化為生動的藝術作品&#xff0c;極大地拓寬了創意與想象的邊界。本文…

大數據面試SQL題-筆記01【運算符、條件查詢、語法順序、表連接】

大數據面試SQL題復習思路一網打盡&#xff01;(文檔見評論區)_嗶哩嗶哩_bilibiliHive SQL 大廠必考常用窗口函數及相關面試題 大數據面試SQL題-筆記01【運算符、條件查詢、語法順序、表連接】大數據面試SQL題-筆記02【...】 目錄 01、力扣網-sql題 1、高頻SQL50題&#xff08…

TCP、UDP、TCP與UDP的區別及聯系

目錄 TCP和UDP區別1.連接2.交互個數3.可靠性4.傳輸方式5.適用場景 怎么實現一個可靠的UDP傳輸TCP詳解UDP詳解 TCP和UDP區別 1.連接 TCP 面向連接的&#xff0c;傳輸數據前先要建立連接。 UDP 是不需要連接&#xff0c;即刻傳輸數據。 2.交互個數 TCP 是一對一通信。 UDP 支…

數據結構——hash(hashmap源碼探究)

hash是什么&#xff1f; hash也稱為散列&#xff0c;就是把任意長度的輸入&#xff0c;通過散列算法&#xff0c;變成固定長度的輸出&#xff0c;這個輸出值就是散列值。 舉例來說明一下什么是hash&#xff1a; 假設我們要把1~12存入到一個大小是5的hash表中&#xff0c;我們…

礦產資源潛力預測不確定性評價

研究目的&#xff1a; 不確定性評估&#xff1a; 到底什么叫不確定性&#xff0c;簡單來說就是某區域內的礦產資源量&#xff0c;并不確定到底有多少&#xff0c;你需要給出一個評估或者分布。 研究方法&#xff1a; 1.以模糊集來表示某些量&#xff1a; 關于什么是模糊集&am…

信通院全景圖發布 比瓴科技領跑軟件供應鏈安全,多領域覆蓋數字安全服務

近日&#xff0c;中國信息通信研究院在2024全球數字經濟大會—數字安全生態建設專題論壇正式發布首期《數字安全護航技術能力全景圖》&#xff08;以下簡稱全景圖&#xff09;。 比瓴科技入選軟件供應鏈安全賽道“開發流程安全管控、交互式安全測試、靜態安全測試、軟件成分分…

智慧水利:邁向水資源管理的新時代,結合物聯網、云計算等先進技術,闡述智慧水利解決方案在提升水災害防控能力、優化水資源配置中的關鍵作用

本文關鍵詞&#xff1a;智慧水利、智慧水利工程、智慧水利發展前景、智慧水利技術、智慧水利信息化系統、智慧水利解決方案、數字水利和智慧水利、數字水利工程、數字水利建設、數字水利概念、人水和協、智慧水庫、智慧水庫管理平臺、智慧水庫建設方案、智慧水庫解決方案、智慧…

數據分析——numpy教程

1.NumPy&#xff1a; 是Python的一個開源的數值計算庫。可以用來存儲和處理大型矩陣&#xff0c;比python自身的嵌套列表結構要高效&#xff0c;支持大量的維度數組與矩陣運算&#xff0c;此外也針對數組運算提供大量的數學函數庫&#xff0c;包括數學、邏輯、形狀操作、排序、…

前端數據加密,后端java解密

在前端對數據進行加密后&#xff0c;通常會使用一些加密算法和技術&#xff0c;如AES&#xff08;Advanced Encryption Standard&#xff09;進行數據加密。然后&#xff0c;將加密后的數據發送到后端。后端接收到加密數據后&#xff0c;使用Java語言進行解密。 以下是一個簡單…

MKS電源管理軟件OPTIMA RPDG DCG系列RF Elit600系列

MKS電源管理軟件OPTIMA RPDG DCG系列RF Elit600系列

數據結構——考研筆記(三)線性表之單鏈表

文章目錄 2.3 單鏈表2.3.1 知識總覽2.3.2 什么是單鏈表2.3.3 不帶頭結點的單鏈表2.3.4 帶頭結點的單鏈表2.3.5 不帶頭結點 VS 帶頭結點2.3.6 知識回顧與重要考點2.3.7 單鏈表的插入和刪除2.3.7.1 按位序插入&#xff08;帶頭結點&#xff09;2.3.7.2 按位序插入&#xff08;不帶…

spring事務 @Transactional

文章目錄 1. 簡介1.1 什么是事務1.2 什么是Spring事務管理1.3 Transactional注解的作用 2. Transactional注解的使用2.1 如何在Spring中使用Transactional2.2 Transactional的屬性配置 3. Transactional的工作原理3.1 Spring如何管理事務3.2 Transactional的底層實現 4. Transa…

數學建模·灰色關聯度

灰色關聯分析 基本原理 灰色關聯分析可以確定一個系統中哪些因素是主要因素&#xff0c;哪些是次要因素&#xff1b; 灰色關聯分析也可以用于綜合評價&#xff0c;但是由于數據預處理的方式不同&#xff0c;導致結果 有較大出入 &#xff0c;故一般不采用 具體步驟 數據預處理…

wps批量刪除空白單元格

目錄 原始數據1.按ctrlg鍵2.選擇“空值”&#xff0c;點擊“定位”3. 右擊&#xff0c;刪除單元格修改后的數據 原始數據 1.按ctrlg鍵 2.選擇“空值”&#xff0c;點擊“定位” 如圖所示&#xff0c;空值已被選中 3. 右擊&#xff0c;刪除單元格 修改后的數據