AWS中国区的那些“坑”

前言

最近做的一个项目是要把公司在国外已经上线的一个物联网的项目移植到AWS中国区来。

由于AWS属于国外云产商,在中国运营,必须符合国家的相关规定:

  • 必须是合资公司 (AWS北京区由北京光环新网运营,宁夏区由西云数据运营)
  • 拿到ICP认证
  • 服务器和数据必须在物理上中国境内
  • 其他

AWS在Global区已有的服务,也是一点点在中国上线的,例如2020年上线了很多重要的服务,Route53、Certificate Manager等等, 可以在这里查看最新上线的服务

我曾经问过AWS中国的support人员,其他未上线的服务是否有时间表?support人员,一般标准回答都是:"没有准确的时间表。"

AWS的中国区和AWS在Global的其他区之间是"不相通的";账号是独立分开的,中国区的账号下,目前只有北京和宁夏两个region

从这段时间的工作经验,总结出要把国外的AWS云项目移植到中国需要注意的一些"坑", 其中很多问题,在中文社区很难找到相关文章,所以决定分享出来,避免大家再走弯路!

坑一:arn问题

问题描述

AWS的各个资源,都有一个arn,作为全局唯一的标识, 例如:arn:partition:service:region:account-id:resource-id

我们一般会在代码中会直接这样写:arn:aws:apigateway:region:lambda, 这样写,在AWS Global基本上没有问题,但是在中国区,AWS采取了不同的arn

上面的那个例子在中国区就变成了: arn:aws-cn:aipgateway:region:lambda

AWS中国区的那些“坑”

大部分公司都希望一套代码在全球使用,不希望单独为中国区准备一个版本。那怎么样做到兼容呢?

解决方案

在cloudFormation内建脚本中有一个参数Partition, 有了这个参数,上面的arn的写法就变成了: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda

AWS中国区的那些“坑”

为了做到批量修改,我们可以使用一些辅助工具replace,它还支持正则表达式

以下是一段参考脚本,适用于在CloudFormation中存在arn hardcode的情况, 可以根据具体情况进行修改替代规则

npm install -g replace
replace '!Sub "arn:aws:' '!Sub "arn:${AWS::Partition}:' *.template.yaml
replace '"arn:aws:iot:",{ "Fn::Sub": "${AWS::Region}" }' '{ "Fn::Sub": "arn:${AWS::Partition}:iot:${AWS::Region}" }' *.template.yaml

坑二:网址域名后缀

问题描述

在Global区,在生成的APIGateway和S3地址都是:https://.amazonaws.com, 在中国区变成了https://.amazonaws.com.cn

解决方案

目前我采取的方案,有些ugly:

  • 把所有hardcode的amazonaws.com用占位符替换掉
  • 部署的时候,根据目标环境替换成对应的值

    伪代码
# preparation
replace '.\$\{AWS::Region\}.amazonaws.com' '.${AWS::Region}.#AMAZONAWS#' *.template.yaml # deployment stage
if "target is China"
replace '#AMAZONAWS#' 'amazonaws.com.cn' *.template.yaml
else
replace '#AMAZONAWS#' 'amazonaws.com' *.template.yaml

坑三:可用区问题

问题描述

在Global区,大部分的region都有3个及以上可用区,所以在自动化创建VPC脚本里面,会默认使用3个可用区,however,在北京区(cn-north-1)目前只有两个可用区

AWS中国区的那些“坑”

解决方案

为了兼容性,方案类似于坑二,就是在部署脚本中需要判断目标区域的可用区数量,然后决定是用2个或3个可用区的脚本,建议VPC的部署脚本分成两份,一份支持两个可用区,另外一个支持三个可用区

坑四:APIGateway端口 80\443默认关闭问题

问题描述

曾经被这个问题耽误了很长时间,明明一个很简单的APIGateway+lambda应用,从本地postman怎么也发不通!后来发现每个账号,默认80和443端口是不通的!

解决方案

需要从AWS Console录一个support的case来开通。另外你的组织可能已经开始使用AWS Organization来管理多级账号了,每个子账号都需要用这种方式来开通端口

case参考模板:

AWS中国区的那些“坑”

坑四:计费单位

问题描述

有时候需要设置一些Alarm,当费用超预算时,自动邮件通知,设置计费单位的时候,需要注意,中国区目前只支持CNY

解决方案

不要hardcode,而是把计费单位作为参数传进去

Parameters:
MoneyUnit:
Type: String
Default: USD
Resources:
DynamoDBBudget:
Type: "AWS::Budgets::Budget"
Properties:
Budget:
BudgetLimit:
Amount: !Ref DynamoDBBillingTreshold
Unit: !Ref MoneyUnit
TimeUnit: MONTHLY

不可用服务替代方案

之前提过,很多服务在中国区未上线,不可用,但很多全球项目又深度依赖这些服务。这个时候,就需要寻找替代方案。顺便说一下,在做整体架构设计的时候,可能需要考虑我的现有代码要从一个云产商移植到另外一个云产商需要付出的代价,这里就不展开讲了。

AWS Cognito User Pool -> Keycloak

问题描述

我们的项目深度依赖Cognito user pool, Cognito user pool和APIGateway集成, 做用户身份验证和授权,遗憾的是这个服务在中国区不可用。

解决方案

我们找到一个非常强大的做用户管理和身份验证的开源项目:Keycloak

经过实践,完美解决:用lambda写一个customize authorizer和APIGateway进行集成

AWS中国区的那些“坑”

其他

一位一起工作的国外同事,在国外,经常碰到一些网络连接的问题,开AWS China Console间歇性断网,非常影响工作效率。

后来的临时解决方案是先走公司内网,连到一台中国的服务器(jump server),再从这台服务器上连接AWS Console。

总觉得不是一个非常好的方案,建议能在国内有一名开发人员配合工作,提高效率!

写在最后

说是“坑”,其实是调侃,毕竟世界发展太快,之前的开发人员可能也没预料到科技受到各种ZZ因素的影响,导致无法理想化的大一统!

程序员就是这么一个职业,不断的给别人挖坑,填别人的坑!哈哈

好了,分享使我快乐,有什么问题,请留言。

上一篇:javascript进阶笔记(2)


下一篇:干货:教你如何监控 Java 线程池运行状态