cover

架構概覽

graph TD
    Storage[儲存類型] --> Block[Block Storage<br/>磁碟區塊]
    Storage --> File[File Storage<br/>檔案系統]
    Storage --> Object[Object Storage<br/>物件儲存]

    Block -->|用途| BlockUse[VM 磁碟<br/>資料庫 Data Volume]
    File -->|用途| FileUse[NFS 共享<br/>容器 Volume Mount]
    Object -->|用途| ObjectUse[使用者上傳<br/>備份歸檔 / CI Artifact]

    Object --> Hot[Hot Bucket<br/>SSD / 頻繁存取]
    Object --> Warm[Warm Bucket<br/>HDD / 偶爾存取]
    Object --> Cold[Cold Bucket<br/>壓縮歸檔 / 長期保留]

Storage Management:檔案放哪裡、放多久、怎麼備份

當應用服務開始產生大量檔案(使用者上傳、報表輸出、日誌歸檔、備份快照),就需要一個獨立於應用伺服器的儲存層。直接放在 Docker volume 或 Host 檔案系統上,會遇到容量不可控、備份困難、跨服務存取複雜等問題。MinIO 是 S3 相容的開源物件儲存,可以自架在現有的 Host 上,用標準的 S3 API 操作,日後遷移到 AWS S3 也只需要改 endpoint。

架構概覽

flowchart TD
  App[Application Services] -->|S3 API| MinIO[MinIO Server\n:9000 API / :9001 Console]
  CI[CI Pipeline] -->|upload artifacts| MinIO
  Backup[Backup Scripts] -->|mc mirror| MinIO

  MinIO --> Hot[Hot Bucket\n頻繁存取 / SSD]
  MinIO --> Warm[Warm Bucket\n偶爾存取 / HDD]
  MinIO --> Cold[Cold Bucket\n歸檔 / 壓縮後備份]

  MinIO -->|lifecycle rule| AutoDelete[自動刪除過期物件]
  MinIO -->|mc mirror| Remote[異地備份\nNAS / 雲端 S3]
  Admin[Admin] -->|管理| Console[MinIO Console UI]

應用服務透過 S3 API 存取 MinIO,MinIO 內部用 Bucket 分類(Hot/Warm/Cold),lifecycle rule 自動管理物件生命週期。備份透過 mc mirror 同步到異地。

核心概念

  1. 物件儲存 vs 檔案系統:傳統檔案系統用目錄結構管理檔案,適合小量檔案和頻繁的隨機讀寫。物件儲存把每個檔案當作一個「物件」,用 key(路徑)+ metadata 來管理,適合大量檔案的寫入和讀取。物件儲存沒有目錄的概念(/ 只是 key 的一部分),所以不會有目錄鎖定、inode 耗盡等問題。當檔案數量超過數十萬,物件儲存的效能和可管理性遠優於傳統檔案系統。

  2. Bucket 分層策略:不是所有資料都需要同等級的存取速度。將 Bucket 按存取頻率分層:Hot(最近 30 天的上傳檔案、活躍的 API 附件)放在 SSD;Warm(30-90 天前的報表、歷史訂單附件)放在 HDD;Cold(超過 90 天的歸檔、法規要求保留的資料)壓縮後備份到 NAS 或雲端。這樣做可以在有限的 SSD 空間下,兼顧效能和成本。

  3. Lifecycle Rule(生命週期規則):MinIO 支援 S3 相容的 lifecycle policy,可以設定規則自動處理物件。例如「uploads/ 下的物件超過 90 天自動刪除」、「temp/ 下的物件超過 7 天自動刪除」。這比手動寫 cron job 清理更可靠,而且規則是 Bucket 層級的,不會漏掉任何物件。

  4. 存取控制:MinIO 支援 IAM-style 的存取控制。每個應用服務用獨立的 Access Key / Secret Key,透過 Policy 限制只能存取特定 Bucket。例如 API 服務只能讀寫 uploads Bucket,備份腳本可以讀取所有 Bucket 但不能刪除。這比所有服務共用一組 root credential 安全得多。

使用情境

  • 使用者上傳檔案:電商平台的商品圖片、使用者大頭貼、訂單附件。應用服務收到上傳後,直接透過 S3 API 存到 MinIO 的 uploads Bucket,回傳一個 presigned URL 給前端顯示。圖片不再佔用應用伺服器的磁碟空間。

  • CD Artifact 儲存:CI pipeline 的 build artifact(打包好的前端檔案、測試報告)推到 MinIO。部署時從 MinIO 拉取,而不是從 CI runner 的暫存目錄。這樣即使 CI runner 被重建,artifact 也不會消失。

  • 資料庫備份歸檔:每天的 PostgreSQL backup dump 上傳到 MinIO 的 db-backups Bucket。設定 lifecycle rule:保留最近 30 天的每日備份、每月 1 號的備份保留 1 年。超過保留期的自動刪除,不用手動清理。

