4
votes

SAM build - construit-il également des couches?

Je suis nouveau dans les deux lambda et SAM - donc si j'ai foiré quelque chose de simple, ne criez pas: D.

Résumé: Je ne parviens pas à faire en sorte que sam build crée une couche spécifiée dans template.yaml , il ne construit que la fonction lambda.

Contexte : J'essaie de créer une fonction lambda en python3.7 qui utilise le module skimage ( scikit-image ). Pour ce faire, j'essaie d'utiliser SAM pour tout construire et tout déployer. ... cela fonctionne

J'essaie de déployer le module scikit-image en tant que couche (et également de construire avec SAM), plutôt que de l'inclure dans la direction de la fonction lambda ... cela ne fonctionne pas


Pour commencer, j'étend simplement l'application standard SAM Hello World .

Je fais fonctionner skimage en l'ajoutant simplement à requirements.txt , puis en utilisant sam build -u , puis en supprimant manuellement les dépendances numpy / scipy du répertoire de package construit (j'ai inclus la couche AWS scipy / numpy).

(J'ai ajouté import numpy, scipy.ndimage et skimage.draw à l'application standard hello world, et inclus des appels de fonction de test à chacun)

requirements.txt:

â–¾ dependencies/                
    requirements.txt (responses and scikit-image)          
â–¸ events/                      
â–¾ hello_world/                 
    __init__.py                
    app.py                     
    requirements.txt (now empty)          
â–¸ tests/                       
  README.md                    
  template.yaml                 

Après cela, tout fonctionne correctement (s'exécutant localement et / ou sur AWS).


Cependant, j'aimerais maintenant déplacer le module skimage hors de mon application et dans un nouveau calque personnalisé (j'aimerais avoir skimage dans un calque à réutiliser pour quelques fonctions)

Pour configurer cela, j'ai créé un répertoire de dépendances et y ai déplacé requirements.txt (en laissant requirements.txt vide dans le répertoire de l'application). J'ai ensuite mis à jour template.yaml pour spécifier également le nouveau calque:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-app

  Sample SAM Template for sam-app

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Layers:
              - arn:aws:lambda:us-west-2:420165488524:layer:AWSLambda-Python37-SciPy1x:2
              - !Ref SkimageLayer
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get

  SkimageLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: Skimage
      Description: Skimage module layer
      ContentUri: dependencies/
      CompatibleRuntimes:
              - python3.7
      RetentionPolicy: Retain
    DependsOn:
            - Skimage

structure de répertoires:

requests
scikit-image

Cependant, lorsque sam build -u avec ce fichier modèle, rien n'est ./dependencies pour la couche spécifiée dans ./dependencies : SkimageLayer dans le fichier template.yml. Cependant, HelloWorldFunction toujours construit correctement (maintenant bien sûr sans aucun module inclus)


1 commentaires

Je travaille un peu sur cette base: noise.getoto.net/2019/02/06/… . À mi-chemin environ, il implique avec comment il le fait que SAM build ne construira pas de couche elle-même, car il exécute manuellement npm install dans son répertoire de dépendances de nœud pour installer les dépendances de nœud


5 Réponses :


2
votes

Réponse rapide - Non , SAM ne construit actuellement pas les couches que vous définissez dans un fichier SAM template.yaml .

Il ne construira que les fonctions que vous définissez .

