tipos son servicios que nube modelos los informatica ejemplos ec2 cuáles computing caracteristicas aws amazon-ec2 ami amazon-cloudformation

amazon-ec2 - son - tipos de cloud computing ejemplos



Crea una imagen AMI como parte de una pila de formación de nubes. (4)

  1. No.
  2. Supongo que sí. Una vez que la pila puede utilizar la operación "Actualizar pila". Debe proporcionar la plantilla JSON completa de la pila inicial + sus cambios en el mismo archivo (AMI modificado). Primero ejecutaría esto en un entorno de prueba (no de producción), ya que no estoy realmente seguro de lo que hace la operación al Instancias existentes.

¿Por qué no crea una AMI inicialmente fuera de la formación de nubes y luego la utiliza en la plantilla final de la nube?

Otra opción es escribir algo de automatización para crear dos pilas de información en la nube y puede eliminar la primera una vez que finalice la AMI que ha creado.

Quiero crear una pila de información en la nube EC2 que básicamente se puede describir en los siguientes pasos:

1.- Lanzar instancia.

2.- Aprovisionar la instancia.

3.- Detenga la instancia y cree una imagen AMI a partir de ella.

4.- Cree un grupo de autoescala con la imagen AMI creada como fuente para iniciar nuevas instancias.

Básicamente puedo hacer 1 y 2 en una plantilla de formación de nubes y 4 en una segunda plantilla. Lo que no puedo hacer es crear una imagen AMI desde una instancia dentro de una plantilla de formación de nubes, lo que básicamente genera el problema de tener que eliminar manualmente la AMI si quiero eliminar la pila.

Dicho esto, mis preguntas son:

1.- ¿Hay una manera de crear una imagen AMI desde una instancia DENTRO de la plantilla de formación de nubes?

2.- Si la respuesta a 1 es no, ¿hay una manera de agregar una imagen AMI (o cualquier otro recurso para esa materia) para que sea parte de una pila completa?

EDITAR:

Solo para aclarar, ya resolví el problema de crear la AMI y usarla en una plantilla de información en la nube, simplemente no puedo crear la AMI DENTRO de la plantilla de la nube o agregarla de alguna manera a la pila creada.

Como comenté en la respuesta de Rico, lo que hago ahora es usar un libro de jugabilidad ansible que básicamente tiene 3 pasos:

1.- Crear una instancia base con una plantilla de formación de nubes.

2.- Cree, utilizando ansible, una AMI de la instancia creada en el paso 1

3.- Cree el resto de la pila (ELB, grupos de autoescalado, etc.) con una segunda plantilla de formación de nubes que actualice la creada en el paso 1 y que use la AMI creada en el paso 2 para iniciar instancias.

Así es como lo gestiono ahora, pero quería saber si hay alguna forma de crear un AMI DENTRO de una plantilla de formación de nubes o si es posible agregar el AMI creado a la pila (algo así como decirle a la pila, "Oye, esto pertenece a Tú también, así que manéjalo ").


Para lo que vale, aquí está la variante de Python de la definición AMIFunction de AMIFunction en la respuesta original . Todos los otros recursos en el yaml original permanecen sin cambios:

AMIFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub | import logging import cfnresponse import json import boto3 from threading import Timer from botocore.exceptions import WaiterError logger = logging.getLogger() logger.setLevel(logging.INFO) def handler(event, context): ec2 = boto3.resource(''ec2'') physicalId = event[''PhysicalResourceId''] if ''PhysicalResourceId'' in event else None def success(data={}): cfnresponse.send(event, context, cfnresponse.SUCCESS, data, physicalId) def failed(e): cfnresponse.send(event, context, cfnresponse.FAILED, str(e), physicalId) logger.info(''Request received: %s/n'' % json.dumps(event)) try: instanceId = event[''ResourceProperties''][''InstanceId''] if (not instanceId): raise ''InstanceID required'' if not ''RequestType'' in event: success({''Data'': ''Unhandled request type''}) return if event[''RequestType''] == ''Delete'': if (not physicalId.startswith(''ami-'')): raise ''Unknown PhysicalId: %s'' % physicalId ec2client = boto3.client(''ec2'') images = ec2client.describe_images(ImageIds=[physicalId]) for image in images[''Images'']: ec2.Image(image[''ImageId'']).deregister() snapshots = ([bdm[''Ebs''][''SnapshotId''] for bdm in image[''BlockDeviceMappings''] if ''Ebs'' in bdm and ''SnapshotId'' in bdm[''Ebs'']]) for snapshot in snapshots: ec2.Snapshot(snapshot).delete() success({''Data'': ''OK''}) elif event[''RequestType''] in set([''Create'', ''Update'']): if not physicalId: # AMI creation has not been requested yet instance = ec2.Instance(instanceId) instance.wait_until_stopped() image = instance.create_image(Name="Automatic from CloudFormation stack ${AWS::StackName}") physicalId = image.image_id else: logger.info(''Continuing in awaiting image available: %s/n'' % physicalId) ec2client = boto3.client(''ec2'') waiter = ec2client.get_waiter(''image_available'') try: waiter.wait(ImageIds=[physicalId], WaiterConfig={''Delay'': 30, ''MaxAttempts'': 6}) except WaiterError as e: # Request the same event but set PhysicalResourceId so that the AMI is not created again event[''PhysicalResourceId''] = physicalId logger.info(''Timeout reached, continuing function: %s/n'' % json.dumps(event)) lambda_client = boto3.client(''lambda'') lambda_client.invoke(FunctionName=context.invoked_function_arn, InvocationType=''Event'', Payload=json.dumps(event)) return success({''Data'': ''OK''}) else: success({''Data'': ''OK''}) except Exception as e: failed(e) Runtime: python2.7 Timeout: 300


