Implementar código de TypeScript transpilado en Lambda con imágenes de contenedor - AWS Lambda

Implementar código de TypeScript transpilado en Lambda con imágenes de contenedor

Puede implementar el código de TypeScript en una función de AWS Lambda en forma de imagen de contenedor de Node.js. AWS proporciona imágenes base para Node.js para ayudarle a crear la imagen de contenedor. Estas imágenes base están precargadas con un tiempo de ejecución de lenguaje y otros componentes necesarios para ejecutar la imagen en Lambda. AWS proporciona un archivo Dockerfile para cada una de las imágenes base para ayudar a crear su imagen contenedor.

Si utiliza una imagen base de la comunidad o de una empresa privada, debe agregar el cliente de interfaz de tiempo de ejecución (RIC) de Node.js a la imagen base para que sea compatible con Lambda.

Lambda proporciona un emulador de interfaz de tiempo de ejecución para realizar pruebas de manera local. Las imágenes base AWS para Node.js incluyen el emulador de interfaz de tiempo de ejecución. Si utiliza una imagen base alternativa, como una imagen de Alpine Linux o Debian, puede compilar el emulador en su imagen o instalarlo en su equipo local.

Uso de una imagen base de Node.js para compilar y empaquetar código de función de TypeScript

Para completar los pasos de esta sección, debe disponer de lo siguiente:

Para crear una imagen a partir de una imagen base AWS para Lambda
  1. En su máquina local, cree un directorio de proyecto para su nueva función.

  2. Cree un nuevo proyecto de Node.js con npm o un administrador de paquetes de su elección.

    npm init
  3. Agregue los paquetes @types/aws-lambda y esbuild en forma de dependencias de desarrollo. El paquete @types/aws-lambda contiene las definiciones de tipos de Lambda.

    npm install -D @types/aws-lambda esbuild
  4. Agregue un script de compilación al archivo package.json.

    "scripts": { "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js" }
  5. Cree un nuevo archivo denominado index.ts. Agregue el siguiente código de muestra al nuevo archivo. Se trata del código de la función de Lambda. La función devuelve el mensaje hello world.

    nota

    La instrucción import importa las definiciones de tipo de @types/aws-lambda. No importa el paquete NPM de aws-lambda, que es una herramienta de terceros no relacionada. Para obtener más información, consulte aws-lambda en el repositorio de GitHub DefinitelyTyped.

    import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda'; export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => { console.log(`Event: ${JSON.stringify(event, null, 2)}`); console.log(`Context: ${JSON.stringify(context, null, 2)}`); return { statusCode: 200, body: JSON.stringify({ message: 'hello world', }), }; };
  6. Cree un nuevo archivo Dockerfile con la siguiente configuración:

    • Establezca la propiedad FROM en el URI de la imagen base.

    • Establezca el argumento CMD para especificar el controlador de función de Lambda.

    El siguiente Dockerfile de ejemplo utiliza una compilación de varias etapas. El primer paso transpila el código de TypeScript a JavaScript. El segundo paso produce una imagen de contenedor que contiene solo archivos de JavaScript y dependencias de producción.

    Tenga en cuenta que el Dockerfile de ejemplo no incluye una instrucción USER. Al implementar una imagen de contenedor en Lambda, Lambda define automáticamente un usuario predeterminado de Linux con permisos de privilegio mínimo. Esto es diferente del comportamiento estándar de Docker, que utiliza de forma predeterminada el usuario root cuando no se proporciona ninguna instrucción USER.

    ejemplo Dockerfile
    FROM public.ecr.aws/lambda/nodejs:20 as builder WORKDIR /usr/app COPY package.json index.ts ./ RUN npm install RUN npm run build FROM public.ecr.aws/lambda/nodejs:20 WORKDIR ${LAMBDA_TASK_ROOT} COPY --from=builder /usr/app/dist/* ./ CMD ["index.handler"]
  7. Cree la imagen de Docker con el comando docker build. En el siguiente ejemplo se asigna un nombre a la imagen docker-image y se le asigna la etiqueta test.

    docker build --platform linux/amd64 -t docker-image:test .
    nota

    El comando especifica la opción --platform linux/amd64 para garantizar que el contenedor sea compatible con el entorno de ejecución de Lambda, independientemente de la arquitectura de la máquina de compilación. Si tiene intención de crear una función de Lambda con la arquitectura del conjunto de instrucciones ARM64, asegúrese de cambiar el comando para utilizar la opción --platform linux/arm64 en su lugar.

  1. Inicie la imagen de Docker con el comando docker run. En este ejemplo, docker-image es el nombre de la imagen y test es la etiqueta.

    docker run --platform linux/amd64 -p 9000:8080 docker-image:test

    Este comando ejecuta la imagen como un contenedor y crea un punto de conexión local en localhost:9000/2015-03-31/functions/function/invocations.

    nota

    Si creó la imagen de Docker para la arquitectura del conjunto de instrucciones ARM64, asegúrese de utilizar la opción --platform linux/arm64 en lugar de --platform linux/amd64.

  2. Desde una nueva ventana de terminal, publique un evento en el punto de conexión local.

    Linux/macOS

    En Linux y macOS, ejecute el siguiente comando curl:

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

    Este comando invoca la función con un evento vacío y devuelve una respuesta. Si utiliza su propio código de función en lugar del código de función de ejemplo, quizás quiera invocar la función con una carga JSON. Ejemplo:

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
    PowerShell

    En PowerShell, ejecute el siguiente comando Invoke-WebRequest:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"

    Este comando invoca la función con un evento vacío y devuelve una respuesta. Si utiliza su propio código de función en lugar del código de función de ejemplo, quizás quiera invocar la función con una carga JSON. Ejemplo:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
  3. Obtenga el ID del contenedor.

    docker ps
  4. Use el comando docker kill para detener el contenedor. En este comando, reemplace 3766c4ab331c por el ID del contenedor del paso anterior.

    docker kill 3766c4ab331c
Para cargar la imagen en Amazon ECR y crear la función de Lambda
  1. Para autenticar la CLI de Docker en su registro de Amazon ECR, ejecute el comando get-login-password.

    • Establezca el valor de --region en la Región de AWS en la que desee crear el repositorio de Amazon ECR.

    • Reemplace 111122223333 por el ID de su Cuenta de AWS.

    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
  2. Cree un repositorio en Amazon ECR con el comando create-repository.

    aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
    nota

    El repositorio de Amazon ECR debe estar en la misma Región de AWS que la función de Lambda.

    Si se realiza de la forma correcta, verá una respuesta como la siguiente:

    { "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world", "registryId": "111122223333", "repositoryName": "hello-world", "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world", "createdAt": "2023-03-09T10:39:01+00:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
  3. Copie el valor de repositoryUri de la salida del paso anterior.

  4. Ejecute el comando docker tag para etiquetar la imagen local en su repositorio de Amazon ECR como la versión más reciente. En este comando:

    • docker-image:test es el nombre y la etiqueta de su imagen de Docker. Son el nombre y la etiqueta de la imagen que especificó en el comando docker build.

    • Reemplace <ECRrepositoryUri> por el repositoryUri que ha copiado. Asegúrese de incluir :latest al final del URI.

    docker tag docker-image:test <ECRrepositoryUri>:latest

    Ejemplo:

    docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  5. Ejecute el comando docker push para implementar la imagen local en el repositorio de Amazon ECR. Asegúrese de incluir :latest al final del URI del repositorio.

    docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  6. Cree un rol de ejecución para la función si aún no tiene uno. Necesitará el nombre de recurso de Amazon (ARN) del rol en el paso siguiente.

  7. Cree la función de Lambda. En ImageUri, especifique el URI del repositorio anterior. Asegúrese de incluir :latest al final del URI.

    aws lambda create-function \ --function-name hello-world \ --package-type Image \ --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \ --role arn:aws:iam::111122223333:role/lambda-ex
    nota

    Puede crear una función con una imagen de una cuenta AWS diferente, siempre que la imagen esté en la misma región que la función de Lambda. Para obtener más información, consulte Permisos entre cuentas de Amazon ECR.

  8. Invoque la función.

    aws lambda invoke --function-name hello-world response.json

    Debería ver una respuesta como la siguiente:

    { "ExecutedVersion": "$LATEST", "StatusCode": 200 }
  9. Para ver la salida de la función, compruebe el archivo response.json.

Para actualizar el código de la función, debe volver a compilar la imagen, cargar la nueva imagen en el repositorio de Amazon ECR y, a continuación, utilizar el comando update-function-code para implementar la imagen en la función de Lambda.

Lambda resuelve la etiqueta de la imagen en un resumen de imagen específico. Esto significa que si apunta la etiqueta de imagen que se utilizó para implementar la función a una nueva imagen en Amazon ECR, Lambda no actualiza automáticamente la función para usar la nueva imagen.

Para implementar la nueva imagen en la misma función de Lambda, debe usar el comando update-function-code, incluso si la etiqueta de la imagen en Amazon ECR sigue siendo la misma. En el siguiente ejemplo, la opción --publish crea una nueva versión de la función con la imagen del contenedor actualizada.

aws lambda update-function-code \ --function-name hello-world \ --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \ --publish