AWS Cloudformation - Template 学习(1)
AWS官方提供了一个参考手册,https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html
非常的详细和有用,初看有些枯燥,但是细细品味很有意思,下面是豆子的学习笔记。
在template里面,他一共有9个section可以定义,但是只有resource这个模块是必须存在的,其他8个模块都是可选项。这9个模块分别是Format Version,MetaData,Parameters, Mappings, Conditons, Transform,Resources 和 Outputs。
基本的格式如下所示 JSON 版
{ "AWSTemplateFormatVersion" : "version date", "Description" : "JSON string", "Metadata" : { template metadata }, "Parameters" : { set of parameters }, "Mappings" : { set of mappings }, "Conditions" : { set of conditions }, "Transform" : { set of transforms }, "Resources" : { set of resources }, "Outputs" : { set of outputs } }
下面来分别看看每个模块能做啥。
Format Version ( 可选)
他定义了template可以实现的功能。目前最新版本的就是一个 2010-09-09
例如:
"AWSTemplateFormatVersion" : "2010-09-09"
Description ( 可选 )
这个也很容易理解,就是添加对模板的说明的。对于YAML来说,可以在template里面随时添加注释,但是对于JSON而言,这个是唯一一个能添加注释说明的地方。
例如:
"Description" : "Here are some details about the template."
Metadata ( 可选 )
可以在里面添加任意的对象,来对template进行额外的说明。
"Metadata" : { "Instances" : {"Description" : "Information about the instances"}, "Databases" : {"Description" : "Information about the databases"} }
Parameters (可选)
这个比起前三个section来说,要复杂的多,这个地方是用于提供给用户可以自己自定义参数的地方。
具体可以定义哪些参数,参考链接
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
一个基本要求是
- 一个模板里面最多60个参数
- 每个参数需要名字
- 每个参数需要定义类型
- 每个参数在执行模板的时候需要传入一个值。我们可以定义这个值的范围,缺省值等等
- 可以通过内部函数Ref来调用我们的参数,这个调用一般是在Resource或者Output 这两个section里面使用。
例如:
"Parameters" : { "DBPort" : { "Default" : "3306", "Description" : "TCP/IP port for the database", "Type" : "Number", "MinValue" : "1150", "MaxValue" : "65535" }, "DBPwd" : { "NoEcho" : "true", "Description" : "The database admin account password", "Type" : "String", "MinLength" : "1", "MaxLength" : "41", "AllowedPattern" : "^[a-zA-Z0-9]*$" } }
Mapping ( 可选 )
这个是通过匹配不同的key来获取不同的value。一个常见的使用是场景是通过不同的region,自动选择对应的AMI镜像文件。
例如:
下面是一个完整的cf文件,里面我们只使用了3个section,分别是Format Version,Mappings 和 Resources。 Mappings 定义了个嵌套的二级JSON对象
Mapping的结构这么大,如何获取对应的信息呢?我们可以通过一个内置函数 Fn::FindInMap来获取。Fn::FindInMap 需要指定 Mapping的名字RegionalMap,第一层的Key region的名字, 以及第二层的key 架构的名字,从而获得对应的AMI的id。这个操作是在Resource部分实行的。这里还调用了一个全局变量 Presudo Parameter AWS::Region 来自动获取用户所在的Region的名字
{ "AWSTemplateFormatVersion" : "2010-09-09", "Mappings" : { "RegionMap" : { "us-east-1" : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"}, "us-west-1" : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"}, "eu-west-1" : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"}, "ap-northeast-1" : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"}, "ap-southeast-1" : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"} } }, "Resources" : { "myEC2Instance" : { "Type" : "AWS::EC2::Instance", "Properties" : { "ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "HVM64"]}, "InstanceType" : "m1.small" } } } }
来实际的运行一下看看结果, 创建Stack之后,看看自动生成的EC2实例。我所在的区域是 North Virginia, 也就是 us-east-1, 他会
看看EC2的AMI ID,这与我们在Mapping里面定义的是一致的
Condition ( 可选 )
接下来,看看Condition 这个模块。这个模块的作用类似于if..else 语句,如果某种情况为真,那么进行操作,否则进行另外的操作。
他的典型使用方式如下:
Parameter setction: 定义你打算比较的输入参数
Condition section:利用内部函数进行判断,内部函数包括Fn::And , Fn:: Equals, Fn::If, Fn::Not, Fn::Not 五个操作,基本语法:
"Conditions" : { "Logical ID" : {Intrinsic function} }
Resource and Outputs section: 这两个模块里面进行关联condition,凡是关联为真的rescource才会被创建。
下面看一个实例进行说明。这两个例子是如果用户创建的是test环境,那么就给创建一个实例,如果是prod的环境,那就在实例的基础上,再添加一个volume
首先还是Mapping 模块,这个上面的例子已经实验过来。
接下来是Parameters 模块,他提供了两个支持的值供用户选择
接下来是Condition 模块,按照我们说的语法,给了一个名字叫CreateProdResource,后面是一个嵌套的内置函数,首先获取EnvType 参数的值,然后和prod这个关键词进行比较,如果一样,就返还真,否则返回假
接下来在resources 模块,创建了3个resources,第一个通过Mappnig来创建EC2,上一个例子已经测试过;第二个resource是创建一个挂载点,里面有一个通过conditon这个关键字来获取对应的条件,第三个类似,通过condition来获取前面定义的条件,另外通过内置函数Fn::GetAtt获取AZ的值
最后是Outputs模块,同样指定了condition 为真,才返回结果
{ "AWSTemplateFormatVersion" : "2010-09-09", "Mappings" : { "RegionMap" : { "us-east-1" : { "AMI" : "ami-0ff8a91507f77f867", "TestAz" : "us-east-1a" }, "us-west-1" : { "AMI" : "ami-0bdb828fd58c52235", "TestAz" : "us-west-1a" }, "us-west-2" : { "AMI" : "ami-a0cfeed8", "TestAz" : "us-west-2a" }, "eu-west-1" : { "AMI" : "ami-047bb4163c506cd98", "TestAz" : "eu-west-1a" }, "sa-east-1" : { "AMI" : "ami-07b14488da8ea02a0", "TestAz" : "sa-east-1a" }, "ap-southeast-1" : { "AMI" : "ami-08569b978cc4dfa10", "TestAz" : "ap-southeast-1a" }, "ap-southeast-2" : { "AMI" : "ami-09b42976632b27e9b", "TestAz" : "ap-southeast-2a" }, "ap-northeast-1" : { "AMI" : "ami-06cd52961ce9f0d85", "TestAz" : "ap-northeast-1a" } } }, "Parameters" : { "EnvType" : { "Description" : "Environment type.", "Default" : "test", "Type" : "String", "AllowedValues" : ["prod", "test"], "ConstraintDescription" : "must specify prod or test." } }, "Conditions" : { "CreateProdResources" : {"Fn::Equals" : [{"Ref" : "EnvType"}, "prod"]} }, "Resources" : { "EC2Instance" : { "Type" : "AWS::EC2::Instance", "Properties" : { "ImageId" : { "Fn::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" : { "Fn::GetAtt" : [ "EC2Instance", "AvailabilityZone" ]} } } }, "Outputs" : { "VolumeId" : { "Value" : { "Ref" : "NewVolume" }, "Condition" : "CreateProdResources" } } }
来实际跑一下
这里可以允许用户选择prod还是test, 我选择了prod
看看他的stack创建resource的顺序,首先创建了EC2和New Volume,然后创建了Mountpoint
看看创建好的volume
以及对应的Outputs
Tranform ( 可选)
这个主要是调用Lambda,后面有具体例子讲解
Resources (必选)
这里面我们创建对应的资源。每种AWS 服务都有自己的属性值需要定义,具体使用可以参考这个链接
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html
Outputs ( 可选)
这里的输出结果可以在其他stack里面调用,也可以在console里面显示结果。
语法格式如下
"Outputs" : { "Logical ID" : { "Description" : "Information about the value", "Value" : "Value to return", "Export" : { "Name" : "Value to export" } } }
至此,9个基本的section简单的过了一遍,下一篇来看看Template里面的intrinsic function(内置函数)