

# Implantar código TypeScript transcompilado no Lambda com imagens de contêiner
<a name="typescript-image"></a>

Você pode implantar seu código TypeScript em uma função do AWS Lambda como [imagem de contêiner](images-create.md) Node.js. A AWS fornece [imagens base](nodejs-image.md#nodejs-image-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](nodejs-image.md#nodejs-image-clients) à 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](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#build-rie-into-your-base-image) ou [instalá-lo na máquina local](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#test-an-image-without-adding-rie-to-the-image).

## Usar uma imagem base Node.js para criar e empacotar código da função TypeScript
<a name="base-image-typescript"></a>

### Pré-requisitos
<a name="typescript-image-prerequisites"></a>

Para executar as etapas desta seção, você deve ter o seguinte:
+ [AWS CLI versão 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker) (versão mínima 25.0.0)
+ O plug-in [buildx](https://github.com/docker/buildx/blob/master/README.md) do Docker.
+ Node.js 22.x

### Criação de uma imagem a partir de uma imagem base
<a name="typescript-image-create"></a>

**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.

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

   ```
   npm init
   ```

1. Adicione pacotes [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) e [esbuild](https://esbuild.github.io/) 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
   ```

1. Adicione um [script de construção](https://esbuild.github.io/getting-started/#build-scripts) ao arquivo `package.json`.

   ```
     "scripts": {
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js"
   }
   ```

1. 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](https://www.npmjs.com/package/@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](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/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',
           }),
       };
   };
   ```

1. 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](https://docs.docker.com/reference/dockerfile/#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.  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/nodejs:22 as builder
   WORKDIR /usr/app
   COPY package.json index.ts  ./
   RUN npm install
   RUN npm run build
       
   FROM public.ecr.aws/lambda/nodejs:22
   WORKDIR ${LAMBDA_TASK_ROOT}
   COPY --from=builder /usr/app/dist/* ./
   CMD ["index.handler"]
   ```

1. Crie a imagem do Docker com o comando [docker build](https://docs.docker.com/engine/reference/commandline/build/). O exemplo a seguir nomeia a imagem como `docker-image` e atribui a ela a [tag](https://docs.docker.com/engine/reference/commandline/build/#tag) `test`. Para tornar sua imagem compatível com o Lambda, é necessário usar a opção `--provenance=false`.

   ```
   docker buildx build --platform linux/amd64 --provenance=false -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.

### (Opcional) Teste a imagem localmente
<a name="typescript-image-test"></a>

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`.

1. 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"
   ```

------

1. Obtenha o ID do contêiner.

   ```
   docker ps
   ```

1. Use o comando [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) para parar o contêiner. Nesse comando, substitua `3766c4ab331c` pelo ID do contêiner da etapa anterior.

   ```
   docker kill 3766c4ab331c
   ```

### Implantação da imagem
<a name="typescript-image-deploy"></a>

**Para enviar a imagem ao Amazon ECR e criar a função do Lambda**

1. Execute o comando [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 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
   ```

1. Crie um repositório no Amazon ECR usando o comando [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html).

   ```
   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"
           }
       }
   }
   ```

1. Copie o `repositoryUri` da saída na etapa anterior.

1. Execute o comando [docker tag](https://docs.docker.com/engine/reference/commandline/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](https://docs.docker.com/engine/reference/commandline/build/#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
   ```

1. Execute o comando [docker push](https://docs.docker.com/engine/reference/commandline/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
   ```

1. [Crie um perfil de execução](lambda-intro-execution-role.md#permissions-executionrole-api) 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.

1. 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 obter mais informações, consulte [Permissões entre contas do Amazon ECR](images-create.md#configuration-images-xaccount-permissions).

1. Invoque a função.

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

   Você obterá uma resposta parecida com esta:

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 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](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 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](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html), 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
```