O blog da AWS

Migração de funções do AWS Lambda no runtime Go1.x para o runtime personalizado no Amazon Linux 2

Por Micah Walter, arquiteto sênior de soluções, Yanko Bolanos, arquiteto sênior de soluções, Ramesh Mathikumar, consultor sênior de DevOps

 

Atualmente, os clientes que usam Go com Lambda podem usar o runtime go1.x ou usar o runtime provided.al2. No futuro, planejamos descontinuar o runtime go1.x junto com o fim da vida útil do Amazon Linux 1, atualmente programado para 31 de dezembro de 2023.

Os clientes que usam o runtime go1.x devem migrar suas funções para o runtime provided.al2 para continuar se beneficiando das atualizações de runtime e dos patches de segurança mais recentes. Os clientes que implantam funções Go usando imagens de contêiner que atualmente usam a imagem de contêiner base go1.x devem migrar da mesma forma para a imagem base provided.al2.

Usar o runtime provided.al2 oferece vários benefícios em relação ao runtime go1.x. Primeiro, ele suporta a execução de funções do Lambda nos processadores AWS Graviton2, oferecendo uma relação preço-desempenho até 34% melhor em comparação com funções executadas em processadores x86_64. Em segundo lugar, ele oferece uma implementação simplificada com um pacote de implantação menor e um caminho de invocação de função mais rápido. Por fim, essa alteração alinha o Go com outras linguagens que também compilam em código nativo, como Rust ou C++, que são executados no runtime provided.al2.

Essa migração não exige nenhuma alteração no código. As únicas alterações estão relacionadas à forma como você cria seu pacote de implantação e configura sua função. Este blog descreve as etapas necessárias para atualizar seus scripts de construção e ferramentas para usar o runtime provided.al2 para suas funções Go.

Há uma diferença no faturamento do Lambda entre o runtime go1.x e o runtime provided.al2. Com o runtime go1.x, o Lambda não cobra pelo tempo gasto durante a inicialização da função (inicialização a frio), enquanto com o runtime provided.al2, o Lambda inclui o tempo de inicialização da função na duração da função. Como as funções Go normalmente são inicializadas muito rapidamente e como o Lambda reduz o número de inicializações ao reutilizar ambientes de execução de funções para várias invocações de funções, na prática, a diferença na fatura do Lambda deve ser muito pequena.

Compilando para o runtime provided.al2

Para executar um aplicativo Go compilado no Lambda, você deve compilar seu código para Linux. Enquanto o runtime go1.x permite que você use qualquer nome executável, o runtime provided.al2 exige que você use bootstrap como nome do executável. No macOS e no Linux, aqui está a forma mais simples do comando build:

GOARCH=amd64 GOOS=linux go build -o bootstrap main.go

Esse comando de compilação cria um arquivo binário Go chamado bootstrap compatível com o conjunto de instruções x86_64 para Lambda. Para compilar para processadores AWS Graviton, defina GOARCH=arm64 no comando anterior.

A etapa final é compactar esse binário em um pacote de implantação de arquivo ZIP, pronto para ser implantado no Lambda:

zip myFunction.zip bootstrapPara usuários que compilam no Windows, o Go oferece suporte à compilação para Linux sem usar uma máquina virtual Linux ou um contêiner de compilação. No entanto, o Lambda usa permissões de arquivo POSIX, que devem ser definidas corretamente. O Lambda fornece uma ferramenta auxiliar que cria um pacote de implantação válido para o Lambda. Consulte a documentação do Lambda para obter detalhes. Os usuários dessa ferramenta devem atualizar para a versão mais recente para garantir que seus scripts de construção estejam atualizados.

Removendo a dependência de RPC

O runtime go1.x usa dois processos no ambiente de execução do Lambda para rotear solicitações para sua função de manipulador (handler). O primeiro processo, incluído no runtime, recupera solicitações de invocação de função da API de runtime do Lambda e usa RPC para passar a invocação para o segundo processo. Esse segundo processo executa o arquivo que você implanta e compreende o pacote aws-lambda-go e seu código de função. O pacote aws-lambda-go recebe a solicitação RPC e executa sua função.

O diagrama de arquitetura de runtime a seguir para o runtime go1.x mostra o processo de runtime chamando a API para recuperar uma invocação de função e usando RPC e chamar um processo separado contendo o código da função.

Execution environment

