virginia east aws amazon-web-services amazon-ec2 autoscaling amazon-cloudformation

amazon-web-services - east - aws tags



¿Cómo crear un número variable de recursos de instancia de EC2 en la plantilla de Cloudformation? (5)

Creo que lo que buscaba el cartel original es algo así como:

"Parameters" : { "InstanceCount" : { "Description" : "Number of instances to start", "Type" : "String" },

...

"MyAutoScalingGroup" : { "Type" : "AWS::AutoScaling::AutoScalingGroup", "Properties" : { "AvailabilityZones" : {"Fn::GetAZs" : ""}, "LaunchConfigurationName" : { "Ref" : "MyLaunchConfiguration" }, "MinSize" : "1", "MaxSize" : "2", "DesiredCapacity" : **{ "Ref" : "InstanceCount" }**, } },

... en otras palabras, inserte el número de instancias iniciales (la capacidad) de un parámetro.

¿Cómo crear un número variable de recursos de instancia de EC2 en la plantilla de Cloudformation, de acuerdo con un parámetro de plantilla?

La API de EC2 y las herramientas de administración permiten iniciar varias instancias de la misma AMI, pero no puedo encontrar la forma de hacerlo utilizando Cloudformation.


La respuesta corta es: no puedes. No puede obtener exactamente el mismo resultado (N instancias EC2 idénticas, no vinculadas por un grupo de escalado automático).

Lanzar varias instancias por igual desde la consola no es como crear un grupo de escalado automático con N instancias como capacidad deseada. Es solo un atajo útil que tienes, en lugar de tener que pasar N veces por el mismo proceso de creación de EC2. Se llama "una reserva" (sin relación con la instancia reservada). Los grupos de escalado automático son una bestia diferente (aunque termine con N instancias EC2 idénticas).

Tu también puedes:

  • duplicar (yuk) el recurso EC2 en la plantilla
  • use una plantilla anidada, que hará la creación de EC2 por sí misma, y ​​la llamará N veces desde su pila maestra, alimentándola cada vez con los mismos parámetros

El problema es que el número de instancias de EC2 no será dinámico, no puede ser un parámetro.

  • use una interfaz para las plantillas de CloudFormation, como la troposfera, que le permite escribir la descripción de EC2 dentro de una función, y llamar a la función N veces (mi elección ahora). Al final, tienes una plantilla de CloudFormation que hace el trabajo, pero has escrito el código de creación EC2 solo una vez. No es un parámetro de CloudFormation real , pero al final del día, obtienes tu número dinámico de EC2.

Mientras tanto, hay muchas Plantillas de ejemplo de AWS CloudFormation disponibles, y varias incluyen el lanzamiento de varias instancias, aunque generalmente muestran otras características en paralelo; por ejemplo, AutoScalingKeepAtNSample.template crea un sitio web de muestra con AutoScalingKeepAtNSample.template carga y AutoScalingKeepAtNSample.template automática y está configurado para iniciar 2 instancias de EC2 para este propósito según este extracto de plantilla:

"WebServerGroup": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "AvailabilityZones": { "Fn::GetAZs": "" }, "LaunchConfigurationName": { "Ref": "LaunchConfig" }, "MinSize": "2", "MaxSize": "2", "LoadBalancerNames": [ { "Ref": "ElasticLoadBalancer" } ] } },

También hay más muestras avanzadas / completas disponibles, por ejemplo, la plantilla Drupal para un servidor web de alta disponibilidad con una instancia de base de datos Multi-AZ Amazon RDS y el uso de S3 para almacenar el contenido del archivo , que actualmente está configurado para permitir hablar de 1 a 5 instancias de servidor web a una instancia de base de datos de Amazon RDS MySQL Multi-AZ y ejecutándose detrás de un Elastic Load Balancer , que organiza las instancias del servidor web a través de Auto Scaling .


Utilice la función Ref .

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html

