En esta ocasión se realizará un ejemplo sencillo para comprender los fundamentos de un despliegue Canario usando servicios de AWS, este tipo de despliegue está siendo muy usado en la industria por el crecimiento de serverless y contenedores.
¿Qué es el despliegue de tipo Canary?
El despliegue Canary consiste en desplegar nuevas versiones de software de manera incremental, es decir, durante un tiempo una porción de usuarios acceden a la nueva versión desplegada y otro grupo de usuarios siguen consumiendo a la versión anterior, los usuarios sirven como carnada para consumir los servicios e indicar que todo está marchando bien y esto permite seguir incrementando de forma gradual a la última versión desplegada. Si durante el uso existe un error, se realiza un rollback dejando en la versión anterior y sin afectar a los demás usuarios.
Ejemplo práctico
Para el ejemplo práctico se crea dos funciones lambdas y se usa el servicio de Api Gateway para poder realizar pruebas mediante Postman y evidenciar el despliegue incremental Canary.
Requisitos previos
- Cuenta de AWS y tener configurado AWS CLI y SAM CLI
- Conocimientos esenciales cloudformation, lambdas y api gateway
- Manejo de Postman y Jmeter
- NodeJs con typescript
Inicio de proyecto
Se inicia el proyecto a partir de una plantilla básica proporcionada en SAM CLI, ejecutando el siguiente comando:
sam init Seguir las instrucciones
Se genera un proyecto básico de un hello world, se borra la entrada principal app.ts y todos los test. Se crea una estructura de carpetas de la siguiente manera:
Nota: la carpeta hello-world ahora es app.
En el directorio donde está definido el package.json instalar las dependencias:
npm install A continuación se muestra el código de ejemplo de cada función, no se está conectando a ninguna base de datos para este ejemplo, pero ya depende de lo que necesitemos, el objetivo es demostrar el despliegue:
createCustomer.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; import { Customer } from '../models/Customer'; export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { const customer: Customer = JSON.parse(event.body ?? '{}'); //TODO: generate id for customer customer.id = '1234'; return { statusCode: 200, body: JSON.stringify({ message: 'Customer created', customer }), }; }; getCustomerById.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; import { Customer } from '../models/Customer'; export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { const id = event.pathParameters?.id; const customer: Customer = { id: id ?? '', name: 'John Doe', email: 'doe@qw.com', age: 30 }; return { statusCode: 200, body: JSON.stringify({ message: 'Customer found', customer }), }; }; Customer.ts
En models solo se tiene definido un tipo de dato Customer:
export type Customer = { id: string; name: string; email: string; age: number; }; Archivo template.yaml
Listo ahora que está todo el código fuente, es necesario configurar la infraestructura a desplegar en AWS.
Se realiza las configuraciones globales de las funciones y de la api:
Nota: La propiedad DeploymentPreference configura a la función lambda para realizar el despliegue incremental. Para conocer todos los tipos que existen se puede revisar el siguiente enlace: Deploy Canary.
En los recursos se definen las Lambdas y el ApiGateway a utilizar:
Nota: Se configura un alias de producción para simular sobre ese escenario.
Se muestra toda la configuración en template.yaml
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > init-app Sample SAM Template for customers Globals: Function: CodeUri: app Timeout: 10 Tracing: Active Runtime: nodejs16.x Architectures: - x86_64 DeploymentPreference: Enabled: true Type: 'Linear10PercentEvery1Minute' Api: TracingEnabled: True Resources: ApiGateway: Type: AWS::Serverless::Api Properties: StageName: v1 Variables: version_alias: 'production' EndpointConfiguration: Type: REGIONAL CreateCustomerFunction: Type: AWS::Serverless::Function Properties: Handler: src/functions/createCustomer.handler FunctionName: !Sub ${AWS::StackName}-create-customer AutoPublishAlias: production Events: CreateCustomer: Type: Api Properties: Path: /customers Method: post RestApiId: !Ref ApiGateway Metadata: BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" EntryPoints: - src/functions/createCustomer.ts GetCustomerByIdFunction: Type: AWS::Serverless::Function Properties: Handler: src/functions/getCustomerById.handler FunctionName: !Sub ${AWS::StackName}-get-customer-by-id AutoPublishAlias: production Events: CreateCustomer: Type: Api Properties: Path: /customers/{id} Method: get RestApiId: !Ref ApiGateway Metadata: BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" EntryPoints: - src/functions/getCustomerById.ts Nota: Algunos recursos como permisos y roles se crea detrás de escena gracias a la ayuda de SAM.
Despliegue de stack
En el directorio principal en donde está la plantilla template.yaml ejecutar los siguientes comandos para empaquetar y desplegar:
sam build sam deploy --guided --capabilities CAPABILITY_NAMED_IAM Se revisa en la consola de cloudformation para ver los recursos creados en el stack:
Si se revisa una de las funciones podemos ver el alias y una tercera versión creada, esto debido a que anteriormente se hizo unos despliegues de prueba, si es primer despliegue desde cero estará una versión 1:
Para el ejemplo se toma la función que simula crear un Cliente para realizar las pruebas, revisar el recurso de ApiGateway para obtener la URL a consultar:
Se comprueba el funcionamiento en Postman:
Actualizar código para evidenciar el despliegue Canary
Para poder ver la ejecución de Canary hay que editar el código y desplegar, se podrá ver que de a poco va incrementando el peso de la versión.
En este caso se edita la función que simula crear un Cliente.
Se instala las siguientes dependencias y se edita el código como se muestra:
npm i short-uuid Una vez realizado los cambios se debe ejecutar los comandos:
sam build sam deploy --capabilities CAPABILITY_NAMED_IAM Prueba de Canary
El despliegue tipo Canary empieza, por cada minuto se incrementa de forma lineal un 10% para pasar a la versión 4.
Para poder evidenciar que la carga se está distribuyendo entre las dos versiones se realiza una prueba de carga con Jmeter.
Nota: Si no conoces sobre Jmeter para pruebas de carga puedes revisar el siguiente recurso.
En los logs de la función de Cloudwatch se puede observar como ha realizado llamadas entre las dos versiones 3 y 4.
Espero hayas aprendido las bases sobre canary con este sencillo ejemplo en funciones lambdas, gracias.















Top comments (0)