当前位置: 首页 > 工具软件 > Spinnaker > 使用案例 >

一次因阿里云API引发的Spinnaker故障

有宏峻
2023-12-01

这是个真实的事故:

2021/02/22 节后第一个星期一中午的准午餐时间,节后综合症导致的吊儿郎当的神经还未绷紧,突然办公室内全面报警,很多服务都出现或多或少的异常,大家不约而同地说“我去,我的服务里阿里云的机器没有了”!!。
我的直觉告诉我这种批量操作不可能是误删,应该是程序或脚本引起的,赶紧联系阿里云审计日志中查下操作账号和源IP。结果是spinnaker账号在公司内网发起的请求。
因为spinnaker的版本最近没有变动过,所以我第一反应没有怀疑spinnaker而是怀疑鉴权泄露了,立马修改了API调用的鉴权,同时运维同事们把先前被删除的实例重新发布了一次。
然而一个多小时后,悲剧再次发生,这些机器又被删除了!当时有一种炸雷的感觉,只能怀疑是什么特殊情况下触发了spinnaker的BUG。
我唯一可以依据的数据就是spinnaker日志和阿里云操作审计日志,发现在两次故障时审计日志的表现都是出奇的相似:先调用了伸缩组查询接口、再调用了伸缩组disable接口、然后调用了伸缩组destroy接口,顺带干掉了伸缩组下的所有实例!!
顺着思路去review了clouddriver相关的代码,终于找到了一些眉目:spinnaker的阿里云实现部分在进行红黑发布或者Highland发布时会清理掉旧版本的弹性伸缩组,而清理ESS原子操作的逻辑如下:

DescribeScalingGroupsRequest describeScalingGroupsRequest = new DescribeScalingGroupsRequest();
describeScalingGroupsRequest.setScalingGroupName(description.getServerGroupName());
describeScalingGroupsResponse = client.getAcsResponse(describeScalingGroupsRequest);
try {
    for (ScalingGroup scalingGroup : describeScalingGroupsResponse.getScalingGroups()) {
        DeleteScalingGroupRequest deleteScalingGroupRequest = new DeleteScalingGroupRequest();
        deleteScalingGroupRequest.setScalingGroupId(scalingGroup.getScalingGroupId());
        deleteScalingGroupRequest.setForceDelete(true);
        client.getAcsResponse(deleteScalingGroupRequest);
      }
} catch (ServerException e) {
  log.info(e.getMessage());
  throw new AliCloudException(e.getMessage());
} catch (ClientException e) {
  log.info(e.getMessage());
  throw new AliCloudException(e.getMessage());
}

后续还有清理实例等一些列动作,跟阿里云审计日志中表现的一模一样。为了确定是这段代码造成的,我又去找到了引起这次故障的spinnaker操作记录,11:26分进行了一次删除操作,审计日志是从11:27开始删除所有伸缩组的。
定位了问题,后面就是跟阿里云方面一起排查了,厂家大方承认确实当天做了API接口的升级,使这个查询接口的“伸缩组名称”条件失效了,导致我拿到了多余的伸缩组,从而引发了一些列的问题。

反思

一切服务都是不可信的,我们一定要具备面向失败的编程思想。
其实这段代码还是考虑到异常如何处理的,例如获取不到或者请求异常时要如何处理,但对“失败”的可能性漏掉了查询条件失效这一点。所以我们在跨服务查询时,一定要对返回结果做好“是否满足过滤条件”的校验,只有这样才能避免本文这种类型的故障。

多云部署的优势

两次故障共删除阿里云上200多台机器,客户真实影响率只升高了不到2%,这么大的事故能有这种容错表现完全是靠公司的多云部署机制来实现的。
从内部服务到边缘服务甚至到APP客户端,都有多域名的重试机制,而且多云之间完全物理隔离,这样当其中一家云出现故障时服务自动重试到另一云厂商。这种架构设计必须要依赖一个强大的多云持续部署平台才能保证版本在多云上的正常发布,spinnaker就是为此而生!而且在此次故障阿里云200多台实例的恢复只用了20分钟左右,这也是依赖spinnaker的流水线。

 

 

 类似资料: