基于 serverless 开发后端服务,前端项目部署在 serverless 上

  1. 目标:深入理解 serverless 的原理以及实战应用

serverless

serverless 基本介绍

  • 传统高并发架构(serverFull)

serverless技术架构 serverless 架构_devops

  • serverless:是无服务器架构思想,并非是说不依赖服务器,而是让开发者更多精力聚焦在业务代码,而无需关注服务器部署,负载均衡,数据存储,并发等一些列服务器问题。
  • serverless技术架构 serverless 架构_serverless_02

  • 直白的个人认知:
  1. 所谓的 serverless 即把传统 IT 架构方案,从线下完全抽象到云端,数字化配置即可。
  2. 把物理服务配置发展到线上可定制化的数据驱动服务。
  3. 从 devops 体系也发展成云端可集成运维方案
  4. 传统架构模式,要 控,容灾备份,高并发,弹性伸缩等等需求统统成为可配置,可数字化集成的线上技术。
  5. 说白了传统架构方案有的,serverless 全部基于云服务统统涵盖,甚至于基于云计算的实时感知,在降低风险,降低成本,提升效率等方面,目前处于最优方案。我们只需要关注代码,其余统统托管,只需要按量付费,便可实现弹性伸缩
  6. 初步可以理解为 faas 和 baas 的结合体:函数即 faas,服务即 baas
  7. 基本的开发/发布流程非常简洁

serverless 基本特点

  • serverless 核心特点:第三方平台,由事件触发,存在于无状态(stateless),暂存计算容器内(只存在于调用过程中 ),微服务,按量付费,弹性伸缩
  • serverless 相比传统 serverFull 特点
  1. 资源分配:
  • 无需关心项目运行时所需资源,如:磁盘大小,内存损耗以及其他服务配置
  1. 计费:
  • serverless 架构中,计费方式按照实际用量计费,如果函数调用次数,运行时常,精确到毫秒,有很多平台有免费额度,甚至有些访问量不大的中小项目,可以免费部署。
  1. 弹性伸缩:
  • 自动化,更精准的根据业务实际情况和发展趋势,用户无感知自动伸缩,极限状态甚至可以允许缩容为 0,那么费用即为 0

谁在用 serverless?

  • 中大厂基本人手一份

应用热度

serverless 的能力概述

  1. 计算能力
  1. 资源按需分配
  2. Mwm:租户级强镜隔离。Docker:进程级隔离
  3. Mwm+Docker:轻量级资源,毫秒级启动
  4. 实时无感知扩容/阶梯缩容
  5. 按需收费
  1. 系统运维能力
  1. 性能保障
  1. 整个链路耗时毫秒级,并支持 VPC(私有网络)内网访问
  1. 安全保障
  1. 资源对用户不可见,安全由托管方如(腾讯云)提供专业保障
  2. 提供进程级和用户级安全隔离
  3. 访问控制管理
  1. 自动性扩缩容
  1. 根据 CPU 和网络 io 的实际情况自动扩容底层资源
  2. 根据请求数量,自动扩缩函数实例,业务高峰扩容,满足并发需求,低峰缩容,释放资源,降低成本
  1. 自愈能力
  1. 确保每一次请求都是健康的函数实例
  1. 关于函数启动方式
  1. serverless 中函数被第一次调用会执行冷启动
  2. serverless 中函数被连续调用会执行热启动
  1. 冷启动:当该函数第一次被请求时,相当于在服务器中开辟一块空间去运行该函数实例,相当于把函数放到虚拟机中运行,每次运行就要先启动虚拟机,加载该函数。不过现在这个过程都是毫秒级,无需担心性能。只不过 session 在这个过程中有可能丢失,所以建议有一套针对 session 的存储策略
  2. 热启动:当该函数持续被调用时,那么第一次冷启动创建的函数实例将不会释放,下次请求由之前已创建的实例来运行。这个过程也类似于打开虚拟机之后运行完该函数,然后虚拟机待机,下回可以直接触发。这样省去冷启动的耗时的环节,但长期激活状态,相比而言系统开销就会更大一点。
  1. 业务运维能力
  1. devops 集成
  2. 错误收集,故障排查,警报监控等等
  3. vscode 插件,云 api,sdk 等等

serverless 服务商

  1. 亚马逊:https://aws.amazon.com/cn/lambda
  2. 谷歌: https://cloud.google.com/functions
  3. 微软:https://www.azure.cn
  4. 阿里:https://www.aliyun.com/product/fc
  5. 腾讯:h
  6. 华为:https://huaweicloud.com/product/functiongraph.html

怎么选服务商

  1. 优先国内服务,方便快速,文档友好
  2. 腾讯云和 serverless 合作开发集成 serverlessFramework,开发可选性强,兼容性好,部署成本低
  3. 当然,华为云和阿里云也很优秀

