Esta publicación de blog cubre los conceptos básicos de las imágenes de contenedores personalizadas de AWS Lambda, cuándo usarlas y cómo crearlas con Docker y AWS CDK en Python.
Cómo crear funciones de AWS Lambda con dependencias externas
Cuando crea una función de AWS Lambda, proporciona el código del controlador y sus módulos internos (capa lógica, controladores de base de datos, etc.). Sin embargo, la mayoría de las veces, su código depende de dependencias externas. Cuando se ejecuta su función Lambda, se ejecuta en una imagen base de contenedor de AWS. Es posible que la imagen de contenedor proporcionada por AWS no contenga todas sus dependencias externas. En ese caso, debe proporcionarlas usted mismo.
Tienes cuatro opciones:
Cree y cargue una imagen de contenedor Lambda que usted mismo cree, que incluya el código del controlador y todas las dependencias externas, y cárguela en el repositorio de Amazon ECR.
Cree y cargue un archivo ZIP que contenga todo el código Lambda y las dependencias externas según la función AWS Lambda. Vea ejemplos de código aquí .
Cree y cargue un archivo ZIP que contenga dependencias externas como una capa de AWS Lambda. Vea ejemplos de código y explicaciones técnicas aquí .
Utilice un ARN de capa Lambda existente que contenga las dependencias externas.
En este blog, nos centraremos en la opción número uno: crear una imagen de contenedor Lambda.
Mi publicación anterior se centró en las opciones tres y cuatro.
¿Qué es una imagen de contenedor Lambda?
Las imágenes de contenedor de AWS Lambda proporcionan una forma conveniente de empaquetar bibliotecas y otras dependencias que puede usar con sus funciones Lambda.
AWS Lambda admite imágenes de hasta 10 GB de tamaño, a diferencia de los métodos de compilación de la función Lambda normal que permiten dependencias descomprimidas de solo hasta 250 MB.
AWS CDK requiere un Dockerfile para crear la imagen del contenedor. Una vez creada, se carga en Amazon ECR (Elastic Container Registry), donde se almacenará y la función Lambda la usará durante la invocación.
¿Cuándo deberías usarlo?
Las imágenes de contenedor de AWS Lambda son un método válido para crear funciones Lambda.
Sin embargo, es más complejo que crear capas Lambda o usar el creador ZIP de dependencias integrado de CDK. como se describe en las opciones 2 a 4 anteriores.
Además, las imágenes de contenedores presentan muchas desventajas:
En comparación con las alternativas (opciones 2 a 4 en las opciones de compilación de Lambda mencionadas anteriormente), debe escribir un archivo Docker, lo que no es una excelente experiencia de usuario.
La creación de una imagen requiere mucho más tiempo que las alternativas. La imagen contiene el entorno de ejecución de Lambda, el código del controlador y sus dependencias. El resultado será mucho más grande que los archivos ZIP que cree en las alternativas.
Subes una imagen a Amazon ECR y pagas por su almacenamiento , mientras que en las otras opciones no es así.
Las imágenes más grandes tardan más en crearse y cargarse, lo que hace que el tiempo de producción sea mayor que crear una capa o un ZIP que contenga solo el código Lambda y sus dependencias.
Considero que las imágenes de contenedores Lambda son un nicho y creo que deberías usarlas solo en casos en los que:
Desea tener control total de la imagen del contenedor por razones de seguridad u optimizaciones personalizadas.
Tu código tiene dependencias que superan los 250 MB al descomprimirlo. Ese es el principal factor a favor de su uso. Así de simple.
Cree un contenedor Lambda con AWS CDK y Docker en Python con Poetry
Nuestro objetivo
Supongamos que nuestro servicio Serverless utiliza poesía para la gestión de dependencias y que el archivo pyproject.toml se ve así:
Queremos agrupar nuestro código de función Lambda y sus dependencias (AWS Lambda Powertools, mypy-boto3-dynamodb, cachetools y otros) en una imagen de contenedor de imágenes Lambda e implementarlo con AWS CDK.
AWS CDK creará una imagen de contenedor, la cargará en Amazon ECR, el repositorio de contenedores, y configurará una función de AWS Lambda para usarla como su imagen de contenedor.
Suposiciones
Instalaste Docker.
Instaló AWS CDK.
Utilice la poesía como su administrador de dependencias de Python.
Utilice un único archivo pyproject.toml general para todas las funciones de AWS Lambda. Incluye todos los requisitos de todas las funciones.
Empezando
Antes de escribir cualquier código CDK, debemos preparar el archivo dockerfile y el archivo Lambda requirements.txt, que describe las dependencias Lambda requeridas y sus versiones.
Almacenaremos todos los artefactos de compilación necesarios en una nueva carpeta: la carpeta '.build', que no será parte de la base del código.
Primero, necesitamos crear un archivo requirements.txt desde nuestro pyproject.toml.
En este ejemplo, usamos poesía, pero pipenv también es una opción.
Generamos un requirements.txt desde la sección [tool.poetry.dependencies] del archivo toml.
A diferencia de la sección [tool.poetry.dev-dependencies] en el toml, las bibliotecas en la sección 'tool.poetry.dependencies' son las bibliotecas que las funciones Lambda en el proyecto requieren en tiempo de ejecución y deben cargarse en AWS.
Ejecute el siguiente comando para crear la carpeta '.build/ecr' y generar el archivo requirements.txt.
El archivo generado podría verse así:
Ahora, agregamos el código del controlador Lambda. Supongamos que en nuestro proyecto, los controladores de funciones Lambda se encuentran en la carpeta raíz del proyecto, en la carpeta "service".
Antes de crear e implementar las funciones Lambda en AWS, copiamos la carpeta "service" en la carpeta ".build/ecr". El código CDK que crea la imagen del contenedor Lambda tomará el código del controlador Lambda, requirements.txt y Dockerfile de la carpeta ".build/ecr".
Ahora, todo lo que queda es crear un Dockerfile y copiarlo en la carpeta '.build/ecr'.
Tiempo de Dockerfile
Como se menciona en los documentos oficiales de AWS, la imagen de su contenedor debe implementar la API de tiempo de ejecución de Lambda:
AWS ofrece un conjunto de imágenes base de código abierto que puede utilizar para crear su imagen de contenedor. Estas imágenes base incluyen un cliente de interfaz de tiempo de ejecución para administrar la interacción entre Lambda y su código de función.
Utilizaremos una imagen de contenedor base y comenzaremos a construir a partir de ella.
La línea 1 configura la imagen base. Usamos una imagen oficial compatible con AWS Python 3.9 y usamos la versión más reciente.
La línea 4 copia el archivo requirements.txt en la carpeta raíz, mientras que la línea 7 instala las dependencias de Lambda en la carpeta raíz de la tarea Lambda. Como se especifica aquí , la variable de entorno define la carpeta donde se encuentra el código.
Las líneas 9 y 10 copian el código del controlador y sus módulos internos, la carpeta 'servicio' y sus subcarpetas en la carpeta del código lambda.
La línea 13 establece la función de entrada del controlador de la función Lambda. En mi proyecto, el servicio tenía una carpeta interna llamada 'handlers' donde se encuentra un 'create_order.py' con una función llamada 'create_order' dentro como su punto de entrada.
¡Eso es todo!
Ahora debería tener la siguiente estructura de carpeta '.build':
Consejo general:
Le recomiendo que utilice un Makefile o cualquier script simple para automatizar estas acciones antes del comando 'cdk deployment'.
Implementación de CDK
Ahora que todo está en su lugar, escribamos una construcción CDK que cree una imagen de contenedor Lambda y una función Lambda que se construya de acuerdo con la configuración en la carpeta '.build/ecr'.
La construcción 'MyConstruct' de AWS CDK crea:
Rol básico de Lambda (líneas 14-20).
Función Lambda basada en la imagen del contenedor (líneas 22-30). CDK busca un requirements.txt y un Dockerfile en el directorio de activos ('.build/ecr') y utiliza Docker para crear la imagen del contenedor. Una vez creada, se carga en Amazon ECR.
Te pillé en Mac M1
En la línea 29, especificamos la arquitectura Lambda como ARM64. Como estaba usando una Mac con un chip M1, tuve que configurar este parámetro como ARM64. Cuando no lo especifiqué, la función Lambda no pudo iniciarse y generó un error de punto final que no tenía ningún sentido (¡por suerte, se llamó a stackoverflow para ayudarme!).
Una vez implementado, diríjase a la consola de AWS Lambda y busque la pestaña "imagen":
Como puede ver, la imagen se cargó en Amazon ECR y tiene la arquitectura ARM64.