Задача:
Сделать CloudFormation шаблон в структуре наследования (Nested templates), в котором будет создаваться VPC + SG а потом набор сервисов, но я покажу на примере одного - ElastiCache.
Так же в задаче указано, что в шаблоне нужно сделать выбор в параметрах Memcache/Redis, в зависимости от окружения выбрать тип узлов и их количество.
Проблем с Nested, Memcache не возникло. Проблем было много при создании Redis.
И вот почему.
Redis можно сделать в режимах Cluster enabled/disabled. Так же можно использовать консоль для создания или CLI/SDK. А в документации для консоли и CLI даже параметры именуются по разному. Да еще и для создания кластеров тип ресурса один описан а создание Redis не поддерживается этим сопособом. Я имею ввиду "Type": "AWS::ElastiCache::CacheCluster".
По сути чем отличается и что выбрать при создании Redis описано в документации AWS.
Я покажу живой пример создания. Ибо для создания Redis нужен другой тип, а именно "Type" : "AWS::ElastiCache::ReplicationGroup". В примере будет создан Redis MultiAZ, Cluster Disabled (не трудно поменять). Так же покажу пример Outputs для ReplicationGroup.
Мастер шаблон (простой пример):
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Master-example template for test purpose only.",
"Parameters": {
"EnvName": {
"Type": "String",
"Default": "Staging",
"AllowedValues": [
"Prod",
"Staging"
],
"Description": "Purposes of created environment"
},
"VpcName": {
"Default": "MyVPC",
"Description": "VPC Name",
"Type": "String"
},
"KeyName": {
"Type": "AWS::EC2::KeyPair::KeyName",
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"MinLength": 1
},
"VpcCidrBlock": {
"Default": "10.0.0.0/16",
"Description": "VPC CIDR Block",
"Type": "String"
},
"AZs": {
"Default": "us-west-2a,us-west-2b,us-west-2c",
"Description": "The list of active AZ's. To use this template need to specify 3 AZ's (A,B and C).",
"Type": "List"
},
"SubnetsSharedPrivate": {
"Type": "CommaDelimitedList",
"Default": "10.0.96.0/22, 10.0.100.0/22, 10.0.104.0/22",
"Description": "IP Ranges (CIDR) for Shared Private Subnets of each A,B,C AZ's"
},
"CacheEngine": {
"Type": "String",
"Default": "Redis",
"AllowedValues": [
"Redis",
"Memcache"
],
"Description": "ElastiCache Engine"
}
},
"Mappings": {},
"Conditions": {},
"Resources": {
"VPC": {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/xxxx/CF/vpc-example.json",
"Parameters": {
"VpcName" : { "Ref": "VpcName" },
"EnvName" : { "Ref": "EnvName" },
"SubnetsSharedPrivate" : {"Fn::Join": [ ",", { "Ref": "SubnetsSharedPrivate" }]},
"AZs" : {"Fn::Join": [ ",", { "Ref": "AZs" }]},
"VpcCidrBlock" : { "Ref" : "VpcCidrBlock" }
},
"TimeoutInMinutes": "60"
}
},
"ElastiCache": {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/xxxx/CF/ElastiCache.json",
"Parameters": {
"EnvName" : { "Ref": "EnvName" },
"CacheEngine" : { "Ref": "CacheEngine" },
"CacheSecurityGroup" : { "Fn::GetAtt" : [ "VPC", "Outputs.SecurityGroup" ] },
"SubnetsPrivateIds" : { "Fn::GetAtt" : [ "VPC", "Outputs.SubnetsPrivateIds" ] }
},
"TimeoutInMinutes": "60"
}
}
},
"Outputs": {
"VpcId": {
"Value": { "Fn::GetAtt" : [ "VPC", "Outputs.VpcId" ] }
},
"SubnetsPrivateIds": {
"Value": { "Fn::GetAtt" : [ "VPC", "Outputs.SubnetsPrivateIds" ] }
},
"ElastiCacheEndpoint": {
"Value": { "Fn::GetAtt" : [ "ElastiCache", "Outputs.ElastiCacheEndpoint" ] }
}
}
}
-------------------------
это часть шаблона vpc-example.json, секция Outputs. Она нам очень важна для передачи параметров в другие шаблоны по порядку.
"Outputs": {
"VpcId": {
"Value": { "Ref": "Vpc" },
"Description": "ID for VPC"
},
"VpcCidrBlock": {
"Description": "CIDR block of created VPC",
"Value": { "Ref": "VpcCidrBlock" }
},
"SubnetsSharedPrivateIds": {
"Value": { "Fn::Join": [ ", ", [ { "Ref": "SubnetPrivateA" }, { "Ref": "SubnetPrivateB" }, { "Ref": "SubnetPrivateC" } ] ] },
"Description": "IDs for private subnets (A/B)"
},
"SecurityGroup": {
"Value": { "Ref": "SecurityGroup" },
"Description": "SG"
}
}
-----------------------------
Это ElastiCache.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "ElastiCache. This template will be create ElastiCache cluster. Needed Environment Name, Engine, Subnets and Security Group. v07.21.2017-01",
"Conditions": {
"CreateProdResources" : {"Fn::Equals" : [{"Ref" : "EnvName"}, "Prod"]},
"CreateRedisResources" : {"Fn::Equals" : [{"Ref" : "CacheEngine"}, "Redis"]},
"CreateMemcacheResources" : {"Fn::Equals" : [{"Ref" : "CacheEngine"}, "Memcache"]}
},
"Mappings" : { "Environments" : {
"Prod" : {
"InstanceType" : "cache.m3.xlarge",
"CountNodes" : "2"
},
"Staging" : {
"InstanceType" : "cache.m3.medium",
"CountNodes" : "2"
}
}
},
"Parameters": {
"EnvName": {
"Type": "String",
"AllowedValues": [
"Prod",
"Staging"
],
"Description": "Purposes of created environment"
},
"CacheEngine": {
"Type": "String",
"AllowedValues": [
"Redis",
"Memcache"
],
"Description": "ElastiCache Engine"
},
"CacheSecurityGroup": {
"Description": "Security group for Cache Cluster",
"Type": "String"
},
"SubnetsPrivateIds": {
"Description": "Shared Private Subnets",
"Type": "List"
}
},
"Metadata": {},
"Resources": {
"CacheSubnetGroup": {
"Type": "AWS::ElastiCache::SubnetGroup",
"Properties": {
"Description": "Cache Subnet Group",
"SubnetIds": { "Ref": "SubnetsPrivateIds" }
}
},
"RedisCluster" : {
"Condition" : "CreateRedisResources",
"Type" : "AWS::ElastiCache::ReplicationGroup",
"Properties" : {
"AutomaticFailoverEnabled" : true,
"CacheNodeType" : { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "InstanceType"] },
"CacheSubnetGroupName" : { "Ref" : "CacheSubnetGroup" },
"Engine" : "redis",
"ReplicationGroupId" : { "Fn::Join": ["",[{"Ref": "EnvName"},"-redis"]]},
"ReplicationGroupDescription" : "Redis (cluster mode disabled)",
"NumCacheClusters": { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "CountNodes"] },
"Port" : 6379,
"CacheParameterGroupName" : "default.redis3.2",
"SecurityGroupIds" : [{ "Ref" : "CacheSecurityGroup" }],
"Tags" : [
{"Key" : "Environment", "Value" : {"Ref" : "EnvName"}}
]
}
},
"MemcacheCluster" : {
"Condition" : "CreateMemcacheResources",
"Type": "AWS::ElastiCache::CacheCluster",
"Properties" : {
"AZMode" : "cross-az",
"ClusterName" : { "Fn::Join": ["",[{"Ref": "EnvName"},"-memcache"]]},
"CacheNodeType" : { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "InstanceType"] },
"Engine" : "memcached",
"NumCacheNodes" : { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "CountNodes"] },
"VpcSecurityGroupIds" : [{ "Ref" : "CacheSecurityGroup" }],
"CacheSubnetGroupName" : { "Ref": "CacheSubnetGroup" },
"Tags" : [
{"Key" : "Environment", "Value" : {"Ref" : "EnvName"}}
]
}
}
},
"Outputs": {
"ElastiCacheEndpoint": {
"Value": {
"Fn::If" : [ "CreateMemcacheResources",
{ "Fn::Join": [ ":", [
{ "Fn::GetAtt": [ "MemcacheCluster", "ConfigurationEndpoint.Address" ] },
{ "Fn::GetAtt": [ "MemcacheCluster", "ConfigurationEndpoint.Port" ] }
]]
},
{ "Fn::Join": [ ":", [
{ "Fn::GetAtt": [ "RedisCluster", "PrimaryEndPoint.Address" ] },
{ "Fn::GetAtt": [ "RedisCluster", "PrimaryEndPoint.Port" ] }
]]
}
]
}
}
}
}
------------------
В итоге создается (если выбран Engine = Redis):
Shards: 1
Nodes: 2
MultiAZ: enabled
Engine: redis.
Поменяте значение этого параметра с "CacheParameterGroupName" : "default.redis3.2" на default.redis3.2.cluster.on для создания Redis Clustered Engine. Так же нужно будет добавлять пареметры по количеству кластеров + количеству шардов и нод в шардах.
Сделать CloudFormation шаблон в структуре наследования (Nested templates), в котором будет создаваться VPC + SG а потом набор сервисов, но я покажу на примере одного - ElastiCache.
Так же в задаче указано, что в шаблоне нужно сделать выбор в параметрах Memcache/Redis, в зависимости от окружения выбрать тип узлов и их количество.
Проблем с Nested, Memcache не возникло. Проблем было много при создании Redis.
И вот почему.
Redis можно сделать в режимах Cluster enabled/disabled. Так же можно использовать консоль для создания или CLI/SDK. А в документации для консоли и CLI даже параметры именуются по разному. Да еще и для создания кластеров тип ресурса один описан а создание Redis не поддерживается этим сопособом. Я имею ввиду "Type": "AWS::ElastiCache::CacheCluster".
По сути чем отличается и что выбрать при создании Redis описано в документации AWS.
Я покажу живой пример создания. Ибо для создания Redis нужен другой тип, а именно "Type" : "AWS::ElastiCache::ReplicationGroup". В примере будет создан Redis MultiAZ, Cluster Disabled (не трудно поменять). Так же покажу пример Outputs для ReplicationGroup.
Мастер шаблон (простой пример):
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Master-example template for test purpose only.",
"Parameters": {
"EnvName": {
"Type": "String",
"Default": "Staging",
"AllowedValues": [
"Prod",
"Staging"
],
"Description": "Purposes of created environment"
},
"VpcName": {
"Default": "MyVPC",
"Description": "VPC Name",
"Type": "String"
},
"KeyName": {
"Type": "AWS::EC2::KeyPair::KeyName",
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"MinLength": 1
},
"VpcCidrBlock": {
"Default": "10.0.0.0/16",
"Description": "VPC CIDR Block",
"Type": "String"
},
"AZs": {
"Default": "us-west-2a,us-west-2b,us-west-2c",
"Description": "The list of active AZ's. To use this template need to specify 3 AZ's (A,B and C).",
"Type": "List
},
"SubnetsSharedPrivate": {
"Type": "CommaDelimitedList",
"Default": "10.0.96.0/22, 10.0.100.0/22, 10.0.104.0/22",
"Description": "IP Ranges (CIDR) for Shared Private Subnets of each A,B,C AZ's"
},
"CacheEngine": {
"Type": "String",
"Default": "Redis",
"AllowedValues": [
"Redis",
"Memcache"
],
"Description": "ElastiCache Engine"
}
},
"Mappings": {},
"Conditions": {},
"Resources": {
"VPC": {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/xxxx/CF/vpc-example.json",
"Parameters": {
"VpcName" : { "Ref": "VpcName" },
"EnvName" : { "Ref": "EnvName" },
"SubnetsSharedPrivate" : {"Fn::Join": [ ",", { "Ref": "SubnetsSharedPrivate" }]},
"AZs" : {"Fn::Join": [ ",", { "Ref": "AZs" }]},
"VpcCidrBlock" : { "Ref" : "VpcCidrBlock" }
},
"TimeoutInMinutes": "60"
}
},
"ElastiCache": {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/xxxx/CF/ElastiCache.json",
"Parameters": {
"EnvName" : { "Ref": "EnvName" },
"CacheEngine" : { "Ref": "CacheEngine" },
"CacheSecurityGroup" : { "Fn::GetAtt" : [ "VPC", "Outputs.SecurityGroup" ] },
"SubnetsPrivateIds" : { "Fn::GetAtt" : [ "VPC", "Outputs.SubnetsPrivateIds" ] }
},
"TimeoutInMinutes": "60"
}
}
},
"Outputs": {
"VpcId": {
"Value": { "Fn::GetAtt" : [ "VPC", "Outputs.VpcId" ] }
},
"SubnetsPrivateIds": {
"Value": { "Fn::GetAtt" : [ "VPC", "Outputs.SubnetsPrivateIds" ] }
},
"ElastiCacheEndpoint": {
"Value": { "Fn::GetAtt" : [ "ElastiCache", "Outputs.ElastiCacheEndpoint" ] }
}
}
}
-------------------------
это часть шаблона vpc-example.json, секция Outputs. Она нам очень важна для передачи параметров в другие шаблоны по порядку.
"Outputs": {
"VpcId": {
"Value": { "Ref": "Vpc" },
"Description": "ID for VPC"
},
"VpcCidrBlock": {
"Description": "CIDR block of created VPC",
"Value": { "Ref": "VpcCidrBlock" }
},
"SubnetsSharedPrivateIds": {
"Value": { "Fn::Join": [ ", ", [ { "Ref": "SubnetPrivateA" }, { "Ref": "SubnetPrivateB" }, { "Ref": "SubnetPrivateC" } ] ] },
"Description": "IDs for private subnets (A/B)"
},
"SecurityGroup": {
"Value": { "Ref": "SecurityGroup" },
"Description": "SG"
}
}
-----------------------------
Это ElastiCache.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "ElastiCache. This template will be create ElastiCache cluster. Needed Environment Name, Engine, Subnets and Security Group. v07.21.2017-01",
"Conditions": {
"CreateProdResources" : {"Fn::Equals" : [{"Ref" : "EnvName"}, "Prod"]},
"CreateRedisResources" : {"Fn::Equals" : [{"Ref" : "CacheEngine"}, "Redis"]},
"CreateMemcacheResources" : {"Fn::Equals" : [{"Ref" : "CacheEngine"}, "Memcache"]}
},
"Mappings" : { "Environments" : {
"Prod" : {
"InstanceType" : "cache.m3.xlarge",
"CountNodes" : "2"
},
"Staging" : {
"InstanceType" : "cache.m3.medium",
"CountNodes" : "2"
}
}
},
"Parameters": {
"EnvName": {
"Type": "String",
"AllowedValues": [
"Prod",
"Staging"
],
"Description": "Purposes of created environment"
},
"CacheEngine": {
"Type": "String",
"AllowedValues": [
"Redis",
"Memcache"
],
"Description": "ElastiCache Engine"
},
"CacheSecurityGroup": {
"Description": "Security group for Cache Cluster",
"Type": "String"
},
"SubnetsPrivateIds": {
"Description": "Shared Private Subnets",
"Type": "List
}
},
"Metadata": {},
"Resources": {
"CacheSubnetGroup": {
"Type": "AWS::ElastiCache::SubnetGroup",
"Properties": {
"Description": "Cache Subnet Group",
"SubnetIds": { "Ref": "SubnetsPrivateIds" }
}
},
"RedisCluster" : {
"Condition" : "CreateRedisResources",
"Type" : "AWS::ElastiCache::ReplicationGroup",
"Properties" : {
"AutomaticFailoverEnabled" : true,
"CacheNodeType" : { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "InstanceType"] },
"CacheSubnetGroupName" : { "Ref" : "CacheSubnetGroup" },
"Engine" : "redis",
"ReplicationGroupId" : { "Fn::Join": ["",[{"Ref": "EnvName"},"-redis"]]},
"ReplicationGroupDescription" : "Redis (cluster mode disabled)",
"NumCacheClusters": { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "CountNodes"] },
"Port" : 6379,
"CacheParameterGroupName" : "default.redis3.2",
"SecurityGroupIds" : [{ "Ref" : "CacheSecurityGroup" }],
"Tags" : [
{"Key" : "Environment", "Value" : {"Ref" : "EnvName"}}
]
}
},
"MemcacheCluster" : {
"Condition" : "CreateMemcacheResources",
"Type": "AWS::ElastiCache::CacheCluster",
"Properties" : {
"AZMode" : "cross-az",
"ClusterName" : { "Fn::Join": ["",[{"Ref": "EnvName"},"-memcache"]]},
"CacheNodeType" : { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "InstanceType"] },
"Engine" : "memcached",
"NumCacheNodes" : { "Fn::FindInMap" : ["Environments", { "Ref" : "EnvName"}, "CountNodes"] },
"VpcSecurityGroupIds" : [{ "Ref" : "CacheSecurityGroup" }],
"CacheSubnetGroupName" : { "Ref": "CacheSubnetGroup" },
"Tags" : [
{"Key" : "Environment", "Value" : {"Ref" : "EnvName"}}
]
}
}
},
"Outputs": {
"ElastiCacheEndpoint": {
"Value": {
"Fn::If" : [ "CreateMemcacheResources",
{ "Fn::Join": [ ":", [
{ "Fn::GetAtt": [ "MemcacheCluster", "ConfigurationEndpoint.Address" ] },
{ "Fn::GetAtt": [ "MemcacheCluster", "ConfigurationEndpoint.Port" ] }
]]
},
{ "Fn::Join": [ ":", [
{ "Fn::GetAtt": [ "RedisCluster", "PrimaryEndPoint.Address" ] },
{ "Fn::GetAtt": [ "RedisCluster", "PrimaryEndPoint.Port" ] }
]]
}
]
}
}
}
}
------------------
В итоге создается (если выбран Engine = Redis):
Shards: 1
Nodes: 2
MultiAZ: enabled
Engine: redis.
Поменяте значение этого параметра с "CacheParameterGroupName" : "default.redis3.2" на default.redis3.2.cluster.on для создания Redis Clustered Engine. Так же нужно будет добавлять пареметры по количеству кластеров + количеству шардов и нод в шардах.
Комментариев нет:
Отправить комментарий