¿Qué hace que un controlador de AWS Lambda sea resistente, rastreable y fácil de mantener? ¿Cómo se escribe un código de este tipo?
En esta serie de blogs, intentaré responder estas preguntas compartiendo mis conocimientos y las mejores prácticas de AWS Lambda, para que no cometa los mismos errores que yo cometí antes.
Esta serie de blogs presenta progresivamente las mejores prácticas y utilidades agregando una utilidad a la vez.
La parte 1 se centró en el registro.
La segunda parte se centró en la observabilidad: seguimiento y rastreo.
La parte 3 se centró en la observabilidad del dominio empresarial .
La parte 5 se centró en la validación de entrada .
La parte 6 se centró en la configuración y los indicadores de características.
La parte 7 se centró en cómo iniciar su propio servicio sin servidor en dos clics.
Parte 8 centrado en las mejores prácticas de AWS CDK .
Este blog se centra en las mejores prácticas en variables de entorno.
El código de esta publicación se ha trasladado a un proyecto de código abierto que puedes usar: El modelador de variables de entorno de AWS:
Proporcionaré un proyecto de plantilla de controlador AWS Lambda en Python, funcional y de código abierto.
Este controlador incorpora las mejores prácticas sin servidor y tiene todas las características necesarias para un controlador adecuado y listo para producción.
Durante esta serie de blogs, cubriré el registro, la observabilidad, la validación de entrada, los indicadores de características, la configuración dinámica y cómo usar variables de entorno de forma segura.
Si bien los ejemplos de código están escritos en Python, los principios son válidos para todos los lenguajes de programación compatibles con las funciones de AWS Lambda.
Puede encontrar la mayoría de los ejemplos en este repositorio de GitHub , incluido el código de implementación de CDK.
Según la documentación oficial de AWS Lambda, “ las variables de entorno son pares de cadenas (clave-valor) almacenadas en la configuración específica de la versión de una función”.
Las variables de entorno suelen considerarse una herramienta esencial. Sirven como configuración estática de la función Lambda de AWS. Sus valores se establecen durante la implementación de Lambda y la única forma de cambiarlos es volver a implementar la función Lambda con valores actualizados.
Sin embargo, muchos ingenieros las utilizan de forma insegura a pesar de ser una parte integral y fundamental de cualquier implementación de funciones de AWS Lambda. Este uso puede provocar errores desagradables o incluso fallas en la producción.
Este blog le mostrará cómo analizar, validar y utilizar correctamente sus variables de entorno en su AWS Lambda de Python, tanto en el código de implementación como en el código de función de AWS Lambda.
Los conceptos básicos
Comencemos con los supuestos fundamentales.
Las variables de entorno de Python se almacenan en un diccionario en el módulo 'os' — os.environ . Se puede acceder individualmente a estas variables, pares de cadenas de clave-valor, llamando a os.getenv('my_var_name') . Si 'my_var_name' no está definido como una variable de entorno, esta función devolverá un objeto None en lugar de una cadena .
Las variables de entorno de la función AWS Lambda se definen en un código de implementación de una infraestructura como marco de código como AWS CDK / Serverless / Terraform , etc.
Malas prácticas en variables de entorno comunes
Uso esporádico e inseguro de os.getenv
Muchos desarrolladores acceden a os.getenv esporádicamente en los archivos de función de AWS Lambda.
Sin embargo, normalmente no comprueban que los valores sean válidos. Además , algunos valores de variables de entorno pueden tener suposiciones ocultas. Por ejemplo, pueden representar un formato de cadena ARN válido o un punto final HTTP REST. Sin embargo, la mayoría de los desarrolladores no validan los valores durante el tiempo de ejecución.
Asumen que todo está bien ya que sus pruebas no fallaron.
Si su cobertura de pruebas es realmente excelente y cubre cada llamada a os.getenv , es posible que estén fuera del alcance del peligro. Sin embargo, supongamos que ese no es el caso; un error o falla horrible podría acechar en el código, esperando una configuración incorrecta en el código de implementación de AWS Lambda.
En otros casos, las variables de entorno sirven como valores de configuración personalizados para bibliotecas y dependencias de terceros. No validar estos valores de configuración antes de usarlos puede provocar un comportamiento inesperado o errores. Piense en un registrador, un rastreador de observabilidad o un controlador de base de datos cuya configuración predeterminada desee anular.
Desorden en el código de implementación
Cuando se definen variables de entorno en infraestructuras como marcos de código como CDK/Serverless/Terraform, normalmente se comienza con un pequeño diccionario de variables de entorno y sus valores. Sin embargo, este diccionario aumentará de tamaño y será más difícil de mantener con el tiempo. Es fundamental comprender qué variables se utilizan y por qué.
Dado que las variables se utilizan en numerosos lugares del código de la función o de sus dependencias de terceros (como se explicó anteriormente), hacer un seguimiento de qué variables se utilizan y cuáles se pueden eliminar de forma segura se convierte en un desafío. Además, debido a que la cobertura de las pruebas no es perfecta, eliminar las variables de entorno se convierte en una operación riesgosa.
Entonces la gente no lo hace y las variables rara vez se eliminan.
Prácticas recomendadas para variables de entorno
Queremos abordar ambas malas prácticas mencionadas anteriormente.
En primer lugar, debemos definir un esquema de variables de entorno por controlador. Este esquema nos informa con precisión qué variables de entorno utiliza la función AWS Lambda en todo su código y dependencias. El esquema también puede definir restricciones de valores.
En segundo lugar, validaremos y analizaremos las variables de entorno según el esquema predefinido cuando se active la función AWS Lambda. Una validación Se genera una excepción con todos los detalles de excepción relevantes en caso de una configuración incorrecta.
En tercer lugar, necesitamos una función de obtención global para las variables de entorno validadas que cualquier archivo en la función AWS Lambda pueda llamar.
Y por último, el código de implementación, es decir, el código CDK/Serverless, definirá y establecerá solo las variables que forman parte del esquema.
Bien, pasemos a la solución propuesta.
Herramientas del oficio
Definiremos y analizaremos el esquema con Pydantic , una biblioteca de validación y análisis orientada al rendimiento. Lea más sobre Pydantic en mi primer blog .
El inicializador de variables de entorno proporcionará el diccionario ' os.environ' como entrada al analizador de Pydantic. Pydantic generará una excepción 'ValidationError' muy detallada si uno o más parámetros no superan la validación.
Además, nos gustaría acceder a estas variables en todos los archivos de función de AWS Lambda con la misma facilidad de uso que nos proporciona llamar a 'os.getenv', PERO de manera segura.
Llamaremos a una función getter que devuelve una instancia global de la configuración analizada.
Es importante tener en cuenta que 'os.getenv' todavía funciona y puede ser utilizado por dependencias de terceros.
Inicializar y analizar variables de entorno
Definamos un nuevo decorador de Python que inicializará las variables de entorno: ' init_environment_variables'.
Utilizaremos la fábrica de middleware de AWS Lambda Powertools , el decorador ' lambda_handler_decorator' para crear un nuevo decorador de controlador de AWS Lambda.
Echemos un vistazo al código a continuación.
En la línea 10, definimos una instancia de esquema global, ' ENV_CONF.'
En la línea 13, utilizamos la fábrica de middleware de AWS Lambda Powertools para convertir 'init_environment_variables' en un decorador. El decorador acepta tres parámetros de decorador de controlador de AWS Lambda habituales (controlador, evento y contexto) y uno propio: el parámetro ' model' . Este parámetro es el nombre de la clase del esquema que definimos.
En la línea 18, ocurre la magia. Pasamos el diccionario 'os.environ' como kwargs al constructor de la clase ' model ' de Pydantic. Pydantic generará una excepción ' ValidationError ' detallada en caso de que el diccionario de variables de entorno no supere la validación.
Una vez que el código llega a la línea 22, se analiza y valida la instancia global ' ENV_CONF ', y el controlador Lambda se puede activar de forma segura.
En la línea 25, la función de obtención global, ' get_environment_variables', devolverá 'ENV_CONF' Instancia global. Se puede llamar en cualquier parte del código del controlador AWS Lambda, incluidas las funciones internas.
Colocaremos este código en el archivo del analizador de entorno en la carpeta de utilidades, ya que todos los controladores y funciones lo utilizan. Cada controlador puede definir un esquema diferente.
¡Es hora del esquema!
Definamos un esquema Pydantic con el nombre ' MyHandlerEnvVars .'
Si recuerdas, implementamos utilidades de registro, seguimiento y métricas en las tres partes anteriores de esta serie de blogs . Podemos configurar estas utilidades con variables de entorno y cambiar el nombre del servicio y el nivel de registro .
Además, supongamos que nuestro controlador, ' my_handler ', requiere dos variables adicionales: un ARN de rol que asume durante su ejecución y una URL de punto final de API REST HTTP que utiliza.
Definiremos las cuatro variables en el esquema siguiente.
Todos los esquemas de Pydantic extienden la clase ' BaseModel' de Pydantic, convirtiéndolos en una clase de datos.
El esquema define cuatro variables de entorno: ' LOG_LEVEL', 'POWERTOOLS_SERVICE_NAME', ' ROLE_ARN' y ' REST_API'.
En la línea 6 , 'MyHandlerEnvVars' extiende la clase 'BaseModel' predeterminada de Pydantic.
Este esquema garantiza que:
'LOG_LEVEL' es una de las cadenas de la lista literal.
'ROLE_ARN' existe y tiene entre 20 y 2048 caracteres de longitud, como se define aquí.
'REST_API' es una URL HTTP válida.
'POWERTOOLS_SERVICE_NAME' es una cadena no vacía.
El esquema residirá en una nueva carpeta de esquemas debajo de la carpeta de controladores.
Poniéndolo todo junto
Agreguemos las utilidades de inicialización y obtención de variables de entorno a las utilidades de registrador, trazador y métrica ya implementadas en los blogs anteriores.
Puede encontrar todos los ejemplos de código en este repositorio de GitHub.
En la línea 8, importamos el esquema de variables de entorno del controlador.
En la línea 9, importamos las dos funciones de inicialización y obtención que colocamos en la carpeta de utilidades.
En la línea 18, agregamos el nuevo decorador, ' init_environment_variables ', y establecemos el argumento 'model' en ' MyHandlerEnvVars ', el esquema definido previamente.
En la línea 25, usamos la función getter para acceder a la clase de datos del esquema analizado global de nuestras variables de entorno, y en la línea 26, registramos las cuatro variables de nuestro esquema.
Código de implementación
Este código de AWS CDK define las variables del esquema ' MyHandlerEnvVars' y establece sus valores. Observe específicamente la función '__add_post_lambda_integration'.
Próximamente
Con esto concluye la cuarta parte de la serie.
Únase a mí en la siguiente parte sobre ranthebuilder.cloud , donde analizo y valido las entradas de eventos de AWS Lambda.