基於 Serverless Component 全棧解決方案

什麼是 Serverless Component

Serverless ComponentServerless Framework 的,支持多個雲資源編排和組織的場景化解決方案。html

Serverless Component 的目標是磨平不一樣雲服務平臺之間差別,你能夠將它看做是能夠更輕鬆地構建應用程序的依賴模塊。目前 Serverless Component 已經造成一個由社區貢獻驅動的生態系統,你能夠瀏覽和使用社區的全部組件,快速開發一款本身想要的應用。前端

Serverless Component 工做原理

基於 Serverless Component 架構,你能夠將任何雲服務打包成一個組件。這個組件將含有一份 serverless.yml 配置文件,而且經過簡單地進行配置就可使用。本文以 @serverless/tencent-express 來舉例。vue

若是咱們要使用它,只須要新建一個項目 express-demo,而後修改 serverless.yml 配置以下:mysql

express:
  component: '@serverless/tencent-express'
  inputs:
    region: ap-shanghai

由於 serverless 框架部署到雲的鑑權都是基於 dotenv 注入全局的變量來實現的,因此還得在根目錄下新增 .env 文件,並配置對應的鑑權參數。ios

以後咱們就能夠在 app.js 中輕鬆的編寫基於 express 的接口服務了:git

const express = require('express')
const app = express()
app.get('/', function(req, res) {
  res.send('Hello Express')
})
// 不要忘了導出,由於該組件會對它進行包裝,輸出成雲函數
module.exports = app

這背後全部的流程邏輯都是組件內部實現的,包括:雲函數的部署,API 網關的生成等。github

下面是一張簡單的組件依賴圖:web

Component Dependency Structure

經過此圖能夠清晰地查看組件帶來的收益,藉助社區現有的 @serverless/tencent-express@serverless/tencent-website 組件,咱們就能夠很快構建想要的全棧應用。sql

全棧應用實戰

接下來將介紹如何藉助 Serverless Component 快速開發全棧 Web 應用。vue-cli

full-stack

在開始全部步驟前,需執行 npm install -g serverless 命令,全局安裝 serverless cli

準備

新建項目目錄 fullstack-application-vue,在該項目目錄下新增 apidashboard 目錄。而後新增 serverless.yml.env 配置文件,項目目錄結構以下:

├── README.md         // 項目說明文檔
├── api                      // Restful api 後端服務
├── dashboard            // 前端頁面
├── .env                    // 騰訊雲相關鑑權參數:TENCENT_APP_ID,TENCENT_SECRET_ID,TENCENT_SECRET_KEY
└── serverless.yml    // serverless 文件

後端服務開發

進入目錄 api,新增 app.js 文件,編寫 express 服務代碼,這裏先新增一個路由 /,並返回當前服務器時間:

const express = require('express')
const cors = require('cors')
const app = express()

app.use(cors())
app.get('/', (req, res) => {
  res.send(JSON.stringfy({ message: `Server time: ${new Date().toString()}` }))
})
module.exports = app

前端頁面開發

本案例使用的是 Vue.js + Parcel 的前端模板,固然你可使用任何前端項目腳手架,好比 Vue.js 官方推薦的 Vue CLI 生成的項目。進入 dashboard 目錄,靜態資源你能夠直接複製我準備好的 項目模板,編寫入口文件 src/index.js:

// 這裏初始是沒有 env.js 模塊的,第一次部署後會自動生成
require('../env')

const Vue = require('vue')

module.exports = new Vue({
  el: '#root',
  data: {
    message: 'Click me!',
    isVisible: true,
  },
  methods: {
    async queryServer() {
      const response = await fetch(window.env.apiUrl)
      const result = await response.json()
      this.message = result.message
    },
  },
})

配置

先後端代碼都準備好了,如今咱們還須要簡單配置下 serverless.yml 文件了:

name: fullstack-application-vue

frontend:
  component: '@serverless/tencent-website'
  # inputs 爲 @serverless/tencent-website 組件的輸入
  # 具體配置說明參考:https://github.com/serverless-components/tencent-website/blob/master/docs/configure.md
  inputs:
    code:
      src: dist
      root: frontend
      hook: npm run build
    env:
      # 下面的 API服務部署後,獲取對應的 api 請求路徑
      apiUrl: ${api.url}

