如何在 AdonisJS 中使用 Vultr 對象存儲

介紹

Drive 是 AdonisJS 中的一個存儲抽像庫。 它提供了適用於所有存儲提供商的一致 API。

Drive有一個S3驅動來支持S3兼容的雲存儲,比如Vultr Object Storage。 本指南解釋瞭如何為 Vultr 對象存儲設置 AdonisJS Drive 並使用它來存儲和讀取文件。

以前的要求

在開始之前,您必須:

安裝 Node.js

AdonisJS 至少需要 Node.js 版本 14。 您可以使用節點版本管理器 (NVM) 安裝最新版本的 Node.js。

  1. 安裝 NVM:

                              
                                $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
    
                              
                            
  2. 斷開並重新連接您的 ssh 會話。

  3. 安裝 Node.js:

                              
                                $ nvm install node
    
                              
                            
  4. 檢查 Node.js 的版本:

                              
                                $ node -v
    
    v19.3.0
    
                              
                            

創建對象存儲

  1. 登錄Vultr 客戶門戶.

  2. 導航產品 -> 對象.

  3. 添加對象存儲. 選擇區域並為其添加標籤。

  4. 單擊您的項目存儲並轉到“立方體”選項卡。

  5. 創建一個存儲桶並為其命名。

  6. 請注意 Hostname Secret Key Access Key Bucket Name .

創建新的 AdonisJS 應用程序

轉到主目錄。

                      
                        $ cd ~

                      
                    

為您的應用程序創建一個新目錄。

                      
                        $ mkdir app

                      
                    

前往 app 目錄並使用 npm init 領域。

                      
                        $ cd app

$ npm init [email protected] website

                      
                    
  • 選擇 Web 項目結構。

  • 當提示配置 Webpack Encore 時選擇“y”。

構建您的應用程序 website 目錄。 對於其餘任務,您必須在 website 目錄。

                      
                        $ cd website

                      
                    

安裝 Redis

本指南中的示例應用程序使用 Redis 來存儲圖像的文件名。

安裝 Redis:

                      
                        $ sudo apt install redis-server

                      
                    

配置 Redis 持久化模式:

  1. 打開 Redis 配置文件:

                              
                                $ sudo nano /etc/redis/redis.conf
    
                              
                            
  2. 改變 appendonly no appendonly yes .

  3. 保存文件並退出。

  4. 重新啟動 Redis。

                              
                                $ sudo systemctl restart redis-server
    
                              
                            

安裝和配置 AdonisJS Redis 包:

                      
                        $ npm i @adonisjs/redis

$ node ace configure @adonisjs/redis

                      
                    

打開 env.ts 程序:

                      
                        $ nano env.ts

                      
                    

添加以下規則:

                      
                        REDIS_CONNECTION: Env.schema.enum(['local'] as const),

REDIS_HOST: Env.schema.string({ format: 'host' }),

REDIS_PORT: Env.schema.number(),

REDIS_PASSWORD: Env.schema.string.optional(),

                      
                    

配置 AdonisJS 單元

AdonisJS Drive 有一個 S3 驅動程序來與 S3 兼容的雲存儲交互,比如 Vultr 對象存儲。

安裝和配置 S3 驅動程序:

                      
                        $ npm i @adonisjs/drive-s3

$ node ace configure @adonisjs/drive-s3

                      
                    

打開 env.ts 程序:

                      
                        $ nano env.ts

                      
                    

更新 DRIVE_DISK 規則:

                      
                        DRIVE_DISK: Env.schema.enum(['local','s3'] as const),

                      
                    

添加以下規則:

                      
                        S3_KEY: Env.schema.string(),

S3_SECRET: Env.schema.string(),

S3_BUCKET: Env.schema.string(),

S3_REGION: Env.schema.string(),

S3_ENDPOINT: Env.schema.string.optional(),

                      
                    

打開 config/drive.ts 程序:

                      
                        $ nano config/drive.ts

                      
                    

