Como criar aplicativos Golang conectáveis ​​e se beneficiar das Camadas da AWS Lambda.

Golang - por que vale a sua atenção?

Golang é uma linguagem de programação de código aberto projetada e implementada pelo Google. É muito usado em aplicativos modernos, especialmente na nuvem. São os recursos mais característicos:

  • O Golang é digitado estaticamente - fornece menos flexibilidade, mas protege você de cometer erros,
  • Não é orientado a objetos. No entanto, você pode criar estruturas e interfaces e isso fornece três dos quatro princípios de POO: abstração de dados, encapsulamento e polimorfismo. A herança é a única que falta,
  • Goroutines! - a melhor implementação dos fios leves que já usei. Ele permite que você crie um novo thread da maneira mais fácil usando o operador go e se comunique entre diferentes goroutines usando canais,
  • Compila no binário único com todas as dependências - sem mais conflitos de pacotes!

Pessoalmente, considero Golang a melhor língua que uso diariamente. No entanto, este artigo não será sobre como criar sua primeira função ou imprimir "Hello World". Eu vou te mostrar coisas um pouco mais avançadas. Se você é iniciante e quer saber mais sobre Golang, visite sua página principal.

AWS Lambda & Golang

O AWS Lambda é um dos serviços de computação sem servidor mais populares na nuvem pública, lançado em novembro de 2014 pela Amazon Web Services. Ele permite que você execute seu código em resposta a eventos como gatilhos DynamoDB, SNS ou HTTP sem provisionar ou gerenciar servidores! Você sabe o que é realmente ótimo? Desde janeiro de 2018, ele suporta o tempo de execução Golang. Trabalhar com o AWS Lambda é realmente simples - basta fazer o upload de um pacote compactado com seu código e todas as dependências (binário único ao usar o Golang).

Avanço rápido, 4 anos depois em 2018, re: Invent AWS lança o Lambda Layers, que permite armazenar e gerenciar dados que são compartilhados em diferentes funções em uma ou várias contas da AWS! Por exemplo, ao usar o Python, você pode colocar todas as dependências em uma camada adicional que pode ser usada posteriormente por outros Lambdas. Não há mais necessidade de colocar dependências diferentes em cada pacote compactado! No mundo Golang, a situação é diferente, pois o AWS Lambda exige que você faça o upload do binário compilado. Como podemos nos beneficiar das camadas da AWS Lambda? A resposta é simples - crie um aplicativo modular usando os Golang Plugins!

Golang Plugins - uma maneira de criar um aplicativo modular

Golang Plugins é o recurso lançado no Go1.8 que permite carregar dinamicamente bibliotecas compartilhadas (arquivos .so). Ele oferece a oportunidade de exportar parte do seu código para uma biblioteca separada ou de usar o plug-in preparado e compilado por outra pessoa. É promissor, no entanto, existem algumas limitações:

  • Seu plug-in deve ser um módulo principal único,
  • Você pode carregar apenas funções e variáveis ​​exportadas como símbolos ELF,
  • Devido à digitação estática, você deve converter todos os símbolos carregados no tipo correto. No pior cenário, você precisa definir a interface correta no seu código,
  • Funciona apenas para o Linux e MacOS. Pessoalmente, não considero isso uma desvantagem :)

Construindo e testando seu primeiro plugin

Agora vamos criar nosso primeiro plugin. Como exemplo, criaremos um módulo simples para a criptografia de cadeias. Vamos voltar ao básico e implementar 2 algoritmos simples de criptografia - Ceasar e Verman.

  • A cifra de César é o algoritmo usado primeiramente por Julius Ceases. Ele muda todas as letras do texto pelo número fixo de posições. Por exemplo, se você quiser criptografar a palavra golang com a chave 4, obterá o ktpek. A descriptografia funciona da mesma maneira. Você só precisa mudar as letras na direção oposta.
  • A cifra de Verman é semelhante à Ceaser, com base na mesma ideia de mudança, a diferença é que você muda todas as letras pelo número diferente de posições. Para descriptografar o texto, você precisa ter a chave que contém as posições usadas para criptografar o texto. Por exemplo, se você quiser criptografar a palavra golang com a chave [-1, 4, 7, 20, 4, -2], obterá futuro.