api:
  component: '@serverless/tencent-express'
  # inputs 爲 @serverless/tencent-express 組件的輸入
  # 具體配置說明參考:https://github.com/serverless-components/tencent-express/blob/master/docs/configure.md
  inputs:
    code: ./api
    functionName: fullstack-vue-api
    apigatewayConf:
      protocol: https
簡單的介紹下配置:首先,該文件定義了 frontendapi 兩個模塊,分別經過 component 屬性指定依賴的 Serverless Component。對於一個標準的 Serverless Component,都會接受一個 inputs 屬性參數,而後組件會根據 inputs 的配置進行處理和部署,具體有關配置的參數說明,請參考相關組件的官方配置說明。

部署

以上全部的步驟都完成後,接下來就是第一次部署了。

爲何不是直接聯調開發呢?由於後端服務是雲函數,可是到目前爲止,全部代碼都是在本地編寫,前端頁面接口請求連接還不存在。因此須要先將雲函數部署到雲端,才能進行先後端調試。這個也是本人目前遇到的痛點,由於每次修改後端服務後,都須要從新部署,而後進行前端開發調試。若是你有更好的建議,歡迎評論指教~

部署時,只須要運行 serverless 命令就行,固然若是你須要查看部署中的 DEBUG 信息,還須要加上 --debug 參數,以下:

$ serverless
# or
$ serverless --debug

而後終端會 balabalabala~, 輸出一大堆 DEBUG 信息,最後只須要看到綠色的 done 就好了:

Deploy Success Result

這樣一個基於 Serverless Component 的全棧應用就開發好了。趕忙點擊你部署好的連接體驗一下吧~

在線 Demo

數據庫鏈接

既然是全棧,怎麼少得了數據庫的讀寫呢?接下來介紹如何添加數據庫的讀寫操做。

準備

想要操做數據庫,必須先擁有一臺數據庫實例,騰訊雲 MySQL 雲數據庫 如今也很便宜,能夠購買一個最基本按量計費 1 核 1G 內存 的 1 小時收費不到 4 毛錢,是否是很是划算。購買好以後初始化配置,而後新增一個 serverless 數據庫,同時新增一張 users 表:

CREATE TABLE if not exists `test` ( `name` varchar (32) NOT NULL ,`email` varchar (64) NOT NULL ,`site` varchar (128) NOT NULL ) ENGINE = innodb DEFAULT CHARACTER SET = "utf8mb4" COLLATE = "utf8mb4_general_ci"

前端修改

首先修改前端入口文件 frontend/src/index.js 新增相關函數操做:

require('../env')

const Vue = require('vue')
const axios = require('axios')
module.exports = new Vue({
  el: '#root',
  data: {
    // ...
    form: {
      name: '',
      email: '',
      site: '',
    },
    userList: [],
  },
  methods: {
    // ...
    // 獲取用戶列表
    async getUsers() {
      const res = await axios.get(window.env.apiUrl + 'users')
      this.userList = (res.data && res.data.data) || []
    },
    // 新增一個用戶
    async addUser() {
      const data = this.form
      const res = await axios.post(window.env.apiUrl + 'users', data)
      console.log(res)
      if (res.data) {
        this.getUsers()
      }
    },
  },
  mounted() {
    // 視圖掛在後,獲取用戶列表
    this.getUsers()
  },
})

固然你還須要修改視圖模板文件 frontend/index.html,在頁面模板中新增用戶列表和用戶表單:

<!-- user form -->
<section class="user-form" action="#">
  <div class="form-item">
    <label for="name">
      Name:
    </label>
    <input name="name" v-model="form.name" type="text" /><br />
  </div>
  <div class="form-item">
    <label for="email">
      Email:
    </label>
    <input name="email" v-model="form.email" type="email" /><br />
  </div>
  <div class="form-item">
    <label for="site">
      Site:
    </label>
    <input name="site" v-model="form.site" type="text" /><br />
  </div>
  <button @click="addUser">Submit</button>
</section>