As funções Go implantadas no runtime provided.al2 usam uma arquitetura de processo único mais simples. Ao criar o executável Go, você inclui o mesmo pacote aws-lambda-go de antes. No entanto, nesse caso, o pacote aws-lambda-go atua como o cliente de runtime, recuperando solicitações de invocação diretamente da API de runtime.

O diagrama de arquitetura de runtime a seguir mostra uma função Go em execução no runtime provided.al2. Um único processo recupera a invocação da função da API de runtime e executa o código da função.

Go running on provided.al2

A remoção do processo adicional e do salto de RPC simplifica o caminho de execução da função, resultando em invocações mais rápidas. Você também pode remover o componente RPC do pacote aws-lambda-go, oferecendo um tamanho binário menor e um carregamento de código mais rápido durante a inicialização a frio (cold start). Para remover a dependência de RPC, adicione a tag lambda.norpc ao seu comando de compilação:

GOARCH=amd64 GOOS=linux go build -tags lambda.norpc -o bootstrap main.go

Criação de uma nova função Lambda

Quando seu pacote de implantação estiver pronto, você poderá criar uma nova função Lambda usando o runtime provided.al2 usando o console Lambda:

Creating in the Lambda console

Migração de funções existentes

Se você tiver funções do Lambda existentes que usam o runtime go1.x, você pode migrar essas funções seguindo estas etapas:

  1. Recompile seu binário usando os comandos anteriores, certificando-se de nomear seu binário como bootstrap.
  2. Se você estiver usando a mesma arquitetura de conjunto de instruções, abra as configurações de runtime e alterne o runtime para “Provide seu próprio bootstrap no Amazon Linux 2”.
  3. Faça o upload da nova versão do seu binário como um arquivo zip.

Edit runtime settings

Observação: o valor do manipulador (handler) não é usado pelo runtime provided.al2 nem pela biblioteca aws-lambda-go e pode ser definido como qualquer valor. Recomendamos definir o valor como bootstrap para ajudar na migração entre go1.x e provided.al2.

Para mudar a arquitetura do conjunto de instruções para Graviton (arm64), salve suas alterações e, em seguida, reabra as configurações de runtimes para fazer a alteração da arquitetura.

Migração de imagens de contêiner Go1.x Lambda

O Lambda permite que você execute seu código Go como uma imagem de contêiner. Os clientes que estão usando a imagem base go1.x para contêineres Lambda devem migrar para a imagem provided.al2. A documentação do Lambda inclui instruções sobre como criar e implantar funções Go usando a imagem base provided.al2.

O Dockerfile a seguir usa uma compilação de dois estágios para evitar camadas e arquivos desnecessários na imagem final. A primeira etapa do processo cria o aplicativo. Esse estágio instala o Go, baixa as dependências do código e compila o binário. O segundo estágio copia o executável para um novo contêiner sem as dependências do processo de construção.

  1. Crie um Dockerfile no diretório do seu projeto:
    FROM public.ecr.aws/lambda/provided:al2 as build
    # install compiler
    RUN yum install -y golang
    RUN go env -w GOPROXY=direct
    # cache dependencies
    ADD go.mod go.sum ./
    RUN go mod download
    # build
    ADD . .
    RUN go build -tags lambda.norpc -o /main
    # copy artifacts to a clean image
    FROM public.ecr.aws/lambda/provided:al2
    COPY --from=build /main /main
    ENTRYPOINT [ "/main" ]           
    
    Docker
  2. Crie sua imagem do Docker com o comando Docker build:
    docker build -t hello-world .
    Bash
  3. Autentique a CLI do Docker em seu registro do Amazon ECR:
    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com 
    Bash
  4. Marque e envie sua imagem para o registro do Amazon ECR:
    docker tag hello-world:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
    
    docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
    Bash

Agora você pode criar ou atualizar sua função Go Lambda para usar a nova imagem do contêiner.

Mudanças nas ferramentas

Para migrar suas funções do runtime go1.x para o runtime provided.al2, você deve fazer alterações na configuração dos scripts de compilação ou nas configurações de CI/CD. Aqui estão alguns exemplos comuns.

Crie arquivos e crie scripts

Se você usa Makefiles ou scripts de construção personalizados para criar funções Go, você deve modificar para garantir que o arquivo executável tenha o nome de bootstrap ao ser implantado no runtime provided.al2.