實作範例 / 設定範例

MinIO 部署(docker-compose)

# docker-compose.yml
version: "3.8"
 
services:
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    restart: unless-stopped
    ports:
      - "9000:9000"   # S3 API
      - "9001:9001"   # Web Console
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: ChangeMeToStrongPassword
    volumes:
      - minio-data:/data
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 5s
      retries: 3
 
volumes:
  minio-data:
    driver: local

mc(MinIO Client)基本操作

# 設定 alias
mc alias set myminio http://minio.example.com:9000 minioadmin ChangeMeToStrongPassword
 
# 建立 Bucket
mc mb myminio/uploads
mc mb myminio/db-backups
mc mb myminio/temp
 
# 設定 lifecycle rule:temp bucket 7 天後自動刪除
mc ilm rule add myminio/temp --expire-days 7
 
# 設定 lifecycle rule:db-backups 保留 90 天
mc ilm rule add myminio/db-backups --expire-days 90
 
# 上傳 / 下載
mc cp ./report.pdf myminio/uploads/2024/09/report.pdf
mc cp myminio/uploads/2024/09/report.pdf ./downloaded-report.pdf
 
# 列出 Bucket 內容
mc ls myminio/uploads/2024/09/
 
# 查看 Bucket 使用量
mc du myminio/uploads

建立應用專用 Access Key

# 建立 policy:只允許讀寫 uploads bucket
cat > uploads-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::uploads",
        "arn:aws:s3:::uploads/*"
      ]
    }
  ]
}
EOF
 
# 建立使用者並套用 policy
mc admin user add myminio app-api-user AppApiSecretKey123
mc admin policy create myminio uploads-readwrite uploads-policy.json
mc admin policy attach myminio uploads-readwrite --user app-api-user

異地備份(mc mirror)

# 設定遠端 alias(NAS 上的另一台 MinIO,或 AWS S3)
mc alias set nas-backup http://nas.internal:9000 backupuser BackupSecret
 
# 同步整個 db-backups bucket 到 NAS
mc mirror myminio/db-backups nas-backup/db-backups
 
# 加入 crontab 每天凌晨 4 點同步
# 0 4 * * * mc mirror --overwrite myminio/db-backups nas-backup/db-backups

常見問題與風險

  • 磁碟空間耗盡:MinIO 本身不會限制 Bucket 容量,如果沒設 lifecycle rule,資料量會無限增長。MinIO 的 data volume 滿了,所有 PUT 操作會失敗,連帶影響應用服務的檔案上傳功能。避免方式:設定 lifecycle rule 自動清理、監控磁碟使用率在 80% 時告警、定期用 mc du 檢查各 Bucket 使用量。

  • Credential 外洩:MinIO 的 root credential 或應用的 Access Key 如果寫在程式碼裡被推到 Git,等於任何人都能存取所有資料。避免方式:Credential 透過環境變數注入,不寫在程式碼或 docker-compose.yml 裡。應用服務用最小權限的 Access Key,不要直接用 root credential。

  • 單節點故障:單台 MinIO 掛了,所有依賴它的服務都無法存取檔案。和 Harbor 類似,已經下載到本地的檔案不受影響,但新的上傳和下載會失敗。避免方式:用 mc mirror 定期備份到異地。對可用性要求高的場景,考慮 MinIO 的 Distributed Mode(多節點 erasure coding)。

  • 效能瓶頸:MinIO 單節點的效能受限於磁碟 I/O。如果大量服務同時讀寫,可能出現延遲。避免方式:Hot data 放 SSD、Cold data 放 HDD。大檔案上傳使用 multipart upload。在應用層加上 CDN 或快取,減少直接存取 MinIO 的次數。

優點

  • S3 相容 API,應用程式碼日後遷移到 AWS/GCP 只需改 endpoint
  • Lifecycle rule 自動管理資料生命週期,減少手動維護
  • Web Console 提供視覺化管理,降低操作門檻

缺點 / 限制

  • 單節點模式沒有資料冗餘,磁碟壞了資料就沒了
  • Distributed Mode 至少需要 4 個節點,小團隊可能資源不足
  • MinIO 的 IAM 功能不如 AWS IAM 完整,複雜的權限需求可能需要額外設計

延伸閱讀