<!-- user list -->
<section class="user-list">
  <ul v-if="userList.length > 0">
    <li v-for="item in userList" :key="item.id">
      <p>
        <b>Name: {{ item.name }}</b>
        <b>Email: {{ item.email }}</b>
        <b>Site: {{ item.site }}</b>
      </p>
    </li>
  </ul>
  <span v-else>No Data</span>
</section>
注意:若是還不熟悉 Vue.js 語法,請移至 官方文檔,固然若是你想快速上手 Vue.js 開發,也能夠閱讀這份 Vue 從入門到精通 教程。

後端修改

這裏使用 .env 來進行數據庫鏈接參數配置,在 api 目錄下新增 .env 文件,將以前的數據庫配置填入文件中,參考 api/.env.example 文件。而後添加並安裝 dotenv 依賴,同時添加 mysql2 模塊進行數據庫操做,body-parser 模塊進行 POST 請求時的 body 解析。

以後新增後端 api,進行數據庫讀寫,修改後的 api/app.js 代碼以下:

'use strict'
require('dotenv').config()
const express = require('express')
const cors = require('cors')
const mysql = require('mysql2')
const bodyParser = require('body-parser')

// init mysql connection
function initMysqlPool() {
  const { DB_HOST, DB_PORT, DB_DATABASE, DB_USER, DB_PASSWORD } = process.env

  const promisePool = mysql
    .createPool({
      host: DB_HOST,
      user: DB_USER,
      port: DB_PORT,
      password: DB_PASSWORD,
      database: DB_DATABASE,
      connectionLimit: 1,
    })
    .promise()

  return promisePool
}

const app = express()
app.use(bodyParser.json())
app.use(cors())

if (!app.promisePool) {
  app.promisePool = initMysqlPool()
}

app.get('/', (req, res) => {
  res.send(JSON.stringify({ message: `Server time: ${new Date().toString()}` }))
})

// get user list
app.get('/users', async (req, res) => {
  const [data] = await app.promisePool.query('select * from users')
  res.send(
    JSON.stringify({
      data: data,
    })
  )
})

// add new user
app.post('/users', async (req, res) => {
  let result = ''
  try {
    const { name, email, site } = req.body
    const [res] = await app.promisePool.query('INSERT into users SET ?', {
      name: name,
      email: email,
      site: site,
    })
    result = {
      data: res && res.insertId,
      message: 'Insert Success',
    }
  } catch (e) {
    result = {
      data: e,
      message: 'Insert Fail',
    }
  }

  res.send(JSON.stringify(result))
})

module.exports = app

配置修改

這裏數據庫訪問須要經過騰訊雲私有網絡,因此還須要爲雲函數配置私有網絡(VPC),同時還須要配置可以操做數據庫的角色(關於角色配置,能夠直接到 角色管理頁面),這裏我新建了一個 QCS_SCFFull 的角色,能夠用來訪問數據庫。而後修改 serverless.yml 中的配置:

# ...
api:
  component: '@serverless/tencent-express'
  # more configuration for @serverless/tencent-website,
  # refer to: https://github.com/serverless-components/tencent-express/blob/master/docs/configure.md
  inputs:
    code: ./api
    functionName: fullstack-vue-api
    role: QCS_SCFFull # 此角色必須具有訪問數據庫權限
    functionConf:
      # 這個是用來訪問新建立數據庫的私有網絡,能夠在你的數據庫實例管理頁面查看
      vpcConfig:
        vpcId: vpc-6n5x55kb
        subnetId: subnet-4cvr91js
    apigatewayConf:
      protocol: https

最後從新部署一下就好了。

以上基於騰訊雲 Serverless Framework 來實現:

小結

固然全棧方案,並無這麼簡單,這裏只是簡單介紹,如何使用 Serverless Component,快速實現一個全棧應用。若是要應用到實際的業務場景,咱們還需考慮更多的問題,期待你們去探索和發現!

傳送門:

歡迎訪問:Serverless 中文網,您能夠在 最佳實踐 裏體驗更多關於 Serverless 應用的開發!


推薦閱讀: 《Serverless 架構:從原理、設計到項目實戰》
相關文章
相關標籤/搜索