Implantar código TypeScript transcompilado no Lambda com imagens de contêiner - AWS Lambda

Implantar código TypeScript transcompilado no Lambda com imagens de contêiner

Você pode implantar seu código TypeScript em uma função do AWS Lambda como imagem de contêiner Node.js. A AWS fornece imagens base para Node.js para ajudar você a criar a imagem do contêiner. Essas imagens base são pré-carregadas com um runtime de linguagem e outros componentes necessários para executar a imagem no Lambda. A AWS fornece um Dockerfile para cada uma das imagens base para ajudar a criar sua imagem de contêiner.

Se você usa uma imagem base pertencente a uma comunidade ou empresa privada, é necessário adicionar um cliente de interface de runtime (RIC) Node.js à imagem base para torná-la compatível com o Lambda.

O Lambda oferece um emulador de interface de runtime para testes locais. As imagens base da AWS para o Node.js incluem o emulador de interface de runtime. Caso use uma imagem base alternativa, como uma imagem Alpine Linux ou Debian, você poderá criar o emulador na sua imagem ou instalá-lo na máquina local.

Usar uma imagem base Node.js para criar e empacotar código da função TypeScript

Para executar as etapas desta seção, você deve ter o seguinte:

Para criar uma imagem a partir de uma imagem base da AWS para o Lambda
  1. Em sua máquina local, crie um diretório de projeto para sua nova função.

  2. Crie um novo projeto Node.js com npm ou um gerenciador de pacotes de sua escolha.

    npm init
  3. Adicione pacotes @types/aws-lambda e esbuild como dependência de desenvolvimento. O pacote @types/aws-lambda contém as definições de tipo para o Lambda.

    npm install -D @types/aws-lambda esbuild
  4. Adicione um script de construção ao arquivo package.json.

    "scripts": { "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js" }
  5. Crie um novo arquivo chamado index.ts. Adicione o código de exemplo a seguir ao novo arquivo. Este é o código da função do Lambda. A função retorna uma mensagem hello world.

    nota

    A instrução import importa as definições de tipo de @types/aws-lambda. Ela não importa o pacote aws-lambda do NPM, que é uma ferramenta de terceiros não relacionada. Para obter mais informações, consulte aws-lambda no repositório DefinitelyTyped do GitHub.

    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. Crie um novo Dockerfile com a seguinte configuração:

    • Defina a propriedade FROM como o URI da imagem base.

    • Defina o argumento CMD para especificar o manipulador de funções do Lambda.

    O exemplo de Dockerfile a seguir usa uma compilação em várias etapas. A primeira etapa transcompila o código TypeScript em JavaScript. A segunda etapa produz uma imagem de contêiner contendo somente arquivos JavaScript e dependências de produção.

    Observe que o Dockerfile de exemplo não inclui uma instrução USER. Quando você implanta uma imagem de contêiner no Lambda, o Lambda define automaticamente um usuário padrão do Linux com permissões de privilégio mínimo. Isso é diferente do comportamento padrão do Docker, que adota o usuário root como padrão quando nenhuma instrução USER é fornecida.

    exemplo 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. Crie a imagem do Docker com o comando docker build. O exemplo a seguir nomeia a imagem como docker-image e atribui a ela a tag test.

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

    O comando especifica a opção --platform linux/amd64 para garantir que seu contêiner seja compatível com o ambiente de execução do Lambda, independentemente da arquitetura da sua máquina de compilação. Se você pretende criar uma função do Lambda usando a arquitetura do conjunto de instruções ARM64, certifique-se de alterar o comando para usar a opção --platform linux/arm64 em vez disso.

  1. Inicie a imagem do Docker com o comando docker run. Neste exemplo, docker-image é o nome da imagem e test é a tag.

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

    Esse comando executa a imagem como um contêiner e cria um endpoint local em localhost:9000/2015-03-31/functions/function/invocations.

    nota

    Se você criou a imagem do Docker para a arquitetura do conjunto de instruções ARM64, certifique-se de usar a opção --platform linux/arm64, em vez de --platform linux/amd64.

  2. Em uma nova janela de terminal, publique um evento no endpoint local.

    Linux/macOS

    No Linux e no MacOS, execute o seguinte comando curl:

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

    Esse comando invoca a função com um evento vazio e retorna uma resposta. Caso esteja usando seu próprio código de função em vez do código de função de exemplo, você talvez queira invocar a função com uma carga útil JSON. Exemplo:

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

    No PowerShell, execute o seguinte comando Invoke-WebRequest:

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

    Esse comando invoca a função com um evento vazio e retorna uma resposta. Caso esteja usando seu próprio código de função em vez do código de função de exemplo, você talvez queira invocar a função com uma carga útil JSON. Exemplo:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
  3. Obtenha o ID do contêiner.

    docker ps
  4. Use o comando docker kill para parar o contêiner. Nesse comando, substitua 3766c4ab331c pelo ID do contêiner da etapa anterior.

    docker kill 3766c4ab331c
Para enviar a imagem ao Amazon ECR e criar a função do Lambda
  1. Execute o comando get-login-password para autenticar a CLI do Docker no seu registro do Amazon ECR.

    • Defina o valor --region para a Região da AWS onde você deseja criar o repositório do Amazon ECR.

    • Substituir 111122223333 por seu ID da Conta da 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. Crie um repositório no Amazon ECR usando o 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

    O repositório do Amazon ECR deve estar na mesma Região da AWS que a função do Lambda.

    Se tiver êxito, você verá uma resposta como esta:

    { "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 o repositoryUri da saída na etapa anterior.

  4. Execute o comando docker tag para aplicar uma tag na sua imagem local em seu repositório do Amazon ECR como a versão mais recente. Neste comando:

    • docker-image:test é o nome e a tag da sua imagem do Docker. Esse é o nome e a tag da imagem que você especificou no comando docker build.

    • Substitua <ECRrepositoryUri> pelo repositoryUri que você copiou. Certifique-se de incluir :latest no final do URI.

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

    Exemplo:

    docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  5. Execute o comando docker push para implantar a imagem local no repositório do Amazon ECR. Certifique-se de incluir :latest no final do URI do repositório.

    docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  6. Crie um perfil de execução para a função, caso ainda não tenha um. Você precisará do nome do recurso da Amazon (ARN) do perfil na próxima etapa.

  7. Criar a função do Lambda. Em ImageUri, especifique o URI do repositório anterior. Certifique-se de incluir :latest no final do 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

    É possível criar uma função usando uma imagem em uma conta da AWS diferente desde que a imagem esteja na mesma região da função do Lambda. Para ter mais informações, consulte Permissões entre contas do Amazon ECR.

  8. Invoque a função.

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

    Você obterá uma resposta parecida com esta:

    { "ExecutedVersion": "$LATEST", "StatusCode": 200 }
  9. Para ver a saída da função, verifique o arquivo response.json.

Para atualizar o código da função, você deve criar a imagem novamente, fazer upload da nova imagem no repositório do Amazon ECR e, em seguida, usar o comando update-function-code para implantar a imagem na função do Lambda.

O Lambda resolve a tag de imagem em um resumo de imagem específico. Isso significa que, se você apontar a tag de imagem que foi usada para implantar a função em uma nova imagem no Amazon ECR, o Lambda não atualizará automaticamente a função para usar a nova imagem.

Para implantar a nova imagem na mesma função do Lambda, você deverá usar o comando update-function-code, mesmo que a tag da imagem no Amazon ECR permaneça a mesma. No exemplo a seguir, a opção --publish cria uma nova versão da função usando a imagem de contêiner atualizada.

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