更灵便的 serverless framework 配置文件

前言

再通过前置教程的部署之后,不晓得你有没有留神这样一个问题,就是咱们部署的函数名,以及 API网关endpoint,它们的名称和门路都带一个 dev?

这个就是 stage 导致的了,咱们执行 sls deploy 部署的时候,因为没有指定 --stage 的参数,导致它默认就是 dev,所以咱们之前部署的函数名称,网关外面都带它。

那么它有什么作用呢?实际上这个值就是用来给你的函数,以及对应的服务去辨别阶段/环境的。

比方咱们一个提供 web 服务的函数,咱们本人人为划分出三个环境:

  1. dev 用于给开发者自行测试
  2. sit 用于进行集成测试
  3. prod 生产环境

不同的环境,它们各自的 API网关 调配的 endpoint 也是不同的。

如果你有一个域名,你就能够把域名多配置一些主或多级域名,把它们的 CNAME 解析到指定的 API网关 地址来应用。当然你仅仅在域名控制台,间接解析是不失效的,因为API网关有个双重验证,你必须进入API网关自定义域名界面,创立自定义域名,并绑定 ACM 证书,审核通过后解析能力失效。

什么是 ACM证书ACM残缺名称为Amazon Certificate Manager,点击这里查看更多

释怀,ACM 证书 申请和颁发非常简单,它的性能和申请流程和咱们申请收费的 SSL/TLS 证书是统一的,都是咱们域名多解析一个 CNAME的事件。

这时候咱们天然能够利用 cli option 去设置:

"scripts": {  "deploy:dev": "sls deploy",  "deploy:sit": "sls deploy -s sit",  "deploy:prod": "sls deploy -s prod"},

然而随着我的项目的日益简单,你会发现应用 CLI 命令,一直的去减少配置项,这种形式既繁琐,又效率低下,有什么形式能够用一个变量去管制大量的配置呢?

<!-- 一般的 nodejs 我的项目咱们通常会想到 dotenv,侥幸的是,serverless framework 同时也给咱们提供了更多的抉择。 -->
serverless framework里,通常咱们能够应用 动静变量 的形式去解决这个问题。

动静变量

什么是动静变量?实际上它们就是非凡写法的字符串罢了。变量常见的写法如下所示:

${variableSource}${sls:stage}-lambdaName${env:MY_API_KEY}${file(create_request.json)}${self:service}:${sls:stage}:UsersTableArn

serverless.yml 反对应用上述变量的形式,来实现配置的援用与读取,它们是十分有用的,毕竟你不可能把某些配置项,诸如 secret 什么的间接 inline 写在 yml 文件里。

其中 ${} 就是变量援用的写法,会在 sls cli 运行的时候,把它们替换成真正的值。

# ${} 第二个参数是默认值otherYamlKey: ${variableSource, defaultValue}

这里介绍一些罕用的变量:

self

首先必须要讲的就是 self 了,它是咱们利用配置本身其余值的要害,self 指向的就是咱们 yml 配置的根节点。这里我给出一个示例,置信聪慧的你能够一眼看出它的用法。

service: new-serviceprovider: awscustom:  globalSchedule: rate(10 minutes)  # 援用的第一行 service: new-service  serviceName: ${self:service}  # 援用的上一行 serviceName: ${self:service}  exportName: ${self:custom.serviceName}-exportfunctions:  hello:    handler: handler.hello    events:      # ${self:someProperty}       # self 指向的就是 yml 配置的根节点,所以能力       - schedule: ${self:custom.globalSchedule}resources:  Outputs:    NewServiceExport:      Value: 'A Value To Export'      Export:        Name: ${self:custom.exportName}

env

顾名思义,应用系统配置的环境变量:

service: new-serviceprovider: awsfunctions:  hello:    name: ${env:FUNC_PREFIX}-hello    handler: handler.hello

这个个别配合 dotenv 等工具比拟好用。

sls

这个变量能够获取一些 Serverless Core 值,比方 instanceIdstage,用例如下

service: new-serviceprovider: aws functions:  func1:    name: function-1    handler: handler.func1    environment:      APIG_DEPLOYMENT_ID: ApiGatewayDeployment${sls:instanceId}      STAGE: ${sls:stage}