A implementação completa deste exemplo está disponível aqui.

Implementação de plugins

O seguinte snippet contém a implementação dos dois algoritmos mencionados acima. Para cada um, implementamos 2 métodos de criptografar e descriptografar nosso texto:

Como você pode ver, exportamos aqui três símbolos diferentes (a Golang exporta apenas esses identificadores que começam com a letra superior):

  • EncryptCeasar - string func (int, string) que criptografa texto usando o algoritmo Ceasar,
  • DecryptCeaser - string func (int, string) que descriptografa texto usando o algoritmo Caeser,
  • VermanCipher - variável do tipo vermanCipher implementando 2 métodos: Criptografar: func (string) e Decrypt: func () (* string, error)

Para compilar este plugin, você deve executar o seguinte comando:

vá build -buildmode = plugin -o plugin / cipher.so plugin / cipher.go

Por enquanto, não há nada de especial - poucas funções simples foram criadas e um módulo foi compilado como um plugin adicionando o argumento -buildmode = plugin.

Carregar e testar plug-in

A diversão começa quando queremos usar o plugin compilado em nosso aplicativo. Vamos criar um exemplo simples:

Primeiro, você precisa importar o pacote de plug-ins golang. Ele contém apenas duas funções - a primeira é para carregar a biblioteca compartilhada e a segunda é para encontrar um símbolo exportado. Para carregar sua biblioteca, você deve usar a função Open, que requer o caminho do seu plug-in compartilhado e retorna a variável do tipo Plugin. Se não for possível carregar a biblioteca (por exemplo, caminho incorreto ou arquivo corrompido), essa função retornará o erro que deve ser tratado.

O próximo passo é carregar todos os símbolos exportados usando o método Lookup. Um pequeno inconveniente é que você precisa carregar todas as funções exportadas separadamente. No entanto, você pode combinar várias funções da mesma maneira que foi feito para o símbolo VermanCipher. Depois de carregar todos os símbolos que deseja usar, você deve convertê-los no tipo correto. Golang é uma linguagem de tipo estatístico, portanto não há outra maneira de usar esses símbolos sem converter. Lembre-se, quando você exporta uma variável que implementa alguns métodos, precisa convertê-la no tipo de interface correto (eu tive que definir a interface encryptionEngine para lidar com isso). \ Newline \ newline

Para compilar e executar o aplicativo, use o seguinte comando:

vá construir app.go
./aplicativo

Na saída, você deve ver o texto criptografado e descriptografado como uma prova de que o algoritmo funciona corretamente.

Usar plug-in no AWS lambda

Para usar nosso plug-in no AWS Lambda, precisamos fazer algumas modificações em nosso aplicativo:

  • O AWS Lambda monta camadas no diretório / opt no contêiner lambda, portanto, precisamos carregar nosso plug-in nesse diretório.
  • Precisamos criar uma função de manipulador que será usada pelo mecanismo Lambda para manipular nosso evento de teste.

O seguinte trecho contém nosso aplicativo ajustado para ser usado pelo Lambda:

Como você pode ver, a implementação é muito semelhante à anterior. Nós mudamos apenas o diretório do qual carregamos nosso plug-in e adicionamos a resposta da função em vez de imprimir valores. Se você quiser saber mais sobre como escrever Lambdas em golang, consulte a documentação da AWS.

Implantação do AWS Lambda

Há duas maneiras de implantar funções e camadas do AWS Lambda. Você pode criar e fazer upload de pacotes compactados manualmente ou usar a estrutura mais avançada, o que torna muito mais fácil e rápido. Para a maioria dos meus projetos, eu uso a estrutura Serverless, por isso já preparei o arquivo de configuração serverless.yml simples usando esta ferramenta:

service: cipherService
frameworkVersion: "> = 1.28.0 <2.0.0"
fornecedor:
  nome: aws
  tempo de execução: go1.x
camadas:
  cipherLayer:
    caminho: bin / plugin
    compatibleRuntimes:
      - go1.x
funções:
  motor:
    manipulador: bin / cipherEngine
    pacote:
      excluir:
        - ./**
      incluir:
        - ./bin/cipherEngine
    camadas:
      - {Ref: CipherLayerLambdaLayer}

Na seção de camadas, definimos uma única camada com o caminho para o plug-in já criado - ele será implementado junto com a função lambda. Você pode definir até 5 camadas diferentes, que ordem é realmente importante. Eles são montados no mesmo diretório / opt, portanto, as camadas com o número mais alto podem substituir os arquivos das camadas montadas anteriormente. Para cada camada, você precisa fornecer pelo menos 2 parâmetros: caminho para o diretório que contém a origem da camada (caminho para o binário do plug-in no seu caso) e a lista de tempos de execução compatíveis.

A próxima seção de funções é um local onde você define a lista de funções a serem implantadas. Para todas as funções, você precisa fornecer pelo menos o caminho para o aplicativo compilado. Além disso, precisamos definir o parâmetro de camadas com referência à camada definida acima. Isso anexará automaticamente a camada à nossa função Lambda durante a implantação. O engraçado é que você precisa converter o nome da camada lambda para TitleCased e adicionar o sufixo LambdaLayer se desejar consultar esse recurso. Parece que a equipe sem servidor o implementou dessa maneira para resolver o conflito com referência aos diferentes tipos de recursos.

Quando nosso arquivo de configuração serverless.yml estiver pronto, a última coisa a fazer é compilar nosso aplicativo, plug-in e implantá-lo. Podemos usar o Makefile simples para isso:

.PHONY: compilação limpa do buildPlugin
construir:
 dep garantir -v
 env GOOS = linux go build -ldflags = "- s -w" -o bin / cipherEngine cipherEngine / main.go
buildPlugin:
 env GOOS = linux vai construir -ldflags = "- s -w" -buildmode = plugin -o bin / plugin / cipher.so ../plugin/cipher.go
limpar \ limpo:
 rm -rf ./bin ./vendor Gopkg.lock
deploy: compilação limpa
 sls deploy --verbose

Você pode criar e implantar sua função executando o seguinte comando:

fazer implantar

Teste o AWS Lambda

Como mencionei anteriormente, o AWS Lambda executa o código na resposta ao evento. No entanto, não configuramos nenhum gatilho de evento, portanto ele não será chamado sem a nossa ajuda. Temos que fazer isso manualmente usando a estrutura sem servidor ou a ferramenta awscli:

sls invoca -f nome_da_função
aws lambda invoke - nome da função nome_da_função nome_da_arquivo

Na resposta, você deve ver a mesma saída de antes, o que prova que nossa função lambda funciona corretamente e carrega o plug-in da camada adicional. Agora você pode criar outras funções que usarão a mesma camada ou até mesmo compartilharão com outras contas da AWS.

Sumário

Foi muito divertido usar os módulos Golang e testar como integrá-los às recém-lançadas AWS Lambda Layers. A biblioteca de plug-ins é realmente incrível, no entanto, devido às suas limitações e à especificação Golang, ela pode ser usada apenas em alguns cenários especiais. Eu acho que para a maioria dos desenvolvedores que estão trabalhando nos projetos padrão, não será necessário nem mesmo possível usar plug-ins. Apenas duas razões me vêm à mente:

  • Implementando algoritmos complicados que podem ser usados ​​por outros aplicativos, ex. algoritmos de codificação ou criptografia de vídeo.
  • Compartilhando seu algoritmo com outras pessoas sem publicar seu código.