Tutorial: búsqueda de ID de AMI con un recurso personalizado respaldado por Lambda - AWS CloudFormation

Tutorial: búsqueda de ID de AMI con un recurso personalizado respaldado por Lambda

En este tutorial, se muestra cómo utilizar Lambda y un recurso personalizado para buscar dinámicamente los ID de imagen de máquina de Amazon (AMI) en la plantilla de CloudFormation. Esto puede ayudarlo a agilizar la actualización de los ID de AMI en las plantillas de CloudFormation.

Al crear una plantilla de CloudFormation para lanzar una instancia de Amazon EC2, debe especificar un ID de AMI, que es como una plantilla para el sistema operativo y el software que se instalarán en la instancia. El ID de AMI correcto depende del tipo de instancia y la Región de AWS en la que va a lanzar la instancia. Estos ID pueden cambiar con regularidad, como cuando una AMI se actualiza con actualizaciones de software.

Por lo general, el ID de AMI se especifica en una sección de Mappings que asigna los ID de AMI a tipos de instancias y regiones específicos. Esto significa que, para actualizar los ID, debe cambiarlos manualmente en cada una de las plantillas. Sin embargo, mediante el uso de los recursos personalizados y Lambda, puede crear una función que obtenga los ID de las últimas AMI para el tipo de instancia y la región que está utilizando. De esta forma, no tiene que mantener manualmente las asignaciones entre los ID de AMI, los tipos de instancias y las regiones en las plantillas de pila.

Este tutorial muestra cómo crear un recurso personalizado y asociarle una función de Lambda para buscar los ID de AMI. Se supone que conoce los recursos personalizados y las funciones de Lambda. Para obtener una introducción a los recursos personalizados y a su funcionamiento, consulte Crear una lógica de aprovisionamiento personalizada con recursos personalizados. Para obtener información acerca de Lambda, consulte la Guía para desarrolladores de AWS Lambda.

nota

CloudFormation es un servicio gratis; sin embargo, se le cobrará por los recursos de AWS, como la función de Lambda y la instancia EC2, que incluya en las pilas aplicando la tarifa actual de cada uno. Para obtener más información sobre los precios de AWS, consulte la página de detalles correspondiente a cada producto en http://aws.amazon.com.

Como alternativa a la creación de un recurso personalizado y una función de Lambda, puede utilizar los parámetros AWS Systems Manager de la plantilla para recuperar el último valor de ID de AMI almacenado en un parámetro de Systems Manager. Esto hace que sus plantillas sean más sencillas y fáciles de mantener. Para obtener más información, consulte Referencia a los recursos existentes y a los parámetros de Systems Manager con los tipos de parámetros proporcionados por CloudFormation.

Información general

Los siguientes pasos proporcionan una descripción general de esta implementación.

  1. Guarde un paquete de ejemplo que contenga el código de la función de Lambda en un bucket de Amazon S3 en la misma Región de AWS donde desea crear su instancia de EC2.

  2. Utilice la plantilla de ejemplo para crear la pila con un recurso personalizado, una función de Lambda, una instancia de EC2 y un rol de IAM que Lambda utiliza para realizar llamadas a Amazon EC2.

  3. La pila asocia la función de Lambda al recurso personalizado. Cuando se crea la pila, CloudFormation invoca la función y le envía información como el tipo de solicitud, los datos de entrada y una URL prefirmada de Amazon S3.

  4. La función de Lambda utiliza los datos de entrada para buscar el ID de la última AMI y envía este ID como respuesta a la URL prefirmada.

  5. CloudFormation recibe una respuesta en la ubicación de la URL prefirmada y procede a crear la pila. Cuando CloudFormation crea la instancia, utiliza el ID de AMI que proporciona la función de Lambda para crear la instancia de EC2 con la AMI más reciente.

Tutorial de plantilla

Para ver toda la plantilla de ejemplo, consulte:

Los siguientes fragmentos explican las partes importantes de la plantilla de ejemplo para ayudarle a entender cómo asociar una función de Lambda a un recurso personalizado y cómo utilizar la respuesta de la función.

AMIInfoFunction del recurso AWS::Lambda::Function

El recurso AWS::Lambda::Function especifica el código fuente de la función, el nombre del controlador, el entorno del tiempo de ejecución y el nombre de recurso de Amazon (ARN).

  • La propiedad Code especifica la ubicación de Amazon S3 (nombre de bucket y de archivo) donde ha cargado el paquete de ejemplo. La plantilla de ejemplo utiliza parámetros de entrada ("Ref": "S3Bucket" y "Ref": "S3Key") para establecer los nombres de bucket y archivo para poder especificar los nombres al crear la pila. Del mismo modo, el nombre del gestor, que se corresponde con el nombre del archivo de origen (el archivo JavaScript) en el paquete .zip, también utiliza un parámetro de entrada ("Ref": "ModuleName"). Dado que el archivo de origen es un código JavaScript, se especifica el tiempo de ejecución como nodejs18.x.

  • Para el código utilizado en este recorrido, el tiempo de ejecución de la función excede el valor predeterminado de 3 segundos, por lo que el tiempo de espera se establece en 30 segundos. Si no especifica un tiempo de espera lo bastante largo, Lambda podría agotar dicho tiempo antes de que se complete la función, fracasando la creación de la pila.

  • La propiedad Role usa la función Fn::GetAtt para obtener el ARN del rol de ejecución LambdaExecutionRole que se declara en otra parte de la plantilla.