Las variables definidas por el usuario se definen en la sección "Parameters" del archivo de configuración. En la sección "Resources" del archivo de configuración puede completar valores utilizando referencias a estos parámetros.

{ "AWSTemplateFormatVersion": "2010-09-09", ... "Parameters": { "MinNumInstances": { "Type": "Number", "Description": "Minimum number of instances to run.", "Default": "1", "ConstraintDescription": "Must be an integer less than MaxNumInstances." }, "MaxNumInstances": { "Type": "Number", "Description": "Maximum number of instances to run.", "Default": "5", "ConstraintDescription": "Must be an integer greater than MinNumInstances." }, "DesiredNumInstances": { "Type": "Number", "Description": "Number of instances that need to be running before creation is marked as complete in CloudFormation management console.", "Default": "1", "ConstraintDescription": "Must be an integer in the range specified by MinNumInstances..MaxNumInstances." } }, "Resources": { "MyAutoScalingGroup": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { ... "MinSize": { "Ref": "MinNumInstances" }, "MaxSize": { "Ref": "MaxNumInstances" }, "DesiredCapacity": { "Ref": "DesiredNumInstances" }, ... }, }, ... }, ... }

En el ejemplo anterior, { "Ref": ... } se usa para llenar valores en la plantilla. En este caso, proporcionamos enteros como valores para "MinSize" y "MaxSize" .


AWS::EC2::Instance Resource no admite los parámetros MinCount / MaxCount de la API RunInstances subyacente, por lo que no es posible crear un número variable de instancias de EC2 pasando Parámetros a una sola copia de este Recurso.

Para crear un número variable de recursos de instancia de EC2 en la plantilla de CloudFormation de acuerdo con un Parámetro de plantilla, y sin implementar un Grupo de Auto Escalado, existen dos opciones:

1. Condiciones

Puede usar las Conditions para crear un número variable de Recursos de AWS::EC2::Instance en función del Parámetro.

Es un poco detallado (porque tienes que usar Fn::Equals ), pero funciona.

Este es un ejemplo práctico que permite al usuario especificar hasta un máximo de 5 instancias:

Description: Create a variable number of EC2 instance resources. Parameters: InstanceCount: Description: Number of EC2 instances (must be between 1 and 5). Type: Number Default: 1 MinValue: 1 MaxValue: 5 ConstraintDescription: Must be a number between 1 and 5. ImageId: Description: Image ID to launch EC2 instances. Type: AWS::EC2::Image::Id # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2 Default: ami-9be6f38c InstanceType: Description: Instance type to launch EC2 instances. Type: String Default: m3.medium AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ] Conditions: Launch1: !Equals [1, 1] Launch2: !Not [!Equals [1, !Ref InstanceCount]] Launch3: !Or - !Not [!Equals [1, !Ref InstanceCount]] - !Not [!Equals [2, !Ref InstanceCount]] Launch4: !Or - !Equals [4, !Ref InstanceCount] - !Equals [5, !Ref InstanceCount] Launch5: !Equals [5, !Ref InstanceCount] Resources: Instance1: Condition: Launch1 Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType Instance2: Condition: Launch2 Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType Instance3: Condition: Launch3 Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType Instance4: Condition: Launch4 Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType Instance5: Condition: Launch5 Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType

1a. Preprocesador de plantillas con condiciones

Como una variación de lo anterior, puede usar un preprocesador de plantillas como el Erb de Ruby para generar la plantilla anterior basada en un máximo específico, haciendo que su código fuente sea más compacto y eliminando la duplicación:

