iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
Modern Web

Fastify 101系列 第 24

[Fastify] Day24 - Upload File to Object Storage (MinIO)

  • 分享至 

  • xImage
  •  

大家好,我是 Yubin

這篇文章會跟大家介紹如何實作上傳檔案到 Object Storage。
並在本地端建立相應的開發環境,使用的 Object Storage 是 Minio,要上傳到 AWS S3 也是相同作法。


要上傳檔案,要先讓 Fastify App 可以支援 multipart 格式的 Content-Type,這邊使用 @fastify/multipart 這個官方 Plugin 來實作。

對於使用 @fastify/multipart 不熟悉的朋友,可以參考 Fastify101: Upload File


MinIO

MinIO 是一款非常熱門的 Object Storage。

說到 Object Storage,許多人可能耳熟能詳的是 AWS S3 服務,但對於公司內部服務的使用或開發人員本地開發環境的架設來說,Minio 是一個非常棒的選擇。

Minio 相容於 S3 的 API,意思是就算你的服務要接的 Object Storage 是 S3,也可以在本地端使用 MinIO 來進行開發測試。

除了相容於 S3,MinIO 是 100% 開源 (可商業使用的 GNU AGPL v3 授權),且支援部屬到 Kubernetes 或其他公私有雲服務商上。

本地端建製 MinIO 開發環境

為了開發的時候方便,我們在自己的本地端上起一個 MinIO 的環境,根據不同作業系統可以參考 MinIO 官方文件 來進行安裝。

當然,為了快速方便,這邊還是一樣使用 Container 來操作。

MinIO Container

打開 terminal 敲入:

docker run -p 9000:9000 -p 9001:9001 --name=minio-server \
    quay.io/minio/minio server /data \
    --console-address ":9001"

如果使用 podman,把 docker run 換成 podman run 即可。

這裡使用的是 MinIO 官方的 image: quay.io/minio/minio

MinIO 的 Port,預設會使用 90009001

9000 是 API Port,也就是程式用來溝通用的 Port。
9001 是 Console Port,這邊的 Console 是指給人看的管理介面。

MinIO Console

起好 Container 後,打開瀏覽器 localhost:9001

https://ithelp.ithome.com.tw/upload/images/20221009/201511488jm5tWIzP7.jpg

看到登入表單,輸入預設帳號密碼 minioadmin / minioadmin 就可以登入。

補充,有些版本的 image 不允許使用預設帳號密碼登入。
可以透過起 Container 的時候加上環境變數 MINIO_ROOT_USERMINIO_ROOT_PASSWORD 來更改 root 帳號密碼。

登入之後就可以看到 MinIO 的管理頁面。

在 MinIO (或 S3) 的使用上,每個檔案都會放在某個 Bucket 底下,所以我們要先建立 Bucket。

https://ithelp.ithome.com.tw/upload/images/20221009/2015114886Rf1S2Plk.jpg

我們的目的只是測試開發用,可以自己取喜歡的 Bucket 名字。

要特別注意的是,Bucket 的名稱不能使用英文大寫來命名。

https://ithelp.ithome.com.tw/upload/images/20221009/20151148X3UQrVPUkv.jpg

建好 Bucket 之後,我們來新增 MinIO 的使用者。

https://ithelp.ithome.com.tw/upload/images/20221009/20151148hkjS80E2OG.jpg

這邊的使用者會設定相應的權限,也就是可以操作這座 MinIO Server 的使用者。

除了個別設定使用者外,也可以設定 Group 以及 Policy
權限的設定攸關資料的隱私及伺服器的安全,請妥善閱讀文件進行相應的設定。

要建立開發測試用的使用者,我們這邊可以自己設定該使用者的 Username 及 Password。
權限部分勾選 readwrite 就足夠了。

https://ithelp.ithome.com.tw/upload/images/20221009/201511486grOaCCRgH.jpg

建立好 MinIO User 後,就可以開始設定程式端的連接。

minio-js

要使用 JavaScript 與 MinIO 進行互動,可以透過官方的套件:minio-js

可以透過 npm 來安裝:

npm i minio

因為我們使用 Typescript 進行開發,要另外安裝 Type 定義檔:

npm i -D @types/minio

接著在程式裡面設定 MinIO Client,帶入要連接的 MinIO Server 資訊。

import * as minio from 'minio'