serverless 熟悉

  1. 线上https://console.cloud.tencent.com/scf 直接操作
  • 函数服务->新建->选模版->选类型:如 web(默认支持:http/https)
  1. serverless Freamwork
  • serverless freamwork 是由 serverless 公司推出的开源的 serverless 应用开发框架
  • 由 serverless freamwork plugin 和 serverless freamwork components 组成
  • serverless freamwork plugin 是个函数管理工具,使用该工具可以轻松部署,删除,触发,回滚函数,也可以查看函数日志,函数信息,函数数据等等。
  • serverless freamwork components 是个组件集,包含各类组件比如:cos,scf,apigateway。还有各种扩展组件,如从 cos 扩展而来的 website 用于部署静态网站,还有其他的框架级组建如 express,koa 等等
  • 详情:https://cn.serverless.com/

serverless 开发环境实操

  • webcli 方式-不推荐
  • https://console.cloud.tencent.com/sls 到这浪
  • 基于 vscode 插件开发云函数 Tencent Serverless Toolkit for VS Code(当然其他的比如阿里也有对应的插件)
  • Tencent Serverless Toolkit for VS Code:是腾讯 serverless 产品 vscode 的插件,该插件可以让你在本地运行 serverless 项目并且可以轻松部署到云端
  • 搜索该插件-安装你就会用了
  • 注意修改本地配置文件「path:/」,不然代码直接部署会访问不到
  • serverless cli (freamwork)- 推荐
  • npm install -g serverless 安装
  • sererless -v 看下版本
  • 初始化 serverless 项目命令:
  • 使用模板创建 serverless 应用并指定名称(此处以 express 为例,至于你想要哪种:serverless)
  • serverless init express-starter --name 项目名称
  • sls init express-starter --name 项目名称
  • 部署:serverless deploy
  • 访问函数,完事
  • 本地调试:node app.js 或者 nodemon app.js 本地运行即可

配置静态 web 服务

提高发布速度,部署自动安装依赖:node_modules(看个人习惯)

  • serverless.yml
  • 配置 exclude
exclude:
      - .env
      - node_modules // 发布是排除该文件夹就会提升发布速度,部署需要到服务器上开启部署安装依赖,手动部署
  1. express 模版静态服务
// 静态web服务
app.use(express.static("website"));
  1. express 配置 ejs 模版引擎
  • 安装 ejs 模版引擎
  • npm i ejs --save
  • 配置引擎
const ejs = require("ejs");
// 配置ejs模版引擎,默认读取根目录下views中的html
app.engine("html", ejs.__express);
app.set("view engine", "html");
  • 渲染数据
app.get(`/`, (req, res) => {
  // res.sendFile(path.join(__dirname, "index.html"));
  res.render("index", {
    // views下的index渲染title
    title: "你大爷",
  });
});
<!-- 通过ejs渲染 -->
<body>
  引擎<%=title%>
</body>
  1. koa 模版静态服务
const static = require("koa-static");
app.use(static("website"));
  1. serverless 部署 eggjs
const config=export={
   env:'prod',
   rundir:'/tmp',
   logger:{
      dir:'/tmp'
   }
}

部署前端项目(基于对象存储)

  1. vue2.0 项目发布
  • serverless init vue-starter --name 项目名称
  • 初始化项目
  • serverless deploy
  • 先在根目录打包出 dist,接着部署到服务器
  • 对象存储-存储桶列表即可查看,列表名称可以通过:yml 文件 bucketName 进行修改
  • 比如 http/https 的问题可以在 yml 中配置,也可以在对象存储-存储桶列表-基础配置-静态网站中修改
  • 比如 错误页默认走 serverless 自带的 error 页面,可以在对象存储-存储桶列表-基础配置-静态网站中修改,改成 index,使用项目的静态路由
  • 关于编译命令和发布包的名称设定在 yml 配置
  1. 部署 vue3.0
  • 简单,把命令生成的脚手架内容全部删掉,只保留 yml 文件,然后把你的项目复制进来即可
  1. 部署 react
  • 步骤与上面一致
  1. 部署 angular

serverless 中 node 配置 mysql,mongodb,私有网络(vpc)

  1. 操作 mysql
  • 注意点
  • 局域网部署要求:云数据库在选择时,选择区域时与当前 serlveless 服务器已在一个区域比如都在上海,以应对 VPC 服务部署的需求
  • 直接函数服务-新建模板-mysql-选择 node 版本,如果需要局域网就记得选择局域网,如果没有则需要新建局域网
  • 新建 mysql/或者数据库集群,开放公网/vpc,如果开放 vpc 选择你之前的新建的局域网,同时开放公网和局域网
  • 如果想通过 api 方式调接口,回到函数服务,创建触发器,通过 api 访问即可
  • 回到函数服务选择 node-mysql 实例,index.js 连接数据库