<%max = 10-%> Description: Create a variable number of EC2 instance resources. Parameters: InstanceCount: Description: Number of EC2 instances (must be between 1 and <%=max%>). Type: Number Default: 1 MinValue: 1 MaxValue: <%=max%> ConstraintDescription: Must be a number between 1 and <%=max%>. ImageId: Description: Image ID to launch EC2 instances. Type: AWS::EC2::Image::Id # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2 Default: ami-9be6f38c InstanceType: Description: Instance type to launch EC2 instances. Type: String Default: m3.medium AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ] Conditions: Launch1: !Equals [1, 1] Launch2: !Not [!Equals [1, !Ref InstanceCount]] <%(3..max-1).each do |x| low = (max-1)/(x-1) <= 1-%> Launch<%=x%>: !Or <% (1..max).each do |i| if low && i >= x-%> - !Equals [<%=i%>, !Ref InstanceCount] <% elsif !low && i < x-%> - !Not [!Equals [<%=i%>, !Ref InstanceCount]] <% end end end-%> Launch<%=max%>: !Equals [<%=max%>, !Ref InstanceCount] Resources: <%(1..max).each do |x|-%> Instance<%=x%>: Condition: Launch<%=x%> Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType <%end-%>

Para procesar la fuente anterior en una plantilla compatible con CloudFormation, ejecute:

ruby -rerb -e "puts ERB.new(ARGF.read, nil, ''-'').result" < template.yml > template-out.yml

Para su comodidad, aquí hay una idea general del YAML de salida generado para 10 instancias de EC2 variables .

2. Recurso personalizado

Un enfoque alternativo es implementar un recurso personalizado que llame directamente a las API RunInstances / TerminateInstances :

Description: Create a variable number of EC2 instance resources. Parameters: InstanceCount: Description: Number of EC2 instances (must be between 1 and 10). Type: Number Default: 1 MinValue: 1 MaxValue: 10 ConstraintDescription: Must be a number between 1 and 10. ImageId: Description: Image ID to launch EC2 instances. Type: AWS::EC2::Image::Id # amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2 Default: ami-9be6f38c InstanceType: Description: Instance type to launch EC2 instances. Type: String Default: m3.medium AllowedValues: [ m3.medium, m3.large, m3.xlarge, m3.2xlarge ] Resources: EC2Instances: Type: Custom::EC2Instances Properties: ServiceToken: !GetAtt EC2InstancesFunction.Arn ImageId: !Ref ImageId InstanceType: !Ref InstanceType MinCount: !Ref InstanceCount MaxCount: !Ref InstanceCount EC2InstancesFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub | var response = require(''cfn-response''); var AWS = require(''aws-sdk''); exports.handler = function(event, context) { var physicalId = event.PhysicalResourceId || ''none''; function success(data) { return response.send(event, context, response.SUCCESS, data, physicalId); } function failed(e) { return response.send(event, context, response.FAILED, e, physicalId); } var ec2 = new AWS.EC2(); var instances; if (event.RequestType == ''Create'') { var launchParams = event.ResourceProperties; delete launchParams.ServiceToken; ec2.runInstances(launchParams).promise().then((data)=> { instances = data.Instances.map((data)=> data.InstanceId); physicalId = instances.join('':''); return ec2.waitFor(''instanceRunning'', {InstanceIds: instances}).promise(); }).then((data)=> success({Instances: instances}) ).catch((e)=> failed(e)); } else if (event.RequestType == ''Delete'') { if (physicalId == ''none'') {return success({});} var deleteParams = {InstanceIds: physicalId.split('':'')}; ec2.terminateInstances(deleteParams).promise().then((data)=> ec2.waitFor(''instanceTerminated'', deleteParams).promise() ).then((data)=>success({}) ).catch((e)=>failed(e)); } else { return failed({Error: "In-place updates not supported."}); } }; Runtime: nodejs4.3 Timeout: 300 LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: ''2012-10-17'' Statement: - Effect: Allow Principal: {Service: [lambda.amazonaws.com]} Action: [''sts:AssumeRole''] Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: EC2Policy PolicyDocument: Version: ''2012-10-17'' Statement: - Effect: Allow Action: - ''ec2:RunInstances'' - ''ec2:DescribeInstances'' - ''ec2:DescribeInstanceStatus'' - ''ec2:TerminateInstances'' Resource: [''*''] Outputs: Instances: Value: !Join ['','', !GetAtt EC2Instances.Instances]