• 更灵活的 serverless framework 配置文件


    bg

    更灵活的 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"
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5

    但是随着项目的日益复杂,你会发现使用 CLI 命令,不断的去增加配置项,这种方式既繁琐,又效率低下,有什么方式可以用一个变量去控制大量的配置呢?

    serverless framework里,通常我们可以使用 动态变量 的方式去解决这个问题。

    动态变量

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

    ${variableSource}
    ${sls:stage}-lambdaName
    ${env:MY_API_KEY}
    ${file(create_request.json)}
    ${self:service}:${sls:stage}:UsersTableArn
    
    • 1
    • 2
    • 3
    • 4
    • 5

    serverless.yml 支持使用上述变量的方式,来实现配置的引用与读取,它们是非常有用的,毕竟你不可能把某些配置项,诸如 secret 什么的直接 inline 写在 yml 文件里。

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

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

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

    self

    首先必须要讲的就是 self 了,它是我们应用配置自身其他值的关键,self 指向的就是我们 yml 配置的根节点。这里我给出一个示例,相信聪明的你可以一眼看出它的用法。

    service: new-service
    provider: aws
    custom:
      globalSchedule: rate(10 minutes)
      # 引用的第一行 service: new-service
      serviceName: ${self:service}
      # 引用的上一行 serviceName: ${self:service}
      exportName: ${self:custom.serviceName}-export
    
    functions:
      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}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    env

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

    service: new-service
    provider: aws
    functions:
      hello:
        name: ${env:FUNC_PREFIX}-hello
        handler: handler.hello
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这个一般配合 dotenv 等工具比较好用。

    sls

    这个变量可以获取一些 Serverless Core 值,比如 instanceIdstage,用例如下

    service: new-service
    provider: aws
     
    functions:
      func1:
        name: function-1
        handler: handler.func1
        environment:
          APIG_DEPLOYMENT_ID: ApiGatewayDeployment${sls:instanceId}
          STAGE: ${sls:stage}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    opt

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

    service: new-service
    provider: aws
    functions:
      hello:
        name: ${opt:stage}-hello
        handler: handler.hello
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这时候它就会根据我们传入的 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'
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    我们可以在里面获取到其他的变量,并进行额外的计算处理,或者我们可以在这里请求远端获取数据作为部署的额外配置。

    更多

    除此之外,它还能引用到更多服务的变量,诸如 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    当然由于它是 nodejs 运行时的缘故,你可以把配置文件拆分成多个文件,再使用 commonjs 原生的方式去引用它们。你也可以使用环境变量,node:fsnode:path 等等模块去按条件动态去生成配置文件,甚至使用某些第三方库做一些额外的工作,这实在是太灵活了!

    Next Chapter

    现在你已经浅尝辄止了 serverless framework 动态配置文件。

    下一篇,《与传统 nodejs web 框架的结合》中,将会详细介绍如何部署 express/koa 和以它们2个为基底的 serverless 应用,欢迎阅读。

    完整示例及文章仓库地址

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

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

  • 相关阅读:
    QProcess 调用 ffmpeg来处理音频
    React——相关js库以及使用React开发者工具调试
    Java基本数据类型
    avec2013数据集谁有吗?可以分享一下吗?跪求
    Servlet—servlet两种配置方式
    Python库使用说明
    SQL之join的简单用法
    Unity fbx动画压缩自动化
    Springboot 使用 Mybatis Plus LambdaQueryWrapper 构造器和注解自定义SQL
    宠物狗之家
  • 原文地址:https://blog.csdn.net/qq_33020601/article/details/132764831