首頁

目前文章總數:254 篇

  

最後更新:2026年 10月 17日

0075. 架設檔案伺服器 - 高性能的物件存儲系統 - MinIO (開源、高速、免費)

日期:2024年 10月 12日

標籤: MinIO Asp.NET Core Windows Forms Docker Ubuntu

摘要:C# 學習筆記


範例所需: 1. Visual Studio 2022 Asp.net Core
      Ubuntu 主機 - 已安裝 Docker
範例檔案:本篇範例代碼
相關參考:MinIO GitHub 連結
解決問題:快速架設 MinIO 檔案伺服器、並且用 C# WinForm 實現上傳、下載功能
基本介紹:本篇分為四大部分。
第一部分:MinIO 簡介
第二部分:架設 MinIO & 基本配置
第三部分:上傳檔案到 MinIO - DEMO
第四部分:下載檔案從 MinIO - DEMO






第一部分:MinIO 簡介

Step 1: MinIO 介紹

官網首次登入頁面時,會看到以下內容:

The MinIO Enterprise Object Store:
Built for AI Data Infrastructure

The MinIO Enterprise Object Store is built for production environments where everything matters - performance, security,
scale and manageability. Cloud-native by design, it is ideal for large scale AI/ML infrastructure, modern data lakes and data lakehouses and
database workloads. It is software-defined and runs on any cloud - private, public, colo or edge.

大意是說:MinIO 企業級物件儲存專為生產環境設計,強調性能、安全性、擴展性和管理性。它是雲原生的。 適合大規模 AI/ML 基礎設施、現代數據湖和數據倉庫,並且能在任何雲端環境運行,包括私有雲、公共雲、托管中心和邊緣計算。
※雲原生:專為雲端運算環境設計和最佳化的應用程式和服務架構方式

Step 2:優點、缺點

優點如官網簡述,這邊延伸補充:

1. 專為物件存儲 : MinIO 是專為處理大規模的非結構化數據(如圖片、影片、備份檔案)設計的物件存儲系統。
  : 它能夠處理大量的物件並支持高效的讀取和寫入操作。
2. 高性能和可擴展 : MinIO 支援高性能的讀寫操作,並且可以通過增加節點來擴展存儲容量和提高性能。
3. S3 API 支持 : 完全兼容 Amazon S3 API,使得許多使用 S3 的應用程序可以輕鬆遷移到 MinIO,而不需要修改代碼。
4. 開源和免費 : MinIO 是開源的,並且有一個免費的社群版,適合各種大小的企業和個人使用。
5. 簡單部署和管理 : 可以在 Docker 容器、Kubernetes 環境或直接在伺服器上部署,配置和管理相對簡單。
6. 高可靠性和安全性 : 提供數據加密、備份和高可用性等功能,確保數據的安全性和可靠性。
7. 高併發處理 : 的設計是分散式的,可以水平擴展。它能夠透過將負載分散到多個節點和磁碟來處理高並發的檔案上傳需求。
  : 每個物件的上傳和下載操作都可以在多個磁碟和節點之間並行化,從而提高效能。


MinIO 也仍具有以下缺點:

1. 非關聯數據處理 : MinIO 是物件存儲系統,不適合處理結構化數據或需要複雜查詢和交易處理的場景。
  : ※不能下 SQL 關聯語法查詢出當前的物件狀態,必須透過 S3 API
2. 依賴於 API : 雖然兼容 S3 API,但對於不熟悉這些 API 的開發者來說,可能需要一些額外的學習和適應。


Step 3:進階收費方式

基本的用戶都是免費的,有需要用到更進階的服務 MinIO 也有提供,如果 MinIO 會用到 200 TB ~ 1 PB 屬於企業輕量版
1 PB 以上則是企業加強版, 1TB 收費 240/月美金

服務級別協議 (Service-Level Agreement, SLA)
供應商向客戶承諾的服務水準之外包和技術廠商合約:

等級 SLA 說明
免費版 無此服務 自行去 Github 社群上留言,回報技術問題,請求協助,不保證何時回覆
企業輕量版 下一天之前 詢問技術問題,保證會在 24 小時內回覆
企業加強版 4小時內 詢問技術問題,保證會在 4 小時內回覆




Step 4:如何評估引入使用

如果有出現以下多種狀況,就可以考慮引入了:
如果都沒下述需求符合,網路芳鄰或路由器上設置共享硬碟就是很適合的方案了。

情境 需求/原因 描述
1. 大數據存儲 需求: 如果你的企業需要存儲大量的非結構化數據,如文件、圖像、影片、備份數據、日誌文件等。
  原因: MinIO 支持 PB 級別的數據存儲,並能高效管理這些數據。其物件存儲架構特別適合處理大規模、不可預測增長的數據。
2. 用於雲端 需求: 需要可以無縫集成到現有的公有雲基礎設施中的物件存儲解決方案。
  原因: 原生雲設計的,支持雲環境中部署。與 Amazon S3 API 完全兼容,這使得將工作負載從公有雲遷移到私有雲變得更加簡單。
3. 高性能 需求: 你的應用程式對數據存取速度有高要求,例如即時分析、流媒體服務、AI/ML 訓練等需要快速的數據讀寫能力。
  原因: 能夠提供極低的延遲和高吞吐量,滿足高性能應用的需求。這對於 AI/ML 需要處理大型數據集的情況,尤為重要。
4. 數據安全 需求: 如果你的企業有高安全性和合規性的要求,特別是在金融、醫療、法律等高度受監管的行業中。
  原因: MinIO 支持端到端的數據加密、多租戶隔離、合規性審計等功能。
5. 用於雲端 需求: 預期數據量將快速增長,並需要一個可以隨需求無縫擴展的存儲解決方案。
  原因: MinIO 分散式架構使得可輕鬆橫向擴展,新增節點後系統會自動重新平衡,無需停機或複雜的配置變更。
6. 可擴展性 需求: 應用程式需要通過對象存儲接口進行數據存取操作,而不是傳統的文件存儲接口。
  原因: MinIO 是一個純物件存儲系統,完美支持通過 REST API 進行的物件存取操作。
7. 備份與恢復 需求: 你需要可靠的備份解決方案,並希望能夠快速恢復數據。
  原因: MinIO 是許多備份與恢復軟體的後端存儲解決方案,可以高效地存儲備份數據,並能快速從災難中恢復。
8. 跨地點數據同步 需求: 要在多個地理位置之間同步數據,並且要求這些數據在所有位置上都能一致地被訪問。
  原因: 支持跨地點的數據同步,確保數據在多個地點的一致性,適合跨國企業或多地運營的組織使用。
9. 降低成本 需求: 希望降低數據存儲的總擁有成本(TCO),不希望被昂貴的專有存儲系統所束縛。
  原因: 開源解決方案,並且支持在標準硬件上運行。


第二部分:架設 MinIO & 基本配置

Step 1:執行 Docker 安裝 & 說明

先確保本機已經安裝 Docker ,然後輸入以下指令,快速建立 MinIO 容器

docker run -p 9005:9005 -p 9011:9011 --name minio -e "MINIO_ROOT_USER=yourrootuser" -e "MINIO_ROOT_PASSWORD=yourrootpassword" minio/minio server /data --address ":9005" --console-address ":9011"


其中,每段重要的參數意思如下:
※ 9000 也是 MinIO 預設 Port 號,因為 9000 很容易被其他容器占用,建議使用別種 Port 號,避免衝突

-p 9005:9005 : 第 1 次的 p 表示啟動 MinIO API 容器對宿主機的 Port 號
-p 9011:9011 : 第 2 次的 p 表示啟動 MinIO WebUI 容器對宿主機的 Port 號
-e “MINIO_ROOT_USER=yourrootuser” : 第 1 次的 e 表示 MinIO 的預設帳號
-e “MINIO_ROOT_PASSWORD=yourrootpassword” : 第 2 次的 e 表示 MinIO 的預設密碼
–address “:9005” : 表示提供外部訪問的 API Port 使用 9005
–console-address “:9011” : 表示提供外部訪問的 WebUI Port 使用 9011


