金丝雀发布是一种减少软件发布风险的技术,它先部署新版本的软件并保留旧版本的软件,然后缓慢的滚动一小部分用户的流量到新版本上,当新版本没有遇到问题时继续提升新版本所占用的流量比例,直到流量100%滚动到新版本;如果流量滚动过程中新版本遇到问题,那么流量会马上100%切回旧版本。这样我们的线上项目可以将版本发布带来的意外故障降到最低。
金丝雀发布的流量切换效果如下:
AWS Lambda只带完善的金丝雀发布功能,相比普通发布(后续的流量直接100%转移到新版本lambda上),金丝雀发布可以让后续的流量以一定的规则按比例的在新旧lambda间分布,这样除了可以让新版本的lambda预热外,还可以在新lambda出现bug的罕见情况下减少故障的影响范围并及时回滚到旧版本。
其实AWS Lamdba的运行导致了金丝雀发布比传统意义上的金丝雀更加优秀.比如可以闪回到旧版本,兼具金丝雀和滚动的优点避免了缺点(比如lambda按需扩展避免了传统金丝雀可能的资源需求浪费,自动闪回到旧版本避免了传统滚动发布回滚的人力负担).
目前AWS SAM和serverless framework都能完美的支持金丝雀发布。
发布的示意图如下
以AWS SAM框架为例,我们可以简单的在自己的template.yml
添加下图高亮部分的设置
第一次发布,使用sam build
和sam deoloy
部署到AWS
第二次次发布,修改代码的返回值,使用sam build
和sam deoloy
部署到AWS
在第二次发布是,我们在AWS控制台可以看到流量的实时转换 如果没有问题新版本承载的流量会逐渐升高,直到100%,最后完成发布
在发布过程中,如果你访问lambda暴露的HTTP接口,会发现返回值按照比例随机的返回不同的值。
新版本遇到故障后自动闪回
前面我们讲到,aws lambda的金丝雀发布可以闪回到旧版本。那么我们继续丰满上面的例子
我们在template.yml
添加一个告警,让这个告警监控我们发布的lamdba的错误
然后引用这个告警,告诉aws sam框架:在遇到告警的时候闪回到旧版本
从原理上讲,aws lambda的金丝雀发布是基于aws codedeploy来实现的,流量滚动由codedeploy来逐渐的自动调整,当有故障时马上回滚,没故障继续增加新版本的流量占比。
这个其中一次发布过程中的,codedeploy正在进行的样例
当我们故意写出有错误的代码,比如
然后接着进行部署,并不断访问lambda的http api,一部分流量会被新版本处理,新版本运行错误会触发错误,产生告警,codedeploy会马上在告警产生的时候,切换全部流量到旧版本
cloudwatch成功监控到了告警
codedeploy自动终止了滚定,立即回滚到旧版本么,避免了有bug的新版本上线导致的线上故障。
金丝雀发布钩子(Hooks
):前置检查(PreTraffic
)和后置检查(PostTraffic
)
AWS Lambda提供金丝雀发布钩子功能(前置检查和后置检查),它们在流量转移开始到新版本之前和流量转移完成之后运行检查。
前置检查(PreTraffic
):在流量转移开始之前,CodeDeploy调用前置检查钩子所引用的Lambda函数。此 Lambda函数必须回调CodeDeploy并指示成功或失败。如果函数失败,它将中止并将失败报告给AWS CloudFormation。如果函数成功,则CodeDeploy继续进行流量转移。
后置检查(PostTraffic
):流量转移完成后,CodeDeploy调用后置检查钩子所引用的Lambda函数。这与预流量挂钩类似,其中函数必须回调CodeDeploy才能报告成功或失败。使用转移流量后挂钩可以运行集成测试或其他验证操作
我们可以使用!Ref xxx
来引用其他lambda函数,比如:
!Ref PreTrafficLambdaFunction
引用函数PreTrafficLambdaFunction做为前置检查!Ref PostTrafficLambdaFunction
引用函数PostTrafficLambdaFunction做为前置检查
注意:篇幅原因,PreTrafficLambdaFunction和PostTrafficLambdaFunction我并未记录在代码里面,你需要自己实现。
总结:
- AWS Lambda可以轻松的和AWS官方框架以及一些第三方框架结合,完成金丝雀发布
- AWS Lambda的金丝雀发布时自动的健康监控和异常闪回
- 在新版本正常时,自动的提升新版本的流量占比,直到100%
- 在新版本被检测到故障后,自动的终止滚动,马上回退到旧版本
- 内置自动的前置检查和后置检查(本文篇幅原因没有展开讲)
- 前置检查:适用于某些前置条件必须满足后才进行发布
- 后置检查:发布后立即进行集成测试,预热等
本文代码库为github sam-samples