Sí, puede crear una AMI a partir de una instancia de EC2 dentro de una plantilla de CloudFormation implementando un recurso personalizado que llama a la API CreateImage en la creación (y llama a las API DeleteSnapshot y DeleteSnapshot en la eliminación).

Como las AMI a veces pueden tardar mucho tiempo en crearse, un recurso personalizado respaldado por Lambda tendrá que volver a invocarse a sí mismo si la espera no se ha completado antes de que la función Lambda se agote.

Aquí hay un ejemplo completo:

Description: Create an AMI from an EC2 instance. Parameters: ImageId: Description: Image ID for base EC2 instance. 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: # Completes when the instance is fully provisioned and ready for AMI creation. AMICreate: Type: AWS::CloudFormation::WaitCondition CreationPolicy: ResourceSignal: Timeout: PT10M Instance: Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId InstanceType: !Ref InstanceType UserData: "Fn::Base64": !Sub | #!/bin/bash -x yum -y install mysql # provisioning example /opt/aws/bin/cfn-signal / -e $? / --stack ${AWS::StackName} / --region ${AWS::Region} / --resource AMICreate shutdown -h now AMI: Type: Custom::AMI DependsOn: AMICreate Properties: ServiceToken: !GetAtt AMIFunction.Arn InstanceId: !Ref Instance AMIFunction: 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) { console.log("Request received:/n", JSON.stringify(event)); var physicalId = event.PhysicalResourceId; function success(data) { return response.send(event, context, response.SUCCESS, data, physicalId); } function failed(e) { return response.send(event, context, response.FAILED, e, physicalId); } // Call ec2.waitFor, continuing if not finished before Lambda function timeout. function wait(waiter) { console.log("Waiting: ", JSON.stringify(waiter)); event.waiter = waiter; event.PhysicalResourceId = physicalId; var request = ec2.waitFor(waiter.state, waiter.params); setTimeout(()=>{ request.abort(); console.log("Timeout reached, continuing function. Params:/n", JSON.stringify(event)); var lambda = new AWS.Lambda(); lambda.invoke({ FunctionName: context.invokedFunctionArn, InvocationType: ''Event'', Payload: JSON.stringify(event) }).promise().then((data)=>context.done()).catch((err)=>context.fail(err)); }, context.getRemainingTimeInMillis() - 5000); return request.promise().catch((err)=> (err.code == ''RequestAbortedError'') ? new Promise(()=>context.done()) : Promise.reject(err) ); } var ec2 = new AWS.EC2(), instanceId = event.ResourceProperties.InstanceId; if (event.waiter) { wait(event.waiter).then((data)=>success({})).catch((err)=>failed(err)); } else if (event.RequestType == ''Create'' || event.RequestType == ''Update'') { if (!instanceId) { failed(''InstanceID required''); } ec2.waitFor(''instanceStopped'', {InstanceIds: [instanceId]}).promise() .then((data)=> ec2.createImage({ InstanceId: instanceId, Name: event.RequestId }).promise() ).then((data)=> wait({ state: ''imageAvailable'', params: {ImageIds: [physicalId = data.ImageId]} }) ).then((data)=>success({})).catch((err)=>failed(err)); } else if (event.RequestType == ''Delete'') { if (physicalId.indexOf(''ami-'') !== 0) { return success({});} ec2.describeImages({ImageIds: [physicalId]}).promise() .then((data)=> (data.Images.length == 0) ? success({}) : ec2.deregisterImage({ImageId: physicalId}).promise() ).then((data)=> ec2.describeSnapshots({Filters: [{ Name: ''description'', Values: ["*" + physicalId + "*"] }]}).promise() ).then((data)=> (data.Snapshots.length === 0) ? success({}) : ec2.deleteSnapshot({SnapshotId: data.Snapshots[0].SnapshotId}).promise() ).then((data)=>success({})).catch((err)=>failed(err)); } }; 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 - arn:aws:iam::aws:policy/service-role/AWSLambdaRole Policies: - PolicyName: EC2Policy PolicyDocument: Version: ''2012-10-17'' Statement: - Effect: Allow Action: - ''ec2:DescribeInstances'' - ''ec2:DescribeImages'' - ''ec2:CreateImage'' - ''ec2:DeregisterImage'' - ''ec2:DescribeSnapshots'' - ''ec2:DeleteSnapshot'' Resource: [''*''] Outputs: AMI: Value: !Ref AMI


Si bien la solución de @ wjdordan es buena para casos de uso simples, la actualización de los Datos del usuario no actualizará la AMI.

(DESCARGO DE RESPONSABILIDAD: Soy el autor original) cloudformation-ami tiene como objetivo permitirle declarar las AMI en CloudFormation que se pueden crear, actualizar y eliminar de forma confiable. Uso de cloudformation-ami Puede declarar AMI personalizadas de la siguiente manera:

MyAMI: Type: Custom::AMI Properties: ServiceToken: !ImportValue AMILambdaFunctionArn Image: Name: my-image Description: some description for the image TemplateInstance: ImageId: ami-467ca739 IamInstanceProfile: Arn: arn:aws:iam::1234567890:instance-profile/MyProfile-ASDNSDLKJ UserData: Fn::Base64: !Sub | #!/bin/bash -x yum -y install mysql # provisioning example # Signal that the instance is ready INSTANCE_ID=`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id` aws ec2 create-tags --resources $INSTANCE_ID --tags Key=UserDataFinished,Value=true --region ${AWS::Region} KeyName: my-key InstanceType: t2.nano SecurityGroupIds: - sg-d7bf78b0 SubnetId: subnet-ba03aa91 BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeSize: ''10'' VolumeType: gp2