Aqui está um exemplo de Makefile que compila o arquivo main.go em um executável chamado bootstrap na pasta bin. Ele também cria um arquivo zip, que você pode implantar no Lambda usando o console ou por meio da AWS CLI.

GOARCH=arm64 GOOS=linux go build -tags lambda.norpc -o ./bin/bootstrap
(cd bin && zip -FS bootstrap.zip bootstrap)
Bash

CloudFormation

Se você implantar suas funções do Lambda usando modelos do AWS CloudFormation, altere as configurações do Handler e do Runtime em Propriedades:

Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      Handler: bootstrap
      Runtime: provided.al2
      ... # Other required properties
YAML

AWS Serverless Application Model

Se você usa o AWS Serverless Application Model (AWS SAM) para criar e implantar suas funções Go, faça as mesmas alterações nas configurações do Handler e do Runtime do CloudFormation. Você também deve adicionar o BuildMethod:

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Metadata:
      BuildMethod: go1.x 
    Properties:
      CodeUri: hello-world/ # folder where your main program resides
      Handler: bootstrap
      Runtime: provided.al2
      Architectures:
        - x86_64
YAML

Cloud Development Kit (CDK)

Se você usa o AWS Cloud Development Kit (AWS CDK), você pode compilar seu executável Go e colocá-lo em uma pasta no seu projeto. Em seguida, especifique a localização usando AWSLambda.code_fromAsset, e o AWS CDK empacota o binário em um arquivo zip e o carrega.

// Go CDK
awslambda.NewFunction(stack, jsii.String("HelloHandler"), &awslambda.FunctionProps{
    Code:         awslambda.Code_FromAsset(jsii.String("lambda"), nil), //folder where bootstrap executable is located
    Runtime:      awslambda.Runtime_PROVIDED_AL2(),
    Handler:      jsii.String("bootstrap"), // Handler named bootstrap
    Architecture: awslambda.Architecture_ARM_64(),
})
Go

Além disso, o AWS CDK pode executar comandos de construção como parte do seu processo de criação do AWS CDK usando a funcionalidade nativa de empacotamento do AWS CDK. Com o parâmetro de empacotamento, o AWS CDK pode executar etapas antes de preparar os arquivos na montagem da nuvem. Em vez de colocar o arquivo binário, coloque o código Go em uma pasta e use a opção Bundling para compilar o código em um contêiner Docker.

Este exemplo usa a imagem do Docker golang:1.20.1. Após a compilação, o AWS CDK cria um arquivo zip com o binário e cria a função Lambda:

// Go CDK
awslambda.NewFunction(stack, jsii.String("HelloHandler"), &awslambda.FunctionProps{
        Code: awslambda.Code_FromAsset(jsii.String("go-lambda"), &awss3assets.AssetOptions{
                Bundling: &awscdk.BundlingOptions{
                        Image: awscdk.DockerImage_FromRegistry(jsii.String("golang:1.20.1")),
                        Command: &[]*string{
                                jsii.String("bash"),
                                jsii.String("-c"),
                                jsii.String("GOCACHE=/tmp go mod tidy && GOCACHE=/tmp GOARCH=arm64 GOOS=linux go build -tags lambda.norpc -o /asset-output/bootstrap"),
                        },
                },
        }),
        Runtime:      awslambda.Runtime_PROVIDED_AL2(),
        Handler:      jsii.String("bootstrap"),
        Architecture: awslambda.Architecture_ARM_64(),
})
Go

Conclusão

O Lambda está descontinuando o runtime go1.x de acordo com o fim da vida útil do Amazon Linux 1, programado para 31 de dezembro de 2023. Os clientes que usam Go com Lambda devem migrar suas funções para o runtime provided.al2. Os benefícios incluem suporte para processadores AWS Graviton2 com melhor relação preço/desempenho e um caminho de invocação simplificado com desempenho mais rápido.

Para obter mais recursos de aprendizado Serverless, visite Serverless Land.

 

Este artigo foi traduzido do Blog da AWS em Inglês.

 


Sobre o autor

Micah Walter é arquiteto sênior de soluções na AWS

 

 

 

 

Yanko Bolanos é arquiteto sênior de soluções na AWS

 

 

 

 

Ramesh Mathikumar é consultor sênior de DevOps na AWS

 

 

 

 

Tradutor

Daniel Abib é Enterprise Solution Architect na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e segurança. Ele trabalha apoiando clientes corporativos, ajudando-os em sua jornada para a nuvem.

https://www.linkedin.com/in/danielabib/