Cloudformation里面,整个架构都是在template里面定义的,然后通过这个template生成对应的Stack
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(内置函数)