JSON

"AMIInfoFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Ref": "S3Bucket" }, "S3Key": { "Ref": "S3Key" } }, "Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".handler"] ] }, "Runtime": "nodejs18.x", "Timeout": "30", "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] } } }

YAML

AMIInfoFunction: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Ref S3Bucket S3Key: !Ref S3Key Handler: !Sub "${ModuleName}.handler" Runtime: nodejs18.x Timeout: 30 Role: !GetAtt LambdaExecutionRole.Arn

LambdaExecutionRole del recurso AWS::IAM::Role

El rol de ejecución concede permiso a la función de Lambda para enviar registros a AWS y para llamar a la API DescribeImages de EC2.

JSON

"LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["lambda.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }] }, "Path": "/", "Policies": [{ "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": ["ec2:DescribeImages"], "Resource": "*" }] } }] } }

YAML

LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* - Effect: Allow Action: - ec2:DescribeImages Resource: "*"

AMIInfo del recurso Custom::AMIInfo

Para las plantillas de Linux y Windows, el recurso personalizado invoca la función de Lambda que tiene asociada. Para asociar una función con un recurso personalizado, debe especificar el ARN de la función de la propiedad ServiceToken con la función intrínseca Fn::GetAtt. CloudFormation envía las propiedades adicionales que se incluyen en la declaración de los recursos personalizados, como Region y Architecture a la función de Lambda como entradas. La función de Lambda determina los nombres y los valores correctos de estas propiedades de entrada.

JSON

"AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] }, "Region": { "Ref": "AWS::Region" }, "Architecture": { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } } }

YAML

AMIInfo: Type: Custom::AMIInfo Properties: ServiceToken: !GetAtt AMIInfoFunction.Arn Region: !Ref "AWS::Region" Architecture: Fn::FindInMap: - AWSInstanceType2Arch - !Ref InstanceType - Arch

En el caso de Windows, el recurso personalizado proporciona la versión de Windows a la función de Lambda en lugar de la arquitectura de la instancia.

JSON

"AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "ServiceToken": { "Fn::GetAtt": ["AMIInfoFunction", "Arn"] }, "Region": { "Ref": "AWS::Region" }, "OSName": { "Ref": "WindowsVersion" } } }

YAML

AMIInfo: Type: Custom::AMIInfo Properties: ServiceToken: !GetAtt AMIInfoFunction.Arn Region: !Ref "AWS::Region" OSName: !Ref "WindowsVersion"

Cuando CloudFormation invoca la función de Lambda, la función llama a la API DescribeImages de EC2, que usa la Región de AWS y la arquitectura de instancias o el nombre del sistema operativo para filtrar la lista de imágenes. A continuación, la función ordena la lista de imágenes por fecha y devuelve el ID de la AMI más reciente.

Cuando devuelve el ID de la última AMI, la función envía el ID a una URL prefirmada en la propiedad Data del objeto de respuesta. Los datos se estructuran como un par de nombre-valor, como se muestra en el ejemplo siguiente:

"Data": { "Id": "ami-02354e95b3example" }

SampleInstance del recurso AWS::EC2::Instance

El siguiente fragmento muestra cómo obtener los datos de una función de Lambda. Utiliza la función intrínseca Fn::GetAtt, proporcionando el nombre del recurso personalizado y el nombre de atributo del valor que desee obtener. En este tutorial, el nombre del recurso personalizado es AMIInfo y el nombre del atributo es Id.

JSON

"SampleInstance": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType" : { "Ref": "InstanceType" }, "ImageId": { "Fn::GetAtt": [ "AMIInfo", "Id" ] } } }

YAML

SampleInstance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType ImageId: !GetAtt AMIInfo.Id

Requisitos previos

Para poder completar los pasos de creación de la pila, es preciso disponer de un bucket de Amazon S3. Al crear una pila con una función de Lambda, debe especificar la ubicación del bucket de Amazon S3 que contiene el código fuente de la función. El bucket debe estar en la misma Región de AWS en la que crea su pila. Para obtener más información acerca de la creación de un bucket, consulte Crear un bucket en la Guía del usuario de Amazon Simple Storage Service.

Se necesitan permisos de IAM para utilizar todos los servicios correspondientes, como Lambda, Amazon EC2 y CloudFormation.