其中 ${sls:stage} 指令的本质实际上是 ${opt:stage, self:provider.stage, "dev"} 的缩写模式,所以你也明确为什么默认值是 dev 了。

opt

这个变量就是去取 CLI 传入的 Options 外面的值:

service: new-serviceprovider: awsfunctions:  hello:    name: ${opt:stage}-hello    handler: handler.hello

file

模块化配置的外围办法/变量,应用这个变量办法能够去读取文件,并进行援用,例如咱们能够在这里引入另外的 yml,json,js文件:

# 你甚至能够引入整个yml文件作为配置custom: ${file(./myCustomFile.yml)}provider:  name: aws  environment:    # 引入 json 文件    MY_SECRET: ${file(./config.${opt:stage, 'dev'}.json):CREDS} functions:  hello:    handler: handler.hello    events:      - schedule: ${file(./myCustomFile.yml):globalSchedule} # Or you can reference a specific property  world:    handler: handler.world    events:      # 甚至能够引入 `js` 文件      - schedule: ${file(./scheduleConfig.js):rate}

这时候它就会依据咱们传入的 stage 参数,去读取相对路径下不同的配置文件了。

其中引入 js 文件的代码有肯定的限度,它必须是 commonjs 格局,且必须导出一个js对象,或者是导出一个function。导出对象形式很简略且泛用性不强,咱们这里以办法为例:

// 目前必须是 commonjs 格局,且返回一个对象作为值// 办法同步/异步的都能够module.exports = async ({ options, resolveVariable }) => {  // We can resolve other variables via `resolveVariable`  const stage = await resolveVariable('sls:stage');  const region = await resolveVariable('opt:region, self:provider.region, "us-east-1"');  ...   // Resolver may return any JSON value (null, boolean, string, number, array or plain object)  return {    prop1: 'someValue',    prop2: 'someOther value'  }}

咱们能够在外面获取到其余的变量,并进行额定的计算解决,或者咱们能够在这里申请远端获取数据作为部署的额定配置。

更多

除此之外,它还能援用到更多服务的变量,诸如 CloudFormation,S3SSM 等等服务,更多更全面的变量详见:官网的变量大全地址

配置反对的其余格局

实际上目前的 serverless cli 不止能够承受 serverless.yml,也能够承受包含 serverless.ts, serverless.json, serverless.js 格局。

这里笔者只举荐两种格局 serverless.ymlserverless.js

为什么不是 serverless.json?因为 json 文件表现力弱,甚至要 jsonc 才反对正文,所以放弃。

为什么不是 serverless.ts,因为间接应用会出错,详见 issues/48,不够省心。这点不如应用 js + jsdoc 的组合,智能提醒有了,灵活性也有了。

所以咱们总结一下 serverless.ymlserverless.js 的长处:

  • serverless.yml: 足够简略,配合动静变量比拟灵便
  • serverless.js: 能够应用 nodejs api,也能够配合动静变量,更加灵便,而且配置能够应用原生 js 写法。

这里咱们以 serverless.js 配置文件为例:

智能提醒, 须要 npm i -D @serverless/typescript
/** * @typedef {import('@serverless/typescript').AWS} AWS * @type {AWS} */const serverlessConfiguration = {  service: 'aws-node-ts-hello-world',  frameworkVersion: '3',  provider: {    // ...  },  functions: {    // ...  },}module.exports = serverlessConfiguration

当然因为它是 nodejs 运行时的缘故,你能够把配置文件拆分成多个文件,再应用 commonjs 原生的形式去援用它们。你也能够应用环境变量,node:fsnode:path 等等模块去按条件动静去生成配置文件,甚至应用某些第三方库做一些额定的工作,这切实是太灵便了!

Next Chapter

当初你曾经浅尝辄止了 serverless framework 动静配置文件。

下一篇,《与传统 nodejs web 框架的联合》中,将会具体介绍如何部署 express/koa 和以它们2个为基底的 serverless 利用,欢送浏览。

残缺示例及文章仓库地址

https://github.com/sonofmagic/serverless-aws-cn-guide

如果你遇到什么问题,或者发现什么勘误,欢送提 issue 给我