const minioClient = new minio.Client({
  endPoint: 'localhost',
  port: 9000,
  useSSL: false,
  accessKey: 'user01',
  secretKey: 'user01password'
})

透過 minio-js 產生 minioClient 物件。

  • endPoint,是要連線的 MinIO Server 的位置,因為我們這邊起在本機,所以用 localhost 即可。
  • port,目標 MinIO Server 使用的 API Port,預設使用的 Port 為 9000
  • useSSL,如果目標 MinIO Server 有透過 SSL 加密連線,要設定為 true
  • accessKey,這邊填入 MinIO User 的 User Name 即可。
  • secretKey,填入 MinIO User 的 Password。

補充,如果使用 AWS S3,就會給你連線用的 accessKey 及 secretKey,而不會是像上面範例輸入使用者的帳號密碼。

接著就可以透過 minioClient 來使用 MinIO API 來與 MinIO Server 進行互動。

putObject()

putObject() 是 MinIO Client 的方法,可以把檔案上傳到 MinIO。

await minioClient.putObject(
    bucketName,
    filename,
    fileBuffer
)

回傳的是 Promise 物件,可以使用 async/await style 或 callback style 來寫。

也可以帶入 metaData 作為附加資訊。

const metaData = {
    key01: 'value01'
}

await minioClient.putObject(bucketName, filename, fileBuffer, metaData)

範例程式

以下程式定義了 POST /uploads 這個 Endpoint,Client 端把檔案送過來後,透過 MinIO Client 上傳到 MinIO Server。

使用 @fastify/multipart,可以參考 Fastify101: Upload File

import fastify, { FastifyInstance } from 'fastify'
import * as minio from 'minio'

const server: FastifyInstance = fastify()

const minioClient = new minio.Client({
    endPoint: 'localhost',
    port: 9000,
    useSSL: false,
    accessKey: 'user01',
    secretKey: 'user01password'
})

const bucketName = 'bucket01'

server.post('/uploads', async (request, reply) => {
    try {
      const data = await request.file()
      if (data) {
        const filename = data.filename
        const fileBuffer = await data.toBuffer()
        const metadata = {
          key01: 'value01'
        }
        
        // upload to minio
        await minioClient.putObject(bucketName, filename, fileBuffer, metadata)

        return reply
          .status(201)
          .send({ message: `Successfully upload file: ${filename}` })
      } else {
        return reply.status(400).send({ message: `Failed to upload file` })
      }
    } catch (error) {
      return reply.status(500).send({ error })
    }
})

定義好 route 後,把程式跑起來。

透過 Postman 幫我們打一個 POST 的 Request,並帶上檔案。

https://ithelp.ithome.com.tw/upload/images/20221009/20151148X2hq3r8dZZ.jpg

看到成功的回應。

接著我們打開 MinIO Console (http://localhost:9001)。

可以在 Bucket 的頁面按 Broswer 瀏覽該 Bucket 內的檔案。

https://ithelp.ithome.com.tw/upload/images/20221009/20151148TEGmogUsFb.jpg

看到剛才上傳的檔案,也可以在這邊對檔案進行操作。

https://ithelp.ithome.com.tw/upload/images/20221009/20151148WprvQ087qi.jpg

也可以觀察到,剛才在程式中的 .putObject() 有帶入了 Metadata:

const metadata = {
    key01: 'value01'
}

上傳到 MinIO 上會以這樣的形式呈現。

https://ithelp.ithome.com.tw/upload/images/20221009/20151148IkfeN1yTQT.jpg


MinIO 是個優秀的 Object Storage,透過 Container 我們也可以快速的建立好開發環境。

官方維護的 minio-js 的操作也相當直覺。

如上述提到的,使用者權限的設定很重要,某個使用者只能對某個 Bucket 進行操作,或只有讀取的權限等。跟資料有關的權限都要謹慎規劃。

把檔案統一交由 Object Storage 管理,而不是存在某台機器的 Local File System 上,是 Cloud Native 中相當常見的做法,不會因為 App 本身的水平擴展而造成資料存取上的問題。


上述範例程式是資料上傳進來,以 Buffer 的形式直接交給 MinIO。

如果要上傳本地端的檔案到 MinIO,可以使用 fPutObject,相關資訊可以參考官方文件的範例程式。

本篇文章的完整程式可以參考 GitHub


上一篇
[Fastify] Day23 - Upload File
下一篇
[Fastify] Day25 - Authentication and Authorization
系列文
Fastify 10130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言