安裝過程:

Step 2:訪問 WebUI

安裝完成後,連線到自己的 IP 網址,我這邊使用的是內部伺服器,因此訪問:

http:\\192.168.51.188:9011


並且輸入 Step 1. 建立的帳號密碼

Step 3:設定存取金鑰 - 1

為了要能上傳下載 & 檔案,需要先建立金鑰
左側選擇 Accsee Key -> 右側選擇 Create Access Key

Step 4:設定存取金鑰 - 2

打開後, MinIO 會創建隨機帳號、密碼,這時只要選擇 Expire Date (過期時間),然後建立

Step 5:設定存取金鑰 - 完成

建立後,系統會顯示明文的帳號、密碼,可以先複製貼上
後續上傳、下載都要靠這個帳號跟密碼

Step 6:建立存儲 Bucket - 1

為了要能上傳下載 & 檔案,還需要建立存儲 (Bucket),才能保存檔案
左側選擇 Bucket -> 右側選擇 Create Bucket

Step 7:建立存儲 Bucket - 2

打開後,輸入名稱,這邊為了示意,輸入 my-bucket,然後建立

Step 8:建立存儲 Bucket - 完成

最後可以看到 Bucket 的資訊



第三部分:上傳檔案到 MinIO - DEMO

Step 1:專案簡要說明


範例檔案:本篇範例代碼,開啟專案後,會有以下內容

1. MinIO 伺服器的資訊 : 共用的 MinIO 伺服器資訊,帳號、密碼、Bucket 等,下載、上傳都會用到
2. 上傳檔案到 MinIO : 使用者 UI 互動,指定上傳檔案、執行上傳
3. 下載檔案到本機 : 使用者 UI 互動,指定下載資料夾、執行下載,檔案目前固定為 test.txt
其他 : 關於範例的版本說明、作者資訊



Step 2:上傳介面 - 選擇檔案 1

執行程式後,選擇 選擇檔案 按鈕

Step 3:上傳介面 - 選擇檔案 2

選擇一個自己的本機檔案

Step 4:上傳介面 - 執行上傳

選擇後會出現路徑,然後選擇 檔案上傳 按鈕

Step 5:上傳介面 - 上傳完成

成功的話會提示如下:

Step 6:檢查檔案

到 MinIo Server 後可以看到剛剛上傳的檔案結果

Step 7:上傳代碼說明 - 瀏覽檔案

瀏覽檔案的部分,當用戶點擊按鈕時,會觸發 ShowDialog(),若成功存取則保存用戶選擇路徑

/// <summary>
/// [Button] 瀏覽檔案
/// </summary>        
private void button_browse_Click(object sender, EventArgs e)
{
    using (OpenFileDialog openFileDialog = new OpenFileDialog())
    {
        openFileDialog.InitialDirectory = "c:\\";
        openFileDialog.Filter = "All files (*.*)|*.*";
        openFileDialog.FilterIndex = 1;
        openFileDialog.RestoreDirectory = true;
        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            // 獲取選取的檔案路徑
            textBox_filepath.Text = openFileDialog.FileName;
        }
    }
}


Step 8:上傳代碼說明 - 檔案上傳

檔案上傳的部分,當用戶點擊按鈕時,會先檢查 Bucket 是否存在,如果不存在會跳錯
成功的話可以順利上傳到 Server
※目前 MinIo 已變為創建者模式建立實例,如果使用 HTTPS,才需要創建 .WithSSL()