exports.main_handler = async (event, context, callback) => {
  const mysql = require("mysql");
  const connection = mysql.createConnection({
    host: "集群/数据库公网地址", // The ip address of cloud database instance, 云数据库实例ip地址
    user: "账号名", // The name of cloud database, for example, root, 云数据库用户名,如root
    password: "数据库密码", // Password of cloud database, 云数据库密码
    database: "链接数据库", // Name of the cloud database, 数据库名称
    port: 端口号,
  });
  // 链接数据库
  connection.connect();
  // 测试sql
  const querySql = `SELECT * from users`;
  let queryResult = await wrapPromise(connection, querySql);
  connection.end();
  return queryResult;
};
  • vpc 访问(更快 )
  • 云函数和数据库的区域必须保持一致
  • 去数据/集群复制私有网络的 IP/端口,去函数服务 index 中替换即可
  1. mongodb 配置
  • 其实一样,选择 mongodb 示例
  • 新建 mongodb 数据库
  • 链接方式大同小异

COS 对象存储

  • 对象存储(cloud object storage),存储海量文件的“分布式存储服务”
  • 优点:高可扩展,低成本,可靠安全
  • 通过控制台,api,skd 以及工具等轻松接入 cos,进行多格式文件进行,上传,下载,管理,实现海量文件存储管理
  • 基础操作: https://cloud.tencent.com/document/product/436/8629

实操

  1. 创建 demo 文件夹,mkdir node-cos
  2. 初始化 npm 环境,npm init --yes
  3. 新建 app.js,touch app.js
  4. npm i cos-nodejs-sdk-v5 --save

app.js 配置 cos

// SECRETID 和 SECRETKEY请登录 https://console.cloud.tencent.com/cam/capi 进行查看和管理
var COS = require("cos-nodejs-sdk-v5");
var cos = new COS({
  SecretId: "你自己的SecretId",
  SecretKey: "你自己SecretKey",
});

对象存储/对象存储列表,创建存储容器

  • 创建完成后返回存储列表

配置上传

cos.putObject(
  {
    Bucket: "file-storage-test-1314081338" /* 存储桶名称 */,
    Region: "ap-guangzhou" /* 所属地域 */,
    Key: "./imgs/" /* 目录或者指定文件名称 */,
    StorageClass: "STANDARD",
    Body: fs.createReadStream("./imgs/test.jpeg"), // 上传文件路径
    onProgress: function (progressData) {
      console.log(JSON.stringify(progressData));
    },
  },
  function (err, data) {
    console.log(err || data);
  }
);

// 执行node app.js,打开存储桶,对应文件夹即可看到上传资料

serverless 应用中实现 cos 上传

  1. express
  • 基于 body-parser 解析 body 资源,可用过 req.body 获取表单资源
  • pnpm install body-parser -S
  • 安装 multer 图片上传插件
  • pnpm install multer -S
  • 如果是页面 form 需要配置 enctype=“multipart/form-data”
  • 配置内存存储引擎,将文件存储在内存中保存一份 buffer(备上传)
  • 拿到 buffer 存储到云端
  • 安装 cos 插件
  • pnpm i cos-nodejs-sdk-v5 --save
  • 添加对应配置项
// app.js
const { uploadImg } = require("./cos.config");
// 上传图片插件
const multer = require("multer");
// 解析body插件
const bodyParser = require("body-parser");
// 配置body-parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 配置图片上传插件
const storage = multer.memoryStorage();
const uploadCloud = multer({ storage });
// 上传方法
// single()内的参数必须跟提交过来的字段名保持一致
app.post("/uploadFile", uploadCloud.single("avatar"), (req, res) => {
  console.log("提交过来的文件", req.body, req.file);
  uploadImg(req, res);
});
  • 封装 cos.config.js
var COS = require("cos-nodejs-sdk-v5");
const fs = require("fs");
var cos = new COS({
  SecretId: "你自己的id",
  SecretKey: "你自己的key",
});

const uploadImg = (req, res) => {
  // 上传
  cos.putObject(
    {
      Bucket: "file-storage-test-1314081338" /* 存储桶名称 */,
      Region: "ap-guangzhou" /* 所属地域 */,
      Key:
        "./imgs/" +
        Date.now() +
        "-" +
        req.file.originalname /* 目录或者指定文件名称 */,
      StorageClass: "STANDARD",
      Body: req.file.buffer, // 上传文件对象
      onProgress: function (progressData) {
        console.log(JSON.stringify(progressData));
        res.send(res.send(req.body));
      },
    },
    function (err, data) {
      console.log(err || data);
    }
  );
};

module.exports = {
  uploadImg,
};
  • 发布线上并测试
  • 如果图片上传失败,去 serverless.yml 中查看一下网关
apigw:
    # isBase64Encoded: true

serverless 中配置域名来访问应用和存储资源(私有备案中,待补充)

  • 域名解析
  • 注册域名
  • 将域名解析指定 serverless 服务
  • 自定义域名:自定义路径映射
  • 使用 HTTPS
  • 安装证书:腾讯云搜索:ssl,去购买“免费版 ”
  • 输入绑定域名