Cómo construir una aplicación Golang conectable y beneficiarse de AWS Lambda Layers.

Golang: ¿por qué merece tu atención?

Golang es un lenguaje de programación de código abierto diseñado e implementado por Google. Es muy utilizado en aplicaciones modernas, especialmente en la nube. Sus características más características son:

  • Golang tiene un tipo estático: proporciona menos flexibilidad, pero lo protege de cometer errores,
  • No está orientado a objetos. Sin embargo, puede crear estructuras e interfaces y eso le da 3 de 4 principios de OOP: abstracción de datos, encapsulación y polimorfismo. La herencia es la única que falta,
  • Goroutines! - La mejor implementación de los hilos de luz que he estado usando. Le permite crear un nuevo hilo de una manera súper fácil usando el operador go y comunicarse entre diferentes gorutinas usando canales,
  • Se compila en un solo binario con todas las dependencias. ¡No más conflictos de paquetes!

Personalmente, considero que Golang es el mejor idioma que uso a diario. Sin embargo, este artículo no tratará de crear su primera función o imprimir "Hello World". Te mostraré cosas un poco más avanzadas. Si eres un principiante y quieres aprender más sobre Golang, visita su página principal.

AWS Lambda y Golang

AWS Lambda es uno de los servicios informáticos sin servidor más populares en la nube pública, lanzado en noviembre de 2014 por Amazon Web Services. ¡Le permite ejecutar su código en respuesta a eventos como DynamoDB, SNS o disparadores HTTP sin aprovisionar o administrar servidores! ¿Sabes lo que es realmente genial? Desde enero de 2018 es compatible con el tiempo de ejecución de Golang. Trabajar con AWS Lambda es realmente simple: simplemente cargue un paquete comprimido con su código y todas las dependencias (binario único cuando use Golang).

Avance rápido, 4 años después, en 2018 re: Invent AWS lanza Lambda Layers que le permite almacenar y administrar datos que se comparten entre diferentes funciones en una o varias cuentas de AWS. Por ejemplo, mientras usa Python, puede poner todas las dependencias en una capa adicional que luego pueden ser utilizadas por otras Lambdas. ¡Ya no es necesario poner diferentes dependencias en cada paquete comprimido! En el mundo de Golang, la situación es diferente, ya que AWS Lambda requiere que cargues un binario compilado. ¿Cómo podemos beneficiarnos de las capas de AWS Lambda? La respuesta es simple: ¡cree una aplicación modular con los complementos de Golang!

Complementos de Golang: una forma de crear una aplicación modular

Golang Plugins es la característica lanzada en Go1.8 que le permite cargar dinámicamente bibliotecas compartidas (archivos .so). Le da la oportunidad de exportar parte de su código a la biblioteca separada o usar el complemento preparado y compilado por otra persona. Es prometedor, sin embargo, hay algunas limitaciones:

  • Su complemento tiene que ser un módulo principal único,
  • Solo puede cargar funciones y variables que se exportan como símbolos ELF,
  • Debido a la escritura estática, debe convertir cada símbolo cargado al tipo correcto. En el peor de los casos, debe definir la interfaz correcta en su código,
  • Funciona solo para Linux y MacOS. Personalmente, no considero esto como una desventaja :)

Creando y probando su primer complemento

Ahora creemos nuestro primer complemento. Como ejemplo, crearemos un módulo simple para el cifrado de cadenas. Volvamos a lo básico e implementemos 2 algoritmos de cifrado simples: Ceasar y Verman.

  • El cifrado César es el algoritmo utilizado por primera vez por Julius Ceases. Cambia cada letra en el texto por el número fijo de posiciones. Por ejemplo, si desea cifrar la palabra golang con la clave 4, obtendrá ktpek. El descifrado funciona de la misma manera. Solo necesita cambiar las letras en la dirección opuesta.
  • El cifrado Verman es similar al Ceaser, basado en la misma idea cambiante, la diferencia es que cambias cada letra por el número diferente de posiciones. Para descifrar el texto, debe tener la clave que contiene las posiciones utilizadas para cifrar el texto. Por ejemplo, si desea cifrar la palabra golang con la clave [-1, 4, 7, 20, 4, -2] obtendrá el futuro.