/// <summary>
/// [Button] 執行上傳
/// </summary>        
private void button_uploadFile_Click(object sender, EventArgs e)
{
    _ = Task.Run(() => Working());
    
    async Task Working()
    {
        try
        {
            // 使用建造者模式初始化 MinioClient
            var minio = new MinioClient()
                                .WithEndpoint(_url, _port)
                                .WithCredentials(_accessKey, _secretKey)
                                //.WithSSL() // 使用 HTTPS,才需要開啟這行
                                .Build();
            // 檢查 Bucket 是否存在                    
            var bucketExistsArgs = new BucketExistsArgs().WithBucket(_bucketName);
            bool bucketExists = await minio.BucketExistsAsync(bucketExistsArgs);
            if (!bucketExists)
            {
                var makeBucketArgs = new MakeBucketArgs().WithBucket(_bucketName);
                await minio.MakeBucketAsync(makeBucketArgs);
                Console.WriteLine($"Bucket '{_bucketName}' created successfully.");
            }
            else
            {
                Console.WriteLine($"Bucket '{_bucketName}' already exists.");
            }
            // 上傳一個檔案
            string filePath = textBox_filepath.Text;
            string objectName = Path.GetFileName(filePath);
            using (var fileStream = new FileStream(filePath, FileMode.Open))
            {
                var putObjectArgs = new PutObjectArgs()
                                    .WithBucket(_bucketName)
                                    .WithObject(objectName)
                                    .WithStreamData(fileStream)
                                    .WithObjectSize(fileStream.Length)
                                    .WithContentType("text/plain");
                await minio.PutObjectAsync(putObjectArgs);
                await ShowMessageAsync("上傳成功!");
            }
        }
        catch (MinioException e)
        {
            Console.WriteLine($"MinIO Exception: {e}");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Exception: {e}");
        }
    }
}




第四部分:下載檔案從 MinIO - DEMO

Step 1:MinIO 已存在檔案

為了說明下載,已先將 MinIO Server 上放了 test.txt 檔案

Step 2:下載介面 - 選擇資料夾1

執行程式後,選擇 存放路徑 按鈕

Step 3:下載介面 - 選擇資料夾2

選擇一個自己的本機資料夾

Step 4:下載介面 - 執行下載

選擇後會出現路徑,然後選擇 下載檔案 按鈕

Step 5:下載介面 - 下載完成

成功的話會提示如下:

Step 6:檢查檔案

到本機剛剛選擇的資料夾後,可以看到剛剛下載的檔案

Step 7:下載代碼說明 - 存放路徑

存放路徑的部分,當用戶點擊按鈕時,會觸發 ShowDialog(),選擇用戶本機的路徑。

/// <summary>
/// [Button] 下載檔案-選擇存放資料夾
/// </summary>        
private void button_downloadPath_Click(object sender, EventArgs e)
{
    using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
    {
        folderBrowserDialog.Description = "選擇下載檔案的資料夾";
        folderBrowserDialog.ShowNewFolderButton = true; // 是否允許建立新資料夾

        if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
        {
            // 獲取選取的資料夾路徑
            string selectedFolderPath = folderBrowserDialog.SelectedPath;
            textBox_downloadPathFile.Text = selectedFolderPath; // 在文本框中顯示選取的資料夾路徑 
        }
    }
}


Step 8:下載代碼說明 - 下載檔案

下載檔案的部分,當用戶點擊按鈕時,會直接從 MinIO 連線,並且下載 Bucket 內對應的檔案 (test.txt)

/// <summary>
/// [Button] 下載檔案
/// </summary>  
private void button_download_Click(object sender, EventArgs e)
{
    _ = Task.Run(() => Working());

    async Task Working()
    {

        try
        {
            // 使用建造者模式初始化 MinioClient
            var minio = new MinioClient()
                                .WithEndpoint(_url, _port)
                                .WithCredentials(_accessKey, _secretKey)
                                .Build();

            // 下載檔案,取得名稱
            string objectName = "test.txt";

            // 下載該檔案
            string downloadFilePath = textBox_downloadPathFile.Text + "\\" + objectName;
            var getObjectArgs = new GetObjectArgs()
                                .WithBucket(_bucketName)
                                .WithObject(objectName)
                                .WithFile(downloadFilePath);                    
            await minio.GetObjectAsync(getObjectArgs);
            await ShowMessageAsync($@"下載成功! 檔案路徑:{downloadFilePath}");

        }
        catch (MinioException e)
        {
            Console.WriteLine($"MinIO Exception: {e}");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Exception: {e}");
        }
    }
}