由于企业内部管理的需要,用到了钉钉的业务事件回调能力,正好将这个轻量级的接口使用无服务器技术来实现部署,以应对流量无规律下的动态扩展伸缩、按需使用、按量计费等需求。
阿里云函数计算版本
由于公司系统部署在阿里云,首先选择使用阿里云函数计算来实现及部署。该接口使用了JVM上语言Kotlin开发,虽然阿里云函数计算官方支持的开发语言有Java但没有Kotlin。其实无论Java或Kotlin最终部署文件都是Java Class字节码,加上Kotlin与Java良好的互操作性,实测函数计算可以完美支持Kotlin开发(个人认为任意JVM上的开发语言都是支持的)。
同时该函数使用了表格存储来持久化回调事件。表格存储是个按量计费的分布式存储,有兴趣的可以自行查阅文档了解更多。
该函数通过API网关和表格存储触发器来触发。访问日志和执行日志被存储在日志服务中。
函数的本地测试和线上部署,使用了函数计算提供的命令行工具Fun。基于Fun定义的阿里云Serverless模型实现了对函数们使用资源的声明和编排,集成Gitlab CI实现了函数的CI/CD自动化发布流程。
不涉及公司业务的代码已开源在Github,有兴趣的可以作为参考。
目前函数计算和表格存储有各自的免费配额,在业务量不大的情况下,该服务完全免费。
AWS Lambda版本
AWS Lambda是目前全球使用最为广泛的serverless服务,同时也是函数计算发展方向的引领者。
由于一些个人原因,笔者最近接触了部分AWS服务,同时尝试将钉钉回调函数移植到了AWS Lambda上。阿里云上使用的云服务改为由AWS上对应服务来实现,例如存储使用了DynamoDB,日志使用CloudWatch收集和查询。
本地测试和部署工具,使用的是SAM CLI,持续集成和持续部署使用的是AWS CodeBuild和AWS CodePipeline。此外AWS通过AWS CloudFormation提供一种非常强大的能力,可以将AWS上的各种资源通过配置声明的方式来管理(也就是现在非常热门的一个概念--Infrastructure as Code)。AWS CloudFormation会为每次一个或多个资源的变更生成ChangeSet,提供查看对比、版本管理、遇到变更错误整体回退等能力。所以,AWS版本也将该项目的CI/CD部署用到的AWS CodeBuild、AWS CodePipeline、Amazon DynamoDB等资源通过CloudFormation的配置管理起来。
配置代码段如下,
Description: Create a CodePipeline to include Github source, CodeBuild and Lambda deployment.
Parameters:
AppBaseName:
Type: String
Description: App base name
Default: dingtalk-callback
ArtifactStoreS3Location:
Type: String
Description: Name of the S3 bucket to store CodePipeline artificat.
BranchName:
Description: GitHub branch name
Type: String
Default: master
RepositoryName:
Description: GitHub repository name
Type: String
Default: dingtalk-callback-on-aws
GitHubOAuthToken:
Type: String
NoEcho: true
Resources:
BuildDingtalkProject:
Type: AWS::CodeBuild::Project
Properties:
Name:
Fn::Sub: ${AppBaseName}-build-${AWS::StackName}
Description: Build, test, package dingtalk callback project
ServiceRole:
Fn::GetAtt: [ CodeBuildRole, Arn ]
Artifacts:
Type: S3
Location:
Ref: ArtifactStoreS3Location
Name:
Fn::Sub: ${AppBaseName}-build-${AWS::StackName}
NamespaceType: BUILD_ID
Path:
Fn::Sub: ${AppBaseName}/artifacts
Packaging: NONE
OverrideArtifactName: true
EncryptionDisabled: true
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/java:openjdk-11
PrivilegedMode: false
ImagePullCredentialsType: CODEBUILD
EnvironmentVariables:
- Name: s3_bucket
Value:
Ref: ArtifactStoreS3Location
Source:
DingtalkCallbackPipeline:
Type: 'AWS::CodePipeline::Pipeline'
Properties:
Name:
Fn::Sub: ${AppBaseName}-pipeline-${AWS::StackName}
RoleArn:
Fn::GetAtt: [ CodePipelineRole, Arn ]
Stages:
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: 1
Provider: GitHub
OutputArtifacts:
- Name:
Fn::Sub: ${AppBaseName}-source-changed
Configuration:
Owner: !Ref GitHubOwner
Repo: !Ref RepositoryName
Branch: !Ref BranchName
OAuthToken: !Ref GitHubOAuthToken
PollForSourceChanges: false
RunOrder: 1
- Name: Build
Actions:
- Name: Build_Test_Package
InputArtifacts:
- Name:
Fn::Sub: ${AppBaseName}-source-changed
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
OutputArtifacts:
- Name:
Fn::Sub: ${AppBaseName}-packaged-yml
Configuration:
ProjectName:
Ref: BuildDingtalkProject
RunOrder: 1
AWS版本完整的代码、CloudFormation配置以及部署文档可以通过这里查看。