Paso 1: guardar el paquete Lambda de ejemplo en Amazon S3

En este paso, cargue el paquete Lambda de ejemplo (un archivo .zip) a su bucket de Amazon S3.

Este paquete contiene el código fuente de la función de Lambda y las bibliotecas necesarias. En este tutorial, la función no requiere bibliotecas adicionales.

Cómo guardar el paquete de ejemplo en Amazon S3
  1. Descargue el paquete de ejemplo de Amazon S3. Cuando guarde el archivo, utilice el mismo nombre de archivo que la muestra amilookup.zip o amilookup-win.zip.

  2. Abra la consola de Amazon S3 en https://console.aws.amazon.com/s3/home.

  3. En la barra de navegación de la parte superior de la pantalla, elija la Región de AWS que utilizó cuando creó su bucket de Amazon S3.

  4. En la lista Buckets, elija el nombre del bucket. Anote el nombre del bucket, ya que lo usará al crear la pila.

  5. Seleccione Cargar.

  6. Debajo de Cargar, en Archivos y carpetas, suba el paquete de ejemplo al bucket. Para obtener más información, consulte Carga de objetos en la Guía del desarrollador de Amazon Simple Storage Service.

Paso 2: lanzar la pila

En este paso, ejecutará una pila a partir de una plantilla de ejemplo. La pila incluye una función de Lambda, un rol de IAM (rol de ejecución), un recurso personalizado que invoque la función y una instancia de EC2 que utilice los resultados de la función.

Durante la creación de la pila, el recurso personalizado invoca la función de Lambda y espera hasta que la función envía una respuesta a la URL de Amazon S3 prefirmada. En la respuesta, la función devuelve el ID de la última AMI que se corresponda con el tipo de instancia de EC2 y la Región de AWS en la que está creando la instancia. Los datos de la respuesta de la función se almacenan como un atributo del recurso personalizado, que se utiliza para especificar el ID de AMI de la instancia de EC2.

Para crear la pila
  1. Abra la consola de CloudFormation en https://console.aws.amazon.com/cloudformation/.

  2. Elija Crear pila.

  3. En la sección Template (Plantilla), elija Specify an Amazon S3 template URL (Especificar una URL de plantilla de Amazon S3) y, a continuación, copie y pegue la siguiente URL en el cuadro de texto:

    Plantilla de Linux

    https://s3.amazonaws.com/cloudformation-examples/lambda/LambdaAMILookupSample.template

    Plantilla de Windows

    https://s3.amazonaws.com/cloudformation-examples/lambda/LambdaAMILookupSample-win.template

  4. Elija Siguiente.

  5. En el campo Stack name (Nombre de pila), escriba SampleEC2Instance.

  6. En la sección Parameters (Parámetros), especifique el nombre del bucket de Amazon S3; que ha creado y, a continuación, elija Next (Siguiente).

    Los valores predeterminados para el resto de los parámetros son los mismos nombres que se utilizan en el paquete .zip de ejemplo.

  7. Para este tutorial, no tiene que añadir etiquetas ni especificar una configuración avanzada, así que elija Next (Siguiente).

  8. Asegúrese de que el nombre de la pila y la URL de la plantilla sean correctos y elija Create (Crear).

CloudFormation puede tardar varios minutos en crear la pila. Para monitorizar el progreso, vea los eventos de la pila. Para obtener más información, consulte Visualización de la información de la pila desde la consola de CloudFormation.

Si se crea la pila correctamente, se crean todos los recursos de la pila, como la función de Lambda, el recurso personalizado y la instancia de EC2. Ha utilizado de forma satisfactoria una función de Lambda y un recurso personalizado para especificar el ID de AMI de una instancia de EC2. No es necesario crear y mantener un mapeo de los ID de AMI en esta plantilla.

Para ver qué ID de AMI usó CloudFormation para crear la instancia de EC2, vea las salidas de la pila.

Si la función de Lambda devuelve un error, vea los registros de la función en la consola de Registros de CloudWatch. El nombre de la flujo de registros es el ID físico del recurso personalizado, que puede encontrar al visualizar los recursos de la pila. Para obtener más información, consulte la sección de Visualización de datos de registro en la Guía del usuario de Amazon CloudWatch.

Paso 3: Limpiar recursos

Elimine la pila para limpiar todos los recursos de la pila que creó para que no se le cobren los recursos innecesarios.

Para eliminar la pila
  1. En la consola de CloudFormation, elija la pila SampleEC2Instance.

  2. Elija Actions (Acciones) y, a continuación, Delete Stack (Eliminar pila).

  3. En el mensaje de confirmación, elija Yes, Delete (Sí, eliminar).

Se eliminan todos los recursos que creó.

Ahora que entiende cómo crear y utilizar funciones de Lambda con CloudFormation, puede usar el código y la plantilla de ejemplo de este tutorial para crear otras pilas y funciones.

Información relacionada