¿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 4 se centró en las variables de entorno .
La parte 5 se centró en la validación de entrada .
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 características y las mejores prácticas de configuración.
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 todos los ejemplos en este repositorio de GitHub , incluido el código de implementación de CDK.
Vídeo TL;DR
Esta entrada del blog también está disponible como charla de conferencia en el vídeo a continuación:
Configuración de la función AWS Lambda
Una configuración de función de AWS Lambda suele ser un par de parámetros clave-valor a los que se accede durante el tiempo de ejecución y que afectan su flujo lógico.
Estos parámetros varían desde configuraciones generales (lista de regiones compatibles, URL de servicios, etc.) hasta definiciones de indicadores de características complejas (habilitar/deshabilitar características de código).
Durante mi trabajo en las funciones de AWS Lambda, me di cuenta de que necesitaba un método rápido y sencillo para cambiar el comportamiento de mi función de AWS Lambda sin cambiar su código. Cambiar la configuración de la función de AWS Lambda parecía el enfoque adecuado, ya que podía alterar el resultado o los efectos secundarios de la función de AWS Lambda.
Pero ¿cómo se hace eso rápidamente? ¿Cómo se almacenan los distintos tipos de configuraciones? ¿Cómo se puede acceder a ellas de forma eficiente y segura?
Este blog explicará las mejores prácticas para almacenar la configuración y los indicadores de características de AWS Lambda y proporcionará una solución Python completamente funcional.
Los indicadores de características inteligentes son indicadores de características que se evalúan en tiempo de ejecución y pueden cambiar sus valores según el contexto de la sesión.
La solución Python se basa en un SDK que desarrollé y doné al excelente repositorio de GitHub AWS Lambda Powertools.
Existen numerosas opciones para almacenar la configuración de la función AWS Lambda.
Supongamos que hemos asignado nuestra configuración a un formato de configuración JSON que deseamos utilizar en nuestro controlador AWS Lambda.
Estas son las opciones más comunes para almacenar dicha configuración:
Variables de entorno.
Agrupe el archivo de configuración JSON con la función.
Almacén de parámetros de AWS SSM/AWS Secrets Manager
Tabla de AWS DynamoDB.
Configuración de AWS AppConfig.
Podemos dividir estas opciones en dos categorías: configuraciones estáticas y dinámicas.
Al comprender la diferencia entre ellos y definir el caso de uso de cada opción, puede elegir la solución de almacenamiento que se ajuste a sus necesidades.
Sugerencia: Probablemente será una mezcla de configuraciones estáticas y dinámicas.
Configuraciones estáticas y dinámicas
Las configuraciones estáticas no cambian durante el tiempo de ejecución de la función; por lo tanto, son estáticas.
Las configuraciones estáticas incluyen variables de entorno o un archivo de configuración JSON incluido con el controlador. Estas configuraciones se implementan con la función y no se pueden modificar a menos que la función se vuelva a implementar.
Por otro lado, las configuraciones dinámicas se pueden modificar fuera del alcance de la función AWS Lambda y cambiar el comportamiento de la función durante el tiempo de ejecución.
La configuración dinámica se almacena en el almacén de parámetros de AWS SSM, una tabla de AWS DynamoDB o una configuración de AWS AppConfig (también puede haber otras opciones, pero estas son las más comunes).
Las configuraciones dinámicas son más complejas ya que requieren una canalización CI/CD dedicada, separada de la canalización CI/CD de la función AWS Lambda.
Esta separación es fundamental; la canalización diferente desacopla la función AWS Lambda de su configuración y permite actualizar la configuración sin tener que volver a implementar la canalización de la función AWS Lambda.
Construir y mantener más canales de CI/CD aumenta la complejidad, pero vale la pena.
Estas canalizaciones son rápidas por diseño, ya que no tienen otra lógica que cargar un archivo de configuración JSON a un servicio de AWS y requieren menos pruebas que un servicio completamente desarrollado basado en AWS Lambda.
En una crisis de producción, uno puede revertir rápidamente una configuración incorrecta o deshabilitar un indicador de función problemática en lugar de volver a implementar la función AWS Lambda con una configuración estática actualizada mientras espera que finalice un proceso de CI/CD de servicio *muy* largo.
TL;DR: Las configuraciones dinámicas requieren una canalización CI/CD rápida e independiente que permite un tiempo de reacción rápido a los problemas a expensas del mantenimiento adicional de la canalización CI/CD.
¿Qué opción de almacenamiento de configuración debería utilizar?
Cada tipo de configuración tiene su lugar.
Utilice la configuración estática para configuraciones que no cambian rápidamente y no requieren cambios rápidos en entornos de producción.
Tenga en cuenta que las variables de entorno tienen un límite de tamaño máximo debido a las restricciones del sistema operativo.
Si alcanza el límite, mueva las configuraciones a un archivo de configuración estático (incluido con el código AWS Lambda) o guárdelas como una configuración dinámica .
Puedes leer más sobre las variables de entorno y las mejores prácticas en mi blog aquí .
Una configuración que espera cambiar o desea tener la capacidad de cambiar rápidamente, debe guardarse como una configuración dinámica .
Además, las características, por su naturaleza, están destinadas a almacenarse como configuraciones dinámicas .
Dado que cubrimos la configuración estática como variables de entorno en un blog anterior ,
Centrémonos en la configuración dinámica y revisemos los requisitos para un SDK de utilidad de configuración dinámica y elijamos la mejor opción de almacenamiento para las configuraciones dinámicas.
Experiencia de usuario de la utilidad de configuración dinámica
Cuando diseñé la utilidad presentada en esta publicación del blog, quería admitir configuraciones dinámicas y marcas de funciones inteligentes.
¿Qué son las banderas de funciones "inteligentes"?
Las marcas de funciones inteligentes requieren una evaluación en tiempo de ejecución y pueden tener diferentes valores para distintas sesiones de funciones de AWS Lambda. Imagine que introduce una nueva función en producción, pero la habilita solo para clientes específicos. Una marca de función inteligente deberá evaluar el nombre del cliente y decidir si el valor final es "Verdadero/Falso" de acuerdo con un conjunto de reglas y condiciones predefinidas. Las marcas de funciones inteligentes se definen mediante reglas, condiciones y acciones que determinan el valor final.
Discutiremos esto en detalle más adelante.
Los requisitos
Utilice el archivo JSON para describir tanto los valores de configuración como los indicadores de funciones inteligentes.
Proporcione una API simple para obtener la configuración en cualquier lugar del código de función de AWS Lambda.
Proporciona una API simple para evaluar los valores de los indicadores de funciones inteligentes.
Durante el tiempo de ejecución, almacene la configuración en un caché local con un TTL configurable para reducir las llamadas API a AWS (para obtener la configuración JSON) y el costo total.
Compatibilidad integrada con modelos de Pydantic . Hemos utilizado Pydantic para serializar y validar la configuración JSON (validación de entrada y variables de entorno) a lo largo de esta serie de blogs, por lo que tiene sentido utilizarlo para analizar la configuración dinámica.
Ahora que entendemos los requisitos y el valor de tener una configuración dinámica en las funciones de AWS Lambda, analicemos el "dónde".
¿Dónde almacenamos la configuración JSON dinámica?
AWS AppConfig: el mejor servicio de almacenamiento de configuración dinámica
Recordemos nuestras opciones de almacenamiento. Al eliminar las opciones estáticas, nos quedamos con:
Almacén de parámetros de AWS SSM/Servicio de secretos de AWS
AWS DynamoDB
Configuración de aplicaciones de AWS
Creo que AWS AppConfig es el mejor servicio de almacenamiento de configuración dinámica para funciones de AWS Lambda. Permítanme explicarles por qué.
AWS AppConfig es un servicio autogestionado que almacena configuraciones de TEXTO/YAML/JSON simples para que sean utilizadas por múltiples clientes.
Lo usaremos en el contexto de la configuración dinámica y la alternancia de funciones, y almacenaremos un único archivo JSON que contiene indicadores de funciones y valores de configuración. AWS AppConfig podría ser el servicio aparente para almacenar la configuración de la función AWS Lambda debido a su nombre. Al investigar las capacidades específicas de configuración del servicio, se vuelve aún más claro que AWS AppConfig es una mejor opción que AWS DynamoDB y AWS SSM Parameter.
Repasemos sus ventajas:
Certificado de alto nivel de FedRAMP
Completamente sin servidor
Soporte listo para usar para validaciones de esquema que se ejecutan antes de una actualización de configuración.
La integración inmediata con las alarmas de AWS CloudWatch activa una reversión automática de la configuración si una actualización de configuración hace que las funciones de AWS Lambda fallen. Obtenga más información aquí .
Puede definir estrategias de implementación de configuración. Las estrategias de implementación definen cómo y cuándo cambiar una configuración. Lea más sobre esto aquí .
Proporciona una única API que brinda acceso a la configuración y a las características (más información a continuación).
AWS AppConfig ofrece integraciones con otros servicios como Atlassian Jira y AWS CodeDeploy. Haga clic aquí para obtener más información.
AWS DynamoDB y AWS SSM tienen diferentes ventajas y casos de uso, pero no están optimizados para el almacenamiento de configuración de AWS Lambda y los archivos JSON.
Debe utilizar AWS SSM Parameter Store para almacenar secretos (o AWS Secrets Manager para casos de uso más avanzados, rotación automática, integración con RDS, etc.), pero no para la configuración estándar. Carece de todas las funciones específicas de configuración descritas en las líneas 4 a 7.
Puede almacenar configuraciones dinámicas en DynamoDB . Sin embargo, carece de todas las funciones específicas de configuración descritas en las líneas 4 a 7.
¡Implementemos una configuración JSON!
En la plantilla de GitHub de la serie de blogs, la implementación de la configuración en AWS AppConfig se realiza a través de una construcción CDK que se encarga de la lógica por usted.
Debe crear una canalización separada para la configuración dinámica y utilizar la construcción CDK proporcionada.
Puedes leer más sobre ello aquí .
¿Cómo funciona AWS AppConfig?
AppConfig consta de jerarquías de configuración.
Su canalización de CI/CD creará una aplicación que se correlacione con el nombre de su servicio AWS Lambda. Una aplicación puede contener varias configuraciones para varios AWS Lambda o una configuración utilizada por todas las funciones AWS Lambda en el servicio; usted elige.
Luego, creará un entorno. Una aplicación tiene una lista de entornos ("dev", "stage", "production", etc.)
Cada entorno puede tener múltiples perfiles de configuración.
Cada perfil define la versión actual de una configuración, sus valores (en formato JSON/YAML/texto simple) y la estrategia de implementación a utilizar al implementarla.
Una vez implementada la configuración, se verá así:
Puede leer más sobre las estrategias de implementación aquí .
Obtención de indicadores de configuración y características
Dividiremos esta parte en dos: obtener la configuración dinámica y obtener los indicadores de características.
AWS Lambda Powertools al rescate
Tuve el privilegio de diseñar y donar una utilidad de configuración dinámica al repositorio de AWS Lambda Powertools. La utilidad se llama "feature flags", pero recupera tanto indicadores de características como configuraciones por igual.
La utilidad se integra con AWS AppConfig desde el primer momento.
Proporciona una manera sencilla de consumir la configuración JSON de AWS AppConfig y guardarla en un caché local dedicado. El caché reduce el costo total y mejora el rendimiento, ya que paga por cada llamada a la API de AWS AppConfig. El caché también tiene un TTL (tiempo de vida) configurable.
Tenga en cuenta que la utilidad requiere permisos IAM adicionales que permiten 'appconfig:GetLatestConfiguration' y 'appconfig:StartConfigurationSession'.
Vamos a obtener la configuración dinámica
Definamos nuestro archivo JSON de configuración dinámica del controlador de AWS Lambda en función del controlador de AWS Lambda presentado en los blogs anteriores: el "servicio de pedidos".
Un cliente puede comprar varias cantidades de un artículo como parte de un pedido. Cada cliente pertenece a un país de origen. El gestor se encargó de las solicitudes de pedido y se presentó en los blogs anteriores de la serie.
Agreguemos la configuración dinámica.
El servicio admite la entrega de pedidos únicamente a una lista cerrada de países. La lista se puede actualizar de forma dinámica y se pueden agregar o eliminar países.
Una posible configuración JSON se ve así:
Definamos el esquema Pydantic correspondiente:
Ahora, definamos nuestro SDK que utiliza la utilidad de indicadores de características y agreguemos el análisis de configuración JSON de Pydantic. Definiremos dos funciones.
La primera función, ' get_dynamic_configuration_store ', se utilizará para inicializar y obtener la instancia singleton de la utilidad de configuración.
La segunda función, ' parse_configuration ', se utiliza para obtener nuestra configuración JSON (sin indicadores de características) y analizarla con el modelo de esquema ' MyConfiguration ' que acabamos de definir.
Echemos un vistazo al código a continuación:
En la línea 4, importamos la utilidad de indicadores de características de AWS Lambda Powertools y cambiamos el nombre de la importación a un nombre más apropiado, ' DynamicConfiguration ', porque proporciona acceso tanto a los indicadores de características como a los valores de configuración.
En las líneas 24 a 34, inicializamos el almacén de configuración de AWS AppConfig, que sirve como clase captadora de configuración.
En la línea 26, usamos el analizador de variables de entorno que implementamos en la parte 4 de la serie y obtenemos las variables de entorno que requiere el almacén de configuración de AWS AppConfig.
Requiere varias variables de entorno nuevas:
Nombre de la aplicación de configuración de AWS AppConfig.
Nombre del entorno de AWS AppConfig.
Nombre de configuración de AWS AppConfig que se recuperará.
TTL de caché en minutos ("max_age" en la línea 31). Yo utilizaría el valor predeterminado de 5 minutos.
En la línea 32, definimos la clave del diccionario JSON para almacenar las definiciones de indicadores de funciones inteligentes.
Usaremos la clave ' features '. Los indicadores de características son opcionales y no tienen que ser parte del archivo JSON. Sin embargo, definiremos dos indicadores más adelante.
En la línea 34, inicializamos la utilidad de indicadores de características de AWS Lambda Powertools.
En la línea 49, obtenemos el archivo JSON de AWS AppConfig y usamos la configuración "sin procesar", es decir, el archivo JSON auténtico que se cargó.
En la línea 50, utilizamos Pydantic para analizar la configuración según el esquema y detectar cualquier error de validación del esquema. Devolvemos una instancia de dataclass una vez que la validación es exitosa para que podamos acceder a cualquier valor de configuración fácilmente.
Veamos este código en acción en un código de controlador de AWS Lambda. Este fragmento de código es una versión simplificada del controlador que se presentó gradualmente en publicaciones de blog anteriores.
En la línea 15, inicializamos las variables de entorno porque la función ' parse_configuration ' las usa en la línea 18.
En la línea 18, llamamos a " parse_configuration " y proporcionamos el nombre de la clase del esquema de configuración. Esta API se puede utilizar en cualquier parte del código de la función AWS Lambda.
Después de la primera llamada, el archivo JSON se guarda en la memoria caché durante 5 minutos y cualquier llamada a " parse_configuration " no generará facturación adicional de AWS AppConfig.
En la línea 23, imprimimos los valores de configuración y accedemos a ellos como una clase de datos regular.
En las líneas 19 a 21, manejamos cualquier error de configuración dinámica que pueda ocurrir, error de conexión de AWS AppConfig o error del archivo JSON que no cumple con nuestro modelo de validación de esquema.
Definamos y obtengamos indicadores de funciones inteligentes y regulares
Supongamos que nuestro controlador AWS Lambda admite dos indicadores de características:
Diez por ciento de descuento para el pedido actual: Verdadero/Falso .
Función premium para el cliente: Verdadero/Falso .
Un descuento del diez por ciento es una característica habitual . Según la política de la tienda, se puede activar o desactivar un descuento del diez por ciento. No cambia según la entrada de la sesión; es Verdadero o Falso para todas las entradas.
Por otro lado, las funciones premium están habilitadas solo para clientes específicos.
La función de bandera de funciones premium se basa en una regla. Es una función de bandera inteligente .
El valor de los indicadores de características es Falso para todos los clientes, excepto para los muy específicos.
Para utilizar las capacidades de los indicadores de características de AWS Lambda Powertools, necesitamos crear un archivo JSON que coincida con el lenguaje del SDK.
Puedes leer más sobre ello aquí .
Definición de indicadores de funciones regulares no inteligentes
Definir el indicador de descuento del diez por ciento es sencillo. Tiene una clave y un diccionario que contiene una clave de valor "predeterminado" con un valor booleano. Supongamos que el indicador de función está habilitado.
Vamos a añadirlo a la configuración actual que ya tenemos:
Definición JSON de indicadores de funciones inteligentes
Ahora, agreguemos la bandera de funciones inteligentes, funciones premium.
Queremos habilitarlo solo para los clientes de 'RanTheBuilder'.
La estructura JSON es simple.
Cada característica tiene un valor predeterminado bajo la clave predeterminada . Puede ser cualquier valor JSON válido (booleano, int, etc.).
Cada característica puede tener reglas opcionales que determinan el valor evaluado.
Cada regla consta de un valor predeterminado que se devolverá (en caso de coincidencia, w hen_match ) y una lista de condiciones. Solo una regla puede coincidir.
Cada condición consta de un nombre de acción (que se asigna a un operador en el código del motor de reglas) y un par clave-valor que sirve como argumento para el motor de reglas del SDK.
Nuestro archivo JSON de configuración ahora contiene indicadores de características (inteligentes y no inteligentes) y configuración general. Los indicadores de características se definen solo dentro de la clave raíz 'features'.
En este ejemplo, la regla coincide (lo que devuelve un valor Verdadero para el indicador) cuando el diccionario de contexto tiene una clave ' customer_name' con un valor de ' RanTheBuilder ' IGUAL A ' RanTheBuilder .'
Hay muchas acciones admitidas para condiciones como STARTSWITH , ENDSWITH , EQUALS , etc.
Puede leer más sobre las reglas, condiciones, lógica y acciones admitidas aquí .
Poniéndolo todo junto
Definiremos los nombres de los indicadores de características en una enumeración para que puedan obtenerse mediante valores de enumeración en lugar de cadenas "mágicas" codificadas.
El archivo Python del esquema de configuración actualizado ahora se verá así:
Redefinamos nuestro archivo JSON de configuración dinámica del controlador de AWS Lambda y agreguemos ambas marcas de características que evalúan las llamadas. Pondremos la definición de las marcas de ambas características bajo la clave " features " en el archivo JSON, que coincide con la variable de sobre en la tienda AppConfig que definimos en la línea 32 del archivo SDK de configuración dinámica.
En la línea 18, obtenemos la configuración de AWS AppConfig y la guardamos como un todo en la memoria caché.
En la línea 24, evaluamos el valor de configuración no inteligente. Dado que no es inteligente, no tiene contexto de sesión (el contexto del diccionario está vacío). El valor predeterminado es Falso si la definición del indicador de función se eliminó accidentalmente del archivo JSON en AWS AppConfig.
En la configuración actual, la línea 29 imprimirá el valor Verdadero .
En la línea 31, evaluamos el indicador de función inteligente. Pasamos el nombre del cliente como parte del diccionario de contexto. En este caso, la regla coincidirá y la función se evaluará como True .
Sin embargo, si customer_name fuera diferente, la regla no tendría coincidencias y la característica se evaluaría como False .
Próximamente
Con esto concluye la sexta parte de la serie.
Únase a mí en la siguiente y última parte, donde le mostraré cómo puede usar el repositorio de plantillas de GitHub y crear su servicio.
Comments