ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(信用就像一面镜子,只要有了裂缝就不能像原来那样连成一片。——(瑞士)阿米尔)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
serverless被称为无服务运算,依托于云厂商,用户不需要关注服务器,网关和数据库等配置,让用户更专注业务。至于这些服务器,数据库等配置项全部由云厂商托管
更直白的说,用户不需要再关心服务器,数据库,证书,负载均衡等的复杂运维配置,也不用担心服务的扩容和伸缩,这些都交给云厂商来做。用户只需要开发代码,一键部署即可
本地部署
基础设施即服务(IaaS)
容器即服务(CaaS)
平台即服务(PaaS)
函数即服务(FaaS)
无服务器架构
控制台
原生资源编排服务/软件
第三方资源编排框架
传统开发模式下,同样从0-1需要15-30天的时间。但在serverless下,依托于云厂商提供的平台,用户不再需要进行繁琐的配置,极大的缩短了运维时间。
资费上serverless也更有优势,传统服务器在没有用户使用的情况下也依然会产生费用,但serverless的按需收费,将会用多少收多少钱,更加的节约成本
下面用AWS亚马逊云进行演示
前提
假设你已经拥有aws账户
假设你已经配置好了aws基本环境

假设你对linux命令有一定的了解
假设你对nodejs,npm有基本的认识
Serverless Farmework官网
Serverless Farmework代码仓库 百分之90以上使用js实现
serverless脚本命令框架,它并不是传统的服务框架。只需要在你本地定义serverless.(.ts/.yml等)配置文件,再通过serverless脚本命令,就可以将你的服务快速的配置,部署到云厂商
目前它支持亚马逊,阿里,腾讯,谷歌等主流的云厂商
Serverless支持的云厂商图谱
npm install -g serverless
验证是否安装成功
serverless help