在裡面添加S3配置 disks 目的:

                      
                        s3: {

    driver: 's3',

    visibility: 'public',

    key: Env.get('S3_KEY'),

    secret: Env.get('S3_SECRET'),

    region: Env.get('S3_REGION'),

    bucket: Env.get('S3_BUCKET'),

    endpoint: Env.get('S3_ENDPOINT'),

}

                      
                    

打開 .env 程序:

                      
                        $ nano .env

                      
                    

更新 DRIVE_DISK s3 :

                      
                        DRIVE_DISK=s3

                      
                    

添加 Vultr 對象存儲憑證:

                      
                        S3_KEY=

S3_SECRET=

S3_BUCKET=adonis-drive

S3_REGION=sgp1

S3_ENDPOINT=https://sgp1.vultrobjects.com

                      
                    
  • S3_KEY 是您訪問 Vultr 對象存儲的密鑰。

  • S3_SECRET 是您的秘密 Vultr 對象存儲密鑰。

  • S3_BUCKET` 是您的 Vultr 對象存儲桶的名稱。

  • S3_ENDPOINT 是您的 Vultr 對象存儲主機名。

  • S3_REGION 是您的 Vultr 對象存儲區域。

添加順風 CSS

本指南使用 Tailwind CSS 作為 CSS 框架。 通過 NPM 安裝 Tailwind CSS 及其依賴項:

                      
                        $ npm install -D tailwindcss postcss autoprefixer postcss-loader

                      
                    

打開 webpack.config.js 程序:

                      
                        $ nano webpack.config.js

                      
                    

啟用 PostCSS 加載器:

                      
                        Encore.enablePostCssLoader()

                      
                    

創建並打開 Tailwind CSS 配置文件:

                      
                        $ npx tailwindcss init -p

$ nano tailwind.config.js

                      
                    

將內容更改為:

                      
                        /** @type {import('tailwindcss').Config} */

module.exports = {

    content: [

        "./resources/**/*.edge",

        "./resources/**/*.js",

    ],

    theme: {

        extend: {},

    },

    plugins: [],

}

                      
                    

打開 resources/css/app.css 並用 Tailwind CSS 指令替換內容:

                      
                        @tailwind base;

@tailwind components;

@tailwind utilities;

                      
                    

添加 JavaScript

打開 resources/js/app.js 並添加以下腳本:

                      
                        import '../css/app.css'



document.getElementById('fileImage').addEventListener('change',function(){

  if( this.files.length > 0 ){

      document.getElementById('uploadBtn').removeAttribute('disabled');

  }

});

                      
                    

用戶選擇圖像文件後,腳本會啟用上傳按鈕。

創建視圖

創建一個 resources/views/gallery.edge 程序:

                      
                        $ nano resources/views/gallery.edge

                      
                    

添加以下代碼:

                      
                        <html>

    <head>

        <title>Gallery</title>



        @entryPointStyles('app')

    </head>

    <body>

        <div class="max-w-7xl m-auto">

            <h1 class="text-3xl font-bold text-gray-900 text-center py-8 uppercase">Gallery</h1>

            <form action="" method="post" enctype="multipart/form-data" class="flex flex-wrap text-center justify-center items-start p-4 rounded-lg">

                <label class="block py-1">

                  <input id="fileImage" type="file" name="fileImage" class="block w-full text-sm text-slate-500 pr-6

                    file:cursor-pointer

                    file:mr-4 file:py-2 file:px-4

                    file:rounded-full file:border-0

                    file:text-sm file:font-semibold

                    file:bg-indigo-50 file:text-indigo-700

                    hover:file:bg-indigo-100

                  "/>



                  @if (flashMessages.has('errors.fileImage'))

                    <span class="block text-red-700 py-4 text-left">{{ flashMessages.get('errors.fileImage') }}</span>

                  @endif

                </label>

                <button id="uploadBtn" disabled class="rounded border border-transparent bg-indigo-600 px-6 py-2 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50" type="submit">

                    Upload Image

                </button>

            </form>



            <div class="grid grid-cols-2 gap-x-4 gap-y-8 sm:grid-cols-3 sm:gap-x-6 lg:grid-cols-4 xl:gap-x-8 ">

                @each(image in images)

                    <div>

                        <img class="rounded" src="">

                    </div>

                @end

            </div>

        </div>



        @entryPointScripts('app')

    </body>

</html>

                      
                    

創建控制器

創建並打開 GalleryController.ts 程序:

                      
                        $ node ace make:controller GalleryController -e

$ nano app/Controllers/Http/GalleryController.ts

                      
                    

在文件頂部導入庫和助手:

                      
                        import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

import Drive from '@ioc:Adonis/Core/Drive'

import Redis from '@ioc:Adonis/Addons/Redis'

import { string } from '@ioc:Adonis/Core/Helpers'

import { schema } from '@ioc:Adonis/Core/Validator'

                      
                    

創建 index 行動。 顯示上傳表單並列出 Vultr 對象存儲中的所有圖像。 獲取Redis鏡像文件名和調用 getUrl 從 Drive 庫中獲取每個圖像的 URL。

                      
                        public async index({ view }: HttpContextContract) {

    const galleryString = await Redis.get('gallery')

    const gallery = (galleryString) ? JSON.parse(galleryString) : []



    let images:string[] = []



    for (const filename of gallery) {

        const url = await Drive.getUrl(`gallery/${filename}`)

        images.push(url)

    }



    return view.render('gallery', { images })

}

                      
                    

創建 upload 行動。 處理用戶上傳圖片的時間。 驗證文件,將文件名保存到 Redis,然後使用 moveToDisk 方法。

                      
                        public async upload({ request, response }: HttpContextContract) {

    const imageSchema = schema.create({

        fileImage: schema.file({

            extnames: ['jpg', 'png', 'gif']

        }),

    })



    const payload = await request.validate({ schema: imageSchema })

    const filename = `${string.generateRandom(32)}.${payload.fileImage.extname}`



    if (payload.fileImage) {

        await payload.fileImage.moveToDisk(", {

            name: `gallery/${filename}`

        }, 's3')



        const galleryString = await Redis.get('gallery')



        let gallery:string[] = []



        if (galleryString) {

            gallery = JSON.parse(galleryString)

        }



        gallery.push(filename)

        await Redis.set('gallery', JSON.stringify(gallery))

    }



    return response.redirect().toPath("https://www.vultr.com/")

}

                      
                    

您需要保存並獲取 Redis 圖像文件名,因為 AdonisJS S3 驅動程序無法獲取存儲桶或文件夾中的文件列表。 您一次只能獲取一個文件。

以下為全文 GalleryController.ts 程序:

                      
                        import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

import Drive from '@ioc:Adonis/Core/Drive'

import Redis from '@ioc:Adonis/Addons/Redis'

import { string } from '@ioc:Adonis/Core/Helpers'

import { schema } from '@ioc:Adonis/Core/Validator'



export default class GalleryController {

    public async index({ view }: HttpContextContract) {

        const galleryString = await Redis.get('gallery')

        const gallery = (galleryString) ? JSON.parse(galleryString) : []



        let images:string[] = []



        for (const filename of gallery) {

            const url = await Drive.getUrl(`gallery/${filename}`)

            images.push(url)

        }



        return view.render('gallery', { images })

    }



    public async upload({ request, response }: HttpContextContract) {

        const imageSchema = schema.create({

            fileImage: schema.file({

                extnames: ['jpg', 'png', 'gif']

            }),

        })



        const payload = await request.validate({ schema: imageSchema })

        const filename = `${string.generateRandom(32)}.${payload.fileImage.extname}`



        if (payload.fileImage) {

            await payload.fileImage.moveToDisk(", {

                name: `gallery/${filename}`

            }, 's3')



            const galleryString = await Redis.get('gallery')



            let gallery:string[] = []



            if (galleryString) {

                gallery = JSON.parse(galleryString)

            }



            gallery.push(filename)

            await Redis.set('gallery', JSON.stringify(gallery))

        }



        return response.redirect().toPath("https://www.vultr.com/")

    }

}

                      
                    

添加路線

打開 start/routes.ts 程序:

                      
                        $ nano start/routes.ts

                      
                    

添加以下代碼:

                      
                        Route.get("https://www.vultr.com/", 'GalleryController.index')

Route.post("https://www.vultr.com/", 'GalleryController.upload')

                      
                    

測試應用

  1. 要測試您的應用程序,您必須禁用防火牆Ubuntu.

                              
                                $ sudo ufw disable
    
                              
                            

    您可以在構建用於生產的應用程序時重新啟用它。

  2. 啟動開發服務器:

                              
                                $ node ace serve --encore-args="--host [VULTR_VPS_IP_ADDRESS]"
    
                              
                            
  3. 打開 https://[VULTR_VPS_IP_ADDRESS]:3333 在瀏覽器中。

  4. 您應該看到上傳表單。

  5. 上傳圖像。

  6. 檢查圖像是否出現在您的 Vultr 對象存儲和上傳表單下方的圖庫中。

  7. 按 CTRL+C 停止開發服務器。

使用多個對象存儲位置

Vultr 對象存儲在多個位置可用。 以下是 Vultr 支持的位置:

  • 阿姆斯特丹: ams1.vultrobjects.com

  • 新澤西州: ewr1.vultrobjects.com

  • 矽谷: sjc1.vultrobjects.com

  • 新加坡: sgp1.vultrobjects.com

您可以在 AdonisJS 應用程序中使用多個對象存儲位置來為您的文件添加冗餘。 為此,請為磁盤上的每個位置添加一個磁盤配置 config/drive.ts 程序。 AdonisJS Drive 中的驅動器代表一個特定的存儲位置和控制器。

創建新的對象存儲

  1. 要去Vultr 客戶門戶.

  2. 導航產品 -> 對象.

  3. 添加對象存儲. 選擇不同的地區,例如阿姆斯特丹。

  4. 在新的對象存儲中創建一個桶。

  5. 請注意 Hostname Secret Key Access Key Bucket Name .

設置新磁盤

打開 config/drive.ts 程序:

                      
                        $ nano config/drive.ts

                      
                    

在 S3 部分添加新的磁盤配置。 您可以將磁盤名稱設置為任何內容,例如, s3ams . 為環境變量名稱添加後綴,以區別於第一個磁盤。

                      
                        s3ams: {

  driver: 's3',

  visibility: 'public',

  key: Env.get('S3_KEY_AMS'),

  secret: Env.get('S3_SECRET_AMS'),

  region: Env.get('S3_REGION_AMS'),

  bucket: Env.get('S3_BUCKET_AMS'),

  endpoint: Env.get('S3_ENDPOINT_AMS'),

},

                      
                    

打開 .env 程序:

                      
                        $ nano .env

                      
                    

添加您的對象存儲憑據:

                      
                        S3_KEY_AMS=

S3_SECRET_AMS=

S3_BUCKET_AMS=adonis-drive

S3_REGION_AMS=ams1

S3_ENDPOINT_AMS=https://ams1.vultrobjects.com

                      
                    
  • S3_KEY_AMS 是您訪問 Vultr 對象存儲的密鑰。

  • S3_SECRET_AMS 是您的秘密 Vultr 對象存儲密鑰。

  • S3_BUCKET_AMS 是它的 Vultr 對象存儲庫名稱。

  • S3_ENDPOINT_AMS 是您的 Vultr 對象存儲主機名。

  • S3_REGION_AMS 是您的 Vultr 對象存儲區域。

打開 env.ts 程序:

                      
                        $ nano env.ts

                      
                    

添加 s3ams 磁盤名稱 DRIVE_DISK 枚舉值:

                      
                        DRIVE_DISK: Env.schema.enum(['local','s3','s3ams'] as const),

                      
                    

添加驗證規則 s3ams 磁盤環境變量:

                      
                        S3_KEY_AMS: Env.schema.string(),

S3_SECRET_AMS: Env.schema.string(),

S3_BUCKET_AMS: Env.schema.string(),

S3_REGION_AMS: Env.schema.string(),

S3_ENDPOINT_AMS: Env.schema.string.optional(),

                      
                    

保存文件並關閉。

更新驅動程序

打開 GalleryController.ts 程序:

                      
                        $ nano app/Controllers/Http/GalleryController.ts

                      
                    

在裡面 upload action,找到負責將文件上傳到對象存儲的代碼。

                      
                        await payload.fileImage.moveToDisk(", {

    name: `gallery/${filename}`

}, 's3')

                      
                    

複製代碼並將磁盤重命名為 s3ams .

                      
                        await payload.fileImage.moveToDisk(", {

    name: `gallery/${filename}`

}, 's3')



await payload.fileImage.moveToDisk(", {

    name: `gallery/${filename}`

}, 's3ams')

                      
                    

將文件上傳到兩個對象存儲位置。

設置默認磁盤

index 中的動作 GalleryController.ts 使用默認磁盤獲取圖像 url。 要更改默認磁盤,請打開 .env 程序:

                      
                        $ nano .env

                      
                    

更新 DRIVE_DISK 您想要的磁盤的值:

                      
                        DRIVE_DISK=s3ams

                      
                    

保存文件並關閉。

試用應用程序

  1. 啟動開發服務器:

                              
                                $ node ace serve --encore-args="--host [VULTR_VPS_IP_ADDRESS]"
    
                              
                            
  2. 打開 https://[VULTR_VPS_IP_ADDRESS]:3333 在瀏覽器中。

  3. 上傳圖像。

  4. 檢查圖像是否同時出現在 Vultr 對象存儲位置和上傳表單下方的圖庫中。

  5. 按 CTRL+C 停止開發服務器。

為生產而建

AdonisJS 應用程序使用 TypeScript。 您必須先將其編譯為 JavaScript,然後才能在生產環境中運行它。

前往 website 文件:

                      
                        $ cd ~/app/website

                      
                    

編譯它使用 build 領域。 結果在 build 文件。

                      
                        $ node ace build --production --ignore-ts-errors

                      
                    

複製 .env 文件到 build 文件夾並打開它:

                      
                        $ cp .env build/.env

$ nano build/.env

                      
                    

選擇 NODE_ENV 中的變量 .env 歸檔到 production :

                      
                        NODE_ENV=production

                      
                    

在上安裝僅限生產的依賴項 build 文件:

                      
                        $ cd build

$ npm ci --production

                      
                    

使用 PM2 在生產環境中運行應用程序

PM2 是守護進程管理器。 它可以幫助您在生產環境中運行和管理 AdonisJS 應用程序。

安裝最新的 PM2 包:

                      
                        $ npm install [email protected] -g

                      
                    

創建 PM2 生態系統文件來管理您的應用程序:

                      
                        $ cd ~/app

$ nano ecosystem.config.js

                      
                    

將這些設置添加到 ecosystem.config.js 程序:

                      
                        module.exports = {

    apps : [

        {

            name   : "website",

            script : "./website/build/server.js"

        }

    ]

}

                      
                    
  • 將您的應用程序的名稱放在 name 範圍。

  • 放生產路線 script.js 在裡面 script 範圍。

運行你的應用程序:

                      
                        $ pm2 start ecosystem.config.js

$ pm2 list

                      
                    

此時,您的應用程序正在運行。 但是,這個過程還不是持久的。 這意味著您必須在重新啟動服務器後再次手動運行您的應用程序。

要運行持久應用程序,您必須為 PM2 生成啟動腳本。

                      
                        $ pm2 startup

                      
                    

複製並粘貼終端中顯示的命令:

                      
                        $ sudo env PATH=$PATH:/home/ubuntu/.nvm/versions/node/v19.3.0/bin /home/ubuntu/.nvm/versions/node/v19.3.0/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu

                      
                    

使用此命令保存您的 PM2 應用程序列表:

                      
                        $ pm2 save

                      
                    

Nginx 回退代理

您必須配置 Nginx 回退代理以將您的域連接到您的應用程序。 你把你的應用程序放在 Nginx 網絡服務器後面。 它接受所有傳入的請求並將它們轉發給您的應用程序。

添加 ondrej 存儲庫以獲取最新版本的 Nginx。

                      
                        $ sudo add-apt-repository -y ppa:ondrej/nginx-mainline

$ sudo apt update

                      
                    

安裝 Nginx:

                      
                        $ sudo apt install nginx

                      
                    

禁用 Nginx 默認設置:

                      
                        $ sudo unlink /etc/nginx/sites-enabled/default

                      
                    

新建一個 Nginx 配置文件:

                      
                        $ sudo nano /etc/nginx/sites-available/website

                      
                    

添加以下設置。 確保更改域名 googlesyndication.com 到您的域。 保存文件並關閉。

                      
                        server {

    listen 80;



    server_name googlesyndication.com;



    location / {

        proxy_pass https://localhost:3333;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;

        proxy_set_header Connection 'upgrade';

        proxy_set_header Host $host;

        proxy_set_header X-Real-IP $remote_addr;

        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_cache_bypass $http_upgrade;

    }

}

                      
                    

啟用 Nginx 配置:

                      
                        $ sudo ln -s /etc/nginx/sites-available/website /etc/nginx/sites-enabled/

                      
                    

測試您的配置是否存在語法錯誤:

                      
                        $ sudo nginx -t

                      
                    

如果沒有錯誤,您可以重新加載 Nginx 進程:

                      
                        $ sudo systemctl reload nginx

                      
                    

將您的域名指向您的 Vultr VPS IP 地址。

配置防火牆

配置防火牆以允許 ssh 端口:

                      
                        $ sudo ufw allow 'OpenSSH'

                      
                    

允許 HTTP 和 HTTPS 端口:

                      
                        $ sudo ufw allow 'Nginx Full'

                      
                    

啟用防火牆:

                      
                        $ sudo ufw enable

                      
                    

查看防火牆狀態:

                      
                        $ sudo ufw status

                      
                    

使用 Let's Encrypt SSL 證書保護應用程序

Let's Encrypt 為您的網站提供免費的 SSL 證書。 要生成證書,您必須使用 Certbot 軟件工具。

安裝 Certbot:

                      
                        $ sudo snap install core; sudo snap refresh core

$ sudo snap install --classic certbot

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

                      
                    

生成 SSL 證書:

                      
                        $ sudo certbot --nginx

                      
                    

在瀏覽器中訪問您的域並確認您有 HTTPS 連接。

Let's Encrypt 證書將在 90 天后過期。 Certbot 將更新命令添加到 systemd 或 Cron Job 計時器,以在證書過期之前自動更新證書。 您可以使用以下命令驗證它:

                      
                        $ systemctl list-timers | grep 'certbot|ACTIVATES'

                      
                    

結論

本指南展示了在具有一個或多個對象存儲位置的 AdonisJS 中使用 Vultr 對象存儲的示例,包括讓您的應用程序做好生產準備的步驟。

其他閱讀

Vultr 對象存儲。

AdonisJS 驅動文檔。

使用 PM2 和 Nginx 部署多個 Adonis.js 應用程序。

PM2 文檔。

NGINX 反向代理。

文章標題 名稱(可選) 電子郵件(可選) 描述

發送建議

相關文章