最近用cloudformation时遇到了一些坑,在此记录一下。

Conditions变量无法直接当布尔类型使用

Conditions可以动态控制一些资源的创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Conditions: 
CreateProdResources: !Equals [ !Ref EnvType, prod ]
Resources:
EC2Instance:
Type: "AWS::EC2::Instance"
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]
MountPoint:
Type: "AWS::EC2::VolumeAttachment"
Condition: CreateProdResources
Properties:
InstanceId:
!Ref EC2Instance
VolumeId:
!Ref NewVolume
Device: /dev/sdh
NewVolume:
Type: "AWS::EC2::Volume"
Condition: CreateProdResources
Properties:
Size: 100
AvailabilityZone:
!GetAtt EC2Instance.AvailabilityZone

但是如果在其他地方像这样使用会报Unresolved resource dependencies CreateResources错误

1
2
3
4
5
6
7
8
/xxx/xx/xx.conf:
source:
!Sub https://${bucket}.s3.amazonaws.com/${prefix}/xx.conf
context:
create_resources: !Ref CreateResources
mode: "000644"
owner: root
group: root

解决办法就时将create_resources: !Ref CreateResources 改成 create_resources: !If [CreateResources, "true output ", "false output"]

aws-resource-init-files 传递布尔变量

AWS::CloudFormation::Init中 files属性可以用来创建文件,filescontext属性可以传递变量,来动态生成文件内容.
AWS文档里说文件是通过类似mustache的方式来处理的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
A typical Mustache template:

Hello {{name}}
You have just won {{value}} dollars!
{{#in_ca}}
Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}
Given the following hash:

{
"name": "Chris",
"value": 10000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
}
Will produce the following:

Hello Chris
You have just won 10000 dollars!
Well, 6000.0 dollars, after taxes.

这里有个坑就是布尔类型在cloudformation里时当做字符类型来传递的,AWS官方认为这是一个feature而不是bug: What you have observed is a known behaviour with the CloudFormation servie
例如:

xxx.conf

1
2
3
4
5
6
7
{{#create_resources}}
this is true
{{/create_resources}}

{{^create_resources}}
this is false
{{/create_resources}}

yaml配置文件

1
2
3
4
5
6
7
8
9
/xxx.conf:
authentication: S3BucketAccess
source:
!Sub https://${bucket}.s3.amazonaws.com/${prefix}/xxx.conf
context:
create_resources: !If [CreateResources, true, false]
mode: "000644"
owner: root
group: root

这里无论 CreateResourcestrue 还是 false,文件内容始终会是 this is true,因为配置文件里的 truefalse 都被转成了字符类型。

这里的解决办法比较hack,就是将!If [CreateResources, true, false]改成!If [CreateResources, [1], []]:

1
2
3
4
5
6
7
8
9
/xxx.conf:
authentication: S3BucketAccess
source:
!Sub https://${bucket}.s3.amazonaws.com/${prefix}/xxx.conf
context:
create_resources: !If [CreateResources, [1], []]
mode: "000644"
owner: root
group: root

这里主要参考了 mustache 文档里 Inverted Sections : https://mustache.github.io/mustache.5.html

aws-resource-init 资源更新问题

aws-resource-init-sources可以用来下载压缩文件并解压到EC2指定目录,但这里有个问题就是如果目标文件夹已存在,cloudformation会将两文件夹内容合并而不是替换文件夹!比如AWS部署的项目使用的依赖LibraryA 1.0,将library升级到Library A 1.1并通过cloudformation source下载并解压新本版的项目到目标目录后,目标目录的项目文件夹里会同时存在Library A1.01.1版本。

解决办法也很简单,在用sources下载前将目标文件夹移除。

AWS平台的服务总有一些奇怪的限制或bug,调试时总会花不少时间,在此记录一下,希望能帮助到遇到相同问题的人,节约大家时间。

Update

  • 2019-07-07 添加aws-resource-init资源更新问题