使用serverless命令,根据引导生成你的服务目录
serverless
Creating a new serverless project
? What do you want to make? (Use arrow keys)
❯ AWS - Node.js - Starter
AWS - Node.js - HTTP API
AWS - Node.js - Scheduled Task
AWS - Node.js - SQS Worker
AWS - Node.js - Express API
AWS - Node.js - Express API with DynamoDB
AWS - Python - Starter
AWS - Python - HTTP API
AWS - Python - Scheduled Task
AWS - Python - SQS Worker
AWS - Python - Flask API
AWS - Python - Flask API with DynamoDB
Other
// 初始化新的serverless服务
serverless
// 发布应用程序
// -s aws环境变量 在nodejs中使用process.env.STAGE获取
// --aws-profile 可能存在多个环境问题,所以需要指定配置文件
serverless deploy -s dev --aws-profile dev
// 本地模拟serverless的模式进行调试 需要安装serverless-offline的npm包
serverless offline -s dev --aws-profile dev
// 查看服务调用日志
serverless logs -f hello --tail
接下来使用dynamodb数据库,s3文件系统来实现基本的数据和文件的增删改查
前提
初始化dynamodb数据库
const { Lambda, DynamoDB } = require('aws-sdk');
const dynammoose = require('dynamoose');
const dayjs = require('dayjs');
// aws链接配置
const dynamodbAwsConf = {
// aws凭证id 非必填 默认使用default
accessKeyId: 'xxx',
// aws凭证key 非必填 默认使用default
secretAccessKey: 'xxx',
// 使用中国-宁夏地区
region: 'cn-northwest-1'
};
// 初始化dynamodb数据库
const dynamodb = new DynamoDB(dynamodbAwsConf);
// 初始化dynamoose
const db = new dynammoose.aws.sdk.DynamoDB(dynamodbAwsConf);
dynammoose.aws.ddb.set(db);
// 定义数据库表
const table = 'test_dynamodb';
// 定义数据库模型
// 其中id是主键 pid是排序键也是范围键
const dynamodbModel = dynammoose.model(table, {
id: {
type: String,
hashKey: true
},
pid: {
type: String,
rangeKey: true
},
name: String,
email: String,
mobile: String,
nickName: String,
});
初始化s3对象存储
const aws = require('aws-sdk');
// aws的s3桶配置
const s3AwsConf = {
// 使用中国-宁夏地区
region: 'cn-northwest-1',
s3ForcePathStyle: true,
// aws凭证id 非必填 默认使用default
accessKeyId: "xxx",
// aws凭证key 非必填 默认使用default
secretAccessKey: "xxx",
};
// 初始化s3桶
const s3 = new aws.S3(s3AwsConf);
数据库增删改查
const uuid = require('uuid');
// 创建
module.exports.testCreate = async (event) => {
const obj = JSON.parse(event.body);
const { _id, name, email, mobile, nickName } = obj;
let lastId = _id ?? uuid.v4();
const data = {
id: lastId,
pid: uuid.v4(),
name,
email,
mobile,
nickName
};
await dynamodbModel.create(data);
return {
code: 200,
message: 'success',
data
};
};
// 更新
module.exports.tetsUpdate = async (event) => {
const obj = JSON.parse(event.body);
const filter = { id: obj.id, pid: obj.pid };
const update = {
name: obj.name,
email: obj.email,
mobile: obj.mobile,
nickName: obj.nickName
};
const data = await dynamodbModel.update(filter, update);
return {
code: 200,
message: 'success',
data
};
};
// 删除
module.exports.testDel = async (event) => {
const obj = event.pathParameters;
const filter = { id: obj.id, pid: obj.pid };
const data = await dynamodbModel.delete(filter);
return {
code: 200,
message: 'success',
data
};
};
// 查询
module.exports.testGet = async (event) => {
const obj = JSON.parse(event.body);
const data = await dynamodbModel.query({ pid: 'ed5c6f8c-c31f-44a4-9968-bc9437d6d7c4' }).exec();
const get = await dynamodbModel.get({ id: 'f279b477-9a32-4548-8bbe-35a2afb11c8b', pid: 'ed5c6f8c-c31f-44a4-9968-bc9437d6d7c4' });
return {
code: 200,
data,
get
}
};
s3文件系统保存,删除,查询和上传
// 保存文件
module.exports.testS3Put = async (event) => {
const obj = JSON.parse(event.body);
const param = {
Key: obj.key,
Body: Buffer.from(JSON.stringify(obj)),
Bucket: obj.bucket,
};
const data = await s3.putObject(param).promise();
return {
code: 200,
data
};
};
// 根据url上传文件
module.exports.testS3Upload = async (event) => {
const obj = JSON.parse(event.body);
const body = obj.body;
const url = obj.url;
await axios.default.put(url, body);
return {
code: 200
};
}
// 获取文件
module.exports.testS3Get = async (event) => {
const obj = JSON.parse(event.body);
const stage = process.env.STAGE;
const param = {
Key: obj.bucketKey,
Bucket: `${stage}-bucket`,
};
const data = await s3.getObject(param).promise();
const body = data.Body;
const resData = Buffer.from(body, 'utf-8').toString();
return {
code: 200,
data: resData
};
}
服务间lambda函数调用
module.exports.testLambda = async (event) => {
// 发送lambda函数事件 服务间调用
// https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/API_Invoke.html
const invokeParam = {
FunctionName: 'project-service-dev',
InvocationType: 'RequestResponse',
Payload: {
"method": "budget",
"payload": {
"action": "create",
"userID": "62e4df570be7ae89e307671d",
"projectID": "1246e309-1598-4784-9036-cec91da37504"
}
}
};
const lambda = new Lambda({
accessKeyId: 'xxx',
secretAccessKey: 'xxx',
region: 'cn-northwest-1'
});
const result = await lambda.invoke(invokeParam).promise();
console.log('result', JSON.parse(result.Payload));
}
现在我们业务代码开完完毕,但想要调试或者发布还需要配置serverless,它可以控制我们的访问,配置,权限等等
代码示例中的表已经手动创建好,serverless配置中仅用于演示
service: aws-node-project # 服务名称
frameworkVersion: "3" # 本地serverless框架版本
plugins: # 配置插件
- serverless-offline
provider: # 服务基本配置
name: aws # 云厂商名称
runtime: nodejs14.x # 运行时
region: cn-northwest-1 # 地区
profile: default # 配置文件所属环境
environment: # 环境变量
DYNAMODB_CUSTOMER_TABLE: ${self:service}-customerTable-${sls:stage}
STAGE: ${sls:stage}
iam: # aws iam角色
role: # 角色名称
statements: # 角色策略
- Effect: "Allow" # 允许任何操作
Action:
- "dynamodb:PutItem"
- "dynamodb:Get*"
- "dynamodb:Scan*"
- "dynamodb:UpdateItem"
- "dynamodb:DeleteItem"
Resource: arn:aws-cn:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
custom: # 配置插件环境
serverless-offline:
lambdaPort: 5003 # serverless函数端口
httpPort: 5004 # http端口
resources: # 数据源
Resources: # 资源项
CustomerTable: # 资源名称
Type: AWS::DynamoDB::Table # 资源类型
Properties: # 资源属性
AttributeDefinitions: # 表结构
- AttributeName: primary_key # 字段名
AttributeType: S # 字段类型
BillingMode: PAY_PER_REQUEST # 表的收费模式 按量收费
KeySchema: # 表主键,排序键设置
- AttributeName: primary_key # key名称
KeyType: HASH # 主键
TableName: ${self:service}-customerTable-${sls:stage} # 表名 这里用到的模板语法符合aws规则
CustomerS3:
Type: AWS::S3::Bucket
Properties:
BucketName: local-bucket # s3桶名称
functions: # 配置函数入口
testGet: # 函数名称
handler: dev/handler.js.testGet # 函数访问路径
events: # 事件
- httpApi: # 事件类型
path: /test/get # http访问路径
method: post # http访问类型
testCreate:
handler: dev/handler.js.testCreate
events:
- httpApi:
path: /test/create
method: post
testUpdate:
handler: dev/handler.js.tetsUpdate
events:
- httpApi:
path: /test/update
method: put
testDel:
handler: dev/handler.js.testDel
events:
- httpApi:
path: /test/delete/{id}/{pid}
method: delete
testS3Put:
handler: dev/handler.js.testS3Put
events:
- httpApi:
path: /test/s3/put
method: post
testS3Upload:
handler: dev/handler.js.testS3Upload
events:
- httpApi:
path: /test/s3/upload
method: put
testS3Get:
handler: dev/handler.js.testS3Get
events:
- httpApi:
path: /test/s3/get
method: post
testLambda:
handler: dev/handler.js.testLambda
events:
- httpApi:
path: /test/s3/lambda
method: post
// 本地调试
serverless offline -s dev --aws-profile dev
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Serverless",
"runtimeExecutable": "node",
"program": "C:\\Users\\17319\\AppData\\Roaming\\npm\\node_modules\\serverless\\bin\\serverless",
"args": [
"offline",
"start",
"-s",
"local",
"--noTimeout",
"--aws-profile",
"local"
],
"protocol": "inspector",
"env": {
"tableName": "player-points"
},
"windows": {
"program": "C:\\Users\\17319\\AppData\\Roaming\\npm\\node_modules\\serverless\\bin\\serverless"
}
}
]
}