La implementación completa de este ejemplo está disponible aquí.

Implementación de complementos

El siguiente fragmento contiene la implementación de los dos algoritmos mencionados anteriormente. Para cada uno, implementamos 2 métodos de encriptación y desencriptación de nuestro texto:

Como puede ver, exportamos aquí 3 símbolos diferentes (Golang exporta solo estos identificadores que comienzan con la letra superior):

  • EncryptCeasar - cadena func (int, string) que encripta texto usando el algoritmo Ceasar,
  • DecryptCeaser - cadena func (int, string) que descifra el texto usando el algoritmo Caeser,
  • VermanCipher: variable de tipo vermanCipher que implementa 2 métodos: Cifrar: cadena func (string) y Descifrar: func () (* cadena, error)

Para compilar este complemento, debe ejecutar el siguiente comando:

vaya a construir -buildmode = plugin -o plugin / cipher.so plugin / cipher.go

Por ahora, no hay nada especial: se crearon pocas funciones simples y se compiló un módulo como complemento agregando el argumento -buildmode = plugin.

Complemento de carga y prueba

La diversión comienza cuando queremos usar el complemento compilado en nuestra aplicación. Vamos a crear un ejemplo simple:

Primero, debe importar el paquete de complementos de golang. Contiene solo dos funciones: la primera es para cargar la biblioteca compartida y la segunda es para encontrar un símbolo exportado. Para cargar su biblioteca, debe usar la función Abrir, que requiere proporcionar la ruta a su complemento compartido y devuelve una variable de tipo Plugin. Si no es posible cargar la biblioteca (por ejemplo, ruta incorrecta o archivo dañado), esta función devuelve el error que debe manejarse.

El siguiente paso es cargar cada símbolo exportado utilizando el método de búsqueda. Un pequeño inconveniente es que necesita cargar cada función exportada por separado. Sin embargo, puede combinar varias funciones juntas de la misma manera que se hizo para el símbolo VermanCipher. Una vez que haya cargado todos los símbolos que desea usar, debe convertirlos al tipo correcto. Golang es un lenguaje estáticamente escrito, por lo que no hay otra forma de usar estos símbolos sin emitir. Recuerde, cuando exporta una variable que implementa algunos métodos, debe convertirla al tipo de interfaz correcto (tuve que definir la interfaz encriptación del motor para manejar esto). \ Newline \ newline

Para compilar y ejecutar la aplicación, use el siguiente comando:

ir a construir app.go
./app

En la salida, debería ver el texto cifrado y descifrado como prueba de que el algoritmo funciona correctamente.

Use el complemento en AWS lambda

Para usar nuestro complemento en AWS Lambda, necesitamos hacer algunas modificaciones en nuestra aplicación:

  • AWS Lambda monta capas en el directorio / opt en el contenedor lambda, por lo que debemos cargar nuestro complemento desde este directorio.
  • Necesitamos crear una función de controlador que será utilizada por el motor Lambda para manejar nuestro evento de prueba.

El siguiente fragmento contiene nuestra aplicación ajustada para ser utilizada por Lambda:

Como puede ver, la implementación es muy similar a la anterior. Solo hemos cambiado el directorio desde el que cargamos nuestro complemento y agregamos la respuesta de la función en lugar de imprimir valores. Si desea obtener más información sobre cómo escribir Lambdas en golang, consulte la documentación de AWS.

Implementación de AWS Lambda

Hay dos formas de implementar funciones y capas de AWS Lambda. Puede crear y cargar paquetes comprimidos manualmente o usar el marco más avanzado, lo que lo hace mucho más fácil y rápido. Para la mayoría de mis proyectos, uso el framework Serverless, por lo que ya he preparado el archivo de configuración simple serverless.yml usando esta herramienta:

servicio: cifrado
frameworkVersion: "> = 1.28.0 <2.0.0"
proveedor:
  nombre: aws
  tiempo de ejecución: go1.x
capas:
  cipherLayer:
    ruta: bin / plugin
    Tiempo de ejecución compatible:
      - go1.x
funciones:
  motor:
    manejador: bin / cipherEngine
    paquete:
      excluir:
        - ./**
      incluir:
        - ./bin/cipherEngine
    capas:
      - {Ref: CipherLayerLambdaLayer}

En la sección de capas definimos una sola capa con la ruta al complemento ya creado: se implementará junto con la función lambda. Puede definir hasta 5 capas diferentes, cuyo orden es realmente importante. Se montan en el mismo directorio / opt, por lo que las capas con el número más alto pueden anular los archivos de las capas montadas previamente. Para cada capa, debe proporcionar al menos 2 parámetros: ruta al directorio que contiene la fuente de la capa (ruta al binario del complemento en su caso) y la lista de tiempos de ejecución compatibles.

La siguiente sección de funciones es un lugar donde define la lista de las funciones que se implementarán. Para cada función, debe proporcionar al menos la ruta a la aplicación compilada. Además de eso, necesitamos definir el parámetro de capas con la referencia a la capa definida anteriormente. Esto adjuntará automáticamente la capa a nuestra función Lambda durante la implementación. Lo curioso es que tienes que convertir el nombre de tu capa lambda para que esté TitleCased y agregar el sufijo LambdaLayer si quieres hacer referencia a ese recurso. Parece que el equipo de Serverless lo implementó de esta manera para resolver el conflicto con referencia a los diferentes tipos de recursos.

Una vez que nuestro archivo de configuración serverless.yml esté listo, lo último que debe hacer es compilar nuestra aplicación, completarla e implementarla. Podemos usar Makefile simple para eso:

.PHONY: build buildPlugin clean deploy
construir:
 dep asegurar -v
 env GOOS = linux go build -ldflags = "- s -w" -o bin / cipherEngine cipherEngine / main.go
buildPlugin:
 env GOOS = linux go build -ldflags = "- s -w" -buildmode = plugin -o bin / plugin / cipher.so ../plugin/cipher.go
limpiar:
 rm -rf ./bin ./vendor Gopkg.lock
desplegar: compilación limpia
 sls deploy --verbose

Puede construir e implementar su función ejecutando el siguiente comando:

hacer despliegue

Prueba AWS Lambda

Como mencioné anteriormente, AWS Lambda ejecuta código en la respuesta al evento. Sin embargo, no configuramos ningún desencadenante de eventos, por lo que no se invocará sin nuestra ayuda. Tenemos que hacerlo manualmente usando el framework Serverless o la herramienta awscli:

sls invoke -f nombre_función
aws lambda invoke - nombre-función nombre_función archivo_salida

En la respuesta, debería ver el mismo resultado que antes, lo que demuestra que nuestra función lambda funciona correctamente y carga el complemento desde la capa adicional. Ahora puede crear otras funciones que usarán la misma capa o incluso compartirla con otras cuentas de AWS.

Resumen

Fue muy divertido usar módulos de Golang y probar cómo integrarlos con las nuevas capas AWS Lambda. La biblioteca de complementos es realmente impresionante, sin embargo, debido a sus limitaciones y la especificación de Golang, solo se puede usar en algunos escenarios especiales. Creo que para la mayoría de los desarrolladores que trabajan en los proyectos estándar no será necesario ni posible utilizar complementos. Solo me vienen a la mente dos razones:

  • Implementación de algoritmos complicados que pueden ser utilizados por otras aplicaciones ej. codificación de video o algoritmos de encriptación.
  • Compartir su algoritmo con otros sin publicar su código.