Le Blog Amazon Web Services

Comment deployer une fonction AWS Lambda à l’aide d’AWS CloudFormation dans différentes régions AWS (de manière générique)

Déployer des fonctions AWS Lambda en utilisant AWS CloudFormation est une solution de déploiement fiable, reproductible et permettant la gestion des versions.

Déployer des fonctions AWS Lambda avec cette méthode, dans une seule région, est facilement réalisable.
Cela devient plus compliqué lorsqu’on souhaite avoir une solution qui permet de déployer une fonction lambda dans plusieurs régions AWS (dans lesquelles est présent le service AWS Lambda).

Un des moyens pour déployer AWS Lambda consiste à stocker l’ensemble des fichiers dans une archive zip et à la stocker dans un compartiment S3 (Amazon Simple Storage Service).

En revanche, la fonction lambda nécessite que le zip soit situé dans un compartiment S3 situé dans la même région que la pile AWS CloudFormation (Amazon S3 étant un service régional). Par conséquent ce modèle de déploiement est restreint puisqu’il fait référence à un seul compartiment S3, donc une seule région.

Par la suite nous allons présenter 3 modèles de déploiement qui permettent de contourner ce problème.

1. Ressources personnalisées

Lorsqu’une pile (stack) AWS CloudFormation est créée, un compartiment (bucket) Amazon S3 est créé dans la même région que la pile et les zips des Lambda sont copiés dans ce compartiment par une ressource personnalisée AWS CloudFormation.

CloudFormation Lambda Deployment

Avec ce modèle, un seul compartiment doit contenir le fichier zip Lambda à l’avance et aucun travail supplémentaire n’est requis pour que des nouvelles régions soient prises en charge. En raison de sa flexibilité, cette approche est recommandée pour la plupart des cas d’utilisation. Toutefois, il nécessite plusieurs ressources supplémentaires dans le modèle de déploiement :

  • une fonction Lambda permettant de copier les zips
  • un rôle IAM (Identity and Access Management) associé
  • un compartiment Amazon S3
  • la ressource personnalisée

L’extrait de code suivant crée un nouveau compartiment Amazon S3 dans la région où se situe la pile AWS CloudFormation (LambdaZipsBucket), puis copie les fichiers zip (CopyZips.Properties.Objects) à partir d’un compartiment source (CopyZips.Properties.SourceBucket) dans le nouveau compartiment.

Resources:
    LambdaZipsBucket:
        Type: AWS::S3::Bucket
    CopyZips:
        Type: Custom::CopyZips
        Properties:
          ServiceToken: !GetAtt 'CopyZipsFunction.Arn'
          DestBucket: !Ref 'LambdaZipsBucket'
          SourceBucket: !Ref 'QSS3BucketName'
          Prefix: !Ref 'QSS3KeyPrefix'
          Objects:
            - functions/packages/MyFunction/lambda.zip

A noter que la paramètre Objects prend en entrée une liste de chemins, de sorte que si vous avez plusieurs fonctions Lambda dans votre modèle, tous les fichiers zip peuvent être ajoutés à une seule ressource CopyZips.
Maintenant, il faut déclarer la fonction Lambda et la faire pointer vers le compartiment S3 nouvellement créé.
Lors de la création de la fonction, nous pointons MyFunction.Properties.Code.S3Bucket vers LambdaZipsBucket.

 MyFunction:
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/MyFunction/lambda.zip'
      ...

Notez que la clé DependsOn pointe vers la ressource personnalisée CopyZips.
Par défaut, AWS CloudFormation tentera de lancer en parallèle des ressources non dépendantes les unes des autres. Il est donc nécessaire de s’assurer que les fichiers zip aient déjà été copiés avant la création de notre fonction Lambda, d’où la nécessité d’imposer cette dépendance.
Pour implémenter cela dans votre propre contexte, vous aurez besoin du code CopyZips Lambda et du rôle IAM associé également déployés.
Un exemple complet d’implémentation est disponible dans le référentiel d’exemples AWS Quick Start.

2. Un compartiment S3 dans chaque région

Si vous avez besoin que le template soit capable de déployer dans quelques régions (liste qui ne change pas fréquemment) le plus simple est de copier, au préalable, le zip vers les compartiments S3 de ces régions.
Lorsque le code de la fonction Lambda est publié ou mis à jour, votre processus de déploiement peut copier le fichier .zip dans chaque compartiments S3.
Pour rendre le modèle générique, les noms des compartiments doivent comporter un préfixe commun suivi du nom de la région. Votre code de modèle peut ensuite utiliser la fonction intrinsèque Fn::Sub pour ajouter la région à la fin du préfixe commun.

MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Sub 'lambda-zips-${AWS::Region}'
      ...

3. Code en ligne de la fonction

Les fonctions simples écrites en NodeJs ou Python peuvent être déclarées directement dans le template AWS CloudFormation qui permet d’éviter de gérer un fichier zip. Comme un template AWS CloudFormation est limité à un maximum de 4096 caractères, ce mode convient pour les petites fonctions.

Resources:
  MyFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |
          import json
          def handler(event, context):
              print("Event: %s" % json.dumps(event))
      ...

Conclusion

Dans cet article, nous avons abordé les différentes manières de créer des modèles AWS CloudFormation qui permettent de déployer des fonctions AWS Lambda dans les différentes régions AWS. Nous aimerions avoir vos retours sur leur fonctionnement. Si vous implémentez un autre modèle qui fonctionne très bien, n’hésitez pas à nous le faire savoir en commentant ci-dessous ou en créant une PR sur GitHub.

Traduit en français par Corneliu Croitoru, Solutions Architect AWS, LinkedIn.
Corneliu est très impliqué dans la communauté Serverless chez AWS et il assiste les clients, principalement français, de toute taille (startups, PME, enterprise) en les aidant à déployer leurs architectures cloud native sur AWS.

Source