Cependant (curieusement) il empaqueter (téléchargement à S3) et Deploy (configuration dans AWS, assign de sorte qu'il peut ARN être utilisé , etc.) toutes les couches que vous définissez.


Il y a une demande de fonctionnalité sur les problèmes github SAM pour implémenter la création de couches avec SAM.


Cela peut en fait être piraté dès maintenant pour que SAM crée également vos couches , en créant une fonction factice dans votre fichier de modèle SAM, ainsi qu'une entrée de couche, et en ayant le point d'entrée ContentUri de la couche vers la construction .aws-sam répertoire qui est créé pour la fonction.

Voir mon message ici à ce sujet.

Cette approche semble en fait fonctionner assez bien pour tordre SAM en ce moment pour créer vos couches pour vous.


0 commentaires

1
votes

Je ne sais pas si quelque chose a changé récemment, mais je peux le faire sans problème. Mon fichier de modèle et ma structure sont très similaires à l'OP sauf que j'ai mis tout mon code commun dans ...

/dependencies/python/lib/python3.7/site-packages/

Je n'ai pas inclus de fichier requirements.txt dans ce répertoire ... juste le fichier __init__.py et divers fichiers .py que je dois importer dans mes fonctions.

SAM trouve ensuite le code et construit la couche. Vous n'avez même pas besoin de compresser le contenu du répertoire comme certains tutoriels vous disent de le faire.

La meilleure partie est Layers: peut être placé dans la section Globals: du fichier modèle afin que le calque soit disponible pour toutes vos fonctions!

Globals:
  Function:
    Handler: main.lambda_handler
    Timeout: 10
    Runtime: python3.7
    Layers: 
        - !Ref HelperFunctions

Resources:
  HelperFunctions:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: MyHelperFunctions
      Description: My Lambda Layer with Helper Functions for accessing RDS, Logging, and other utilities.
      ContentUri: dependencies/
      CompatibleRuntimes:
        - python3.6
        - python3.7
      LicenseInfo: MIT
      RetentionPolicy: Delete


9 commentaires

J'apprécie cette réponse - je vais essayer cette approche.


Le problème avec cela en ce moment est que vous créez toutes les dépendances sur votre local. Certains peuvent ne pas fonctionner après le déploiement. numpy par exemple aurait ce problème.


Le chemin est important. Le nom de répertoire de 'dependencies' est juste celui que j'ai choisi mais tout ce qui se trouve en dessous est important et doit suivre cette configuration. Si vous le faites, les packages de site doivent être trouvés lors du téléchargement de la couche. Je n'ai pas essayé de le faire avec numpy mais je ne comprends pas comment cela ne fonctionnerait pas.


@Karuhanga - lorsque vous utilisez SAM, il existe une option avec sam build (je pense que c'est le drapeau -u?) Pour construire dans un conteneur de docker d'environnement AWS lambda. De cette façon, il se construit localement, mais utilise l'environnement AWS approprié. Par conséquent, tout se construit «nativement» pour lambda. Je l'utilise sans problème pour numpy etc.


@Karuhanga - également REMARQUE - AWS fournit une couche numpy / scipy pré-construite que vous pouvez utiliser - vous n'avez pas besoin de créer votre propre couche pour numpy / scipy si c'est tout ce dont vous avez besoin d'une couche.


@Richard comment référeriez-vous du code construit dans un conteneur docker dans contentUri?


Dans le code, il s'agit simplement d'un ensemble de modules packagés, donc des instructions d'importation habituelles. Dans la version SAM, comme ceci: AQSTestCTACR: Type: AWS :: Serverless :: Function Properties: FunctionName: aqs_test_ct_acr Runtime: python3.7 CodeUri: ./src/ Handler: ct_acr.lambda_handler MemorySize: 2048 Timeout: 15 Role: arn: aws : iam :: XXXX Calques: - arn: aws: lambda: us-west-2: XXXX: layer: AWSLambda-Python37-SciPy‌ 1x: 2 - arn: aws: lambda: us-west-2: XXXX: layer: AQSTestModules: 3


Ce qui précède n'est pas formaté: (. Mais je construis un lambda en référence à deux couches - celle que j'ai construite, puis aussi la couche AWS numpy / scipy 'incluse'


Merci. Essayé. sam monte votre dossier sur le conteneur Docker.



0
votes

Je l'ai fait fonctionner avec le script suivant. Testé avec Ubuntu 18 et CodeBuild

Il installe les exigences de la couche dans .aws-sam/build/layername/python/ . Ensuite, vous pouvez exécuter sam package et sam deploy comme d'habitude

build-layers.py :

---  # build spec for AWS CodeBuild

version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
      - pip install aws-sam-cli
  build:
    commands:
      - cd lambda/layers
      - python build-layers.py
      - sam package --s3-bucket foo --s3-prefix sam/lambda/layers | sam deploy --capabilities CAPABILITY_IAM -t /dev/stdin --stack-name LAYERS

template.yaml :

lambda
  layers
    pandas
      requirements.txt (content = pandas)
    sqlparse
      requirements.txt (content = sqlparse)
  template.yaml
  build-layers.py

alors appelez d'abord python build-layers.py , puis sam package puis sam deploy

mes répertoires ressemblent à ceci:

Transform: AWS::Serverless-2016-10-31

Resources:
  pandas:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: pandas
      ContentUri: pandas
      CompatibleRuntimes:
        - python3.6
        - python3.7
        - python3.8
  sqlparse:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: sqlparse
      ContentUri: sqlparse
      CompatibleRuntimes:
        - python3.6
        - python3.7
        - python3.8

buildspec.yml :

import yaml
import subprocess
import sys
import shutil

SAM_BUILD_PATH = ".aws-sam/build"

with open("template.yaml", "r") as f:
    template = yaml.safe_load(f)

for key, resource in template["Resources"].items():
    if resource["Type"] not in ["AWS::Serverless::LayerVersion", "AWS::Lambda::LayerVersion"]:
        continue
    properties = resource["Properties"]
    content_uri = properties["ContentUri"]
    layer_name = properties["LayerName"]
    requirements_path = f"{content_uri}/requirements.txt"

    subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", requirements_path, "-t", f"{SAM_BUILD_PATH}/{layer_name}/python"])

shutil.copyfile("template.yaml", f"{SAM_BUILD_PATH}/template.yaml")


2 commentaires

Hey Neil - Je vais devoir vérifier ça. ... vous l'avez fait fonctionner sans spécifier de fonction? La seule façon auparavant de «tromper» SAM pour créer une couche pour vous était de l'associer à une fonction factice. Vous ne pouviez pas spécifier uniquement un calque dans le fichier yaml de modèle. Mais vous semblez pouvoir le faire! Ce serait bien s'ils avaient changé ça maintenant


Doux - je vais devoir le vérifier alors



2
votes

Depuis la version v0.50.0 de SAM Cli , il construit des couches dans le cadre de sam build .

Le document de conception pourrait être un bon point de départ pour comprendre son fonctionnement.

En gros, vous devez définir un BuildMethod personnalisé avec le runtime cible de votre lambda:

MyLayer:
Type: AWS::Serverless::LayerVersion
Properties:
  ContentUri: my_layer
  CompatibleRuntimes:
    - python3.8
Metadata:
  BuildMethod: python3.8 (or nodejs8.10 etc..)

Attention : pour un langage compilé comme Java, il a un problème où il essaie de construire des couches avant les fonctions. On s'attend à ce qu'il soit corrigé dans la prochaine version ( PR ouvert déjà ).


0 commentaires

0
votes

L'équipe AWS a dû rendre les choses plus faciles, par rapport à ces réponses plus anciennes. À partir de la documentation actuelle, tout ce que vous faites est de répertorier une couche en tant que propriété dans votre modèle (novembre 2020):

ServerlessFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: .
    Handler: my_handler
    Runtime: Python3.7
    Layers:
        - arn:aws:lambda:us-west-2:111111111111:layer:myLayer:1
        - arn:aws:lambda:us-west-2:111111111111:layer:mySecondLayer:1

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-layers.html


0 commentaires