[PYTHON] [AWS] Faites des choses de type SSI avec S3 / Lambda

2020.11.16 mise à jour Version Alibaba Cloud Je l'ai fait.

TL;DR Le code HTML dans lequel SSI (include virtual) est décrit est stocké dans un compartiment spécifique de S3, et les sources de l'inclusion sont combinées par Lambda, puis stockées dans un autre compartiment.

Ce que je voulais faire

Etant donné que S3 est un service d'hébergement de site statique, il ne peut en principe pas être traité dynamiquement côté serveur. Bien sûr, le côté CDN (CloudFront), qui est la destination de la mise en cache après cela, ne peut pas non plus être utilisé.

Dans ce cas, je pense que la méthode standard consiste à créer un environnement de développement local, à les conserver dans des fichiers séparés localement et à les combiner lors de la compilation, mais S3 + est un site existant qui utilisait à l'origine SSI. Malheureusement, ce flux ne peut pas être introduit pour tous les projets, y compris lors du transfert vers CloudFront.

Donc, si SSI a été utilisé à l'origine, j'ai essayé de l'ajuster du côté AWS afin qu'il puisse être utilisé tel quel sans le remplacer tel quel.

Ce que j'ai fait

(En principe, les paramètres IAM ont été terminés)

En gros, je me réfère à cet article et je le personnalise moi-même. Faire des choses de type SSI avec S3 et Lambda

Sur le site de référence, j'étais un peu inquiet de devoir ajouter .ssi comme suffixe à l'extension du fichier d'origine. Un seau pour la température est préparé séparément et ajusté afin qu'il puisse être traité sans ajouter de suffixe.

Constitution

Fondamentalement, les seuls services que nous utilisons sont S3 et Lambda. CloudFront si nécessaire. ARMS_TECHSTACK (1) (1).png

Méthode de réglage

S3 Préparez deux compartiments pour le téléchargement temporaire des fichiers et un compartiment pour la publication.

Seau public

Le nom peut être n'importe quoi. Cette fois, c'est "s3-ssi-include".

Godet pour temp

Le nom peut être n'importe quoi. Cette fois, c'est "s3-ssi-include-base".

Chaque paramètre

On suppose que les autorisations d'accès sont définies de manière appropriée. Le compartiment temporaire stocke les fichiers et n'est transmis qu'au compartiment public, il n'est donc pas nécessaire de le publier. Si vous utilisez également CloudFront pour votre bucket de publication, vous n'avez pas besoin de le publier.

Godet pour temp

Depuis la page de détails du bucket pour temp, allez dans "Propriétés" -> "Notification d'événement" -> "Créer une notification d'événement". La fonction Lambda est maintenant lancée lorsque le fichier est téléchargé (événement PUT)

--Type d'événement: PUT --Destination: fonction Lambda

Après avoir sélectionné jusqu'à, effectuez le réglage une fois. Plus tard, après avoir créé la fonction Lambda, je suis revenu à nouveau sur cet écran et

--Spécifier la fonction Lambda: spécifiez la fonction Lambda créée précédemment dans "Sélectionner parmi les fonctions Lambda"

Il est nécessaire de définir.

Lambda

Lambda détecte l'événement PUT, et si SSI (Server Side Include) est décrit dans le fichier HTML téléchargé, Lambda l'inclura et créera une fonction pour le stocker dans un autre compartiment. Pour S3, modifiez la stratégie de base de ressources pour public pour temporaire et accordez des autorisations. Je pense que ce qui suit sera utile. Politique basée sur les ressources de Lambda lorsqu'elle est déclenchée par S3

Code de fonction

import json
import os
import logging
import boto3
from botocore.errorfactory import ClientError
import re
import urllib.parse

logger = logging.getLogger()
logger.setLevel(logging.INFO)
s3 = boto3.client('s3')
def lambda_handler(event, context):
    logger.info('## ENVIRONMENT VARIABLES')
    logger.info(os.environ)
    logger.info('## EVENT')
    logger.info(event)
 
    input_bucket = event['Records'][0]['s3']['bucket']['name']
    output_bucket = os.environ['S3_BUCKET_TARGET']

    logger.info('## INPUT BUKET')
    logger.info(input_bucket)
    
    input_key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    logger.info('## INPUT KEY')
    logger.info(input_key)

    try:
        #Obtenir le fichier d'entrée
        response = s3.get_object(Bucket=input_bucket, Key=input_key)

        if not input_key.endswith('.html'):
            s3.copy_object(Bucket=output_bucket, Key=input_key, CopySource={'Bucket': input_bucket, 'Key': input_key})
        else:
            input_html = response[u'Body'].read().decode('utf-8')
            output_html = input_html
            #Obtenir la description SSI
            include_path_base = re.findall(r'<!--#include virtual="/(.*?)" -->.*?\n', input_html, flags=re.DOTALL)
            logger.info('## PATH BASE')
            logger.info(include_path_base)
            if len(include_path_base) > 0:
                for path in include_path_base:
                    include_path = path
                    logger.info('## PATH')
                    logger.info(include_path)
            
                    #Obtenir le fichier SSI
                    try:
                        include = s3.get_object(Bucket=input_bucket, Key=include_path)
                        include_html = include[u'Body'].read().decode('utf-8')
                        #Exécutez SSI
                        output_html = output_html.replace('<!--#include virtual="/' + include_path + '" -->', include_html)
                    except ClientError:
                        pass
            
            #Sortie de fichier
            logger.info('## OUTPUT BUKET')
            logger.info(output_bucket)
            
            output_key    = input_key
            logger.info('## OUTPUT KEY')
            logger.info(output_key)
            
            out_s3   = boto3.resource('s3')
            s3_obj   = out_s3.Object(output_bucket, output_key)
            response = s3_obj.put(Body = bytes(output_html, 'UTF-8'))
    except Exception as e:
        logger.info(e)
        raise e

Autres réglages

Variable d'environnement

Définissez le nom du compartiment public (cette fois s3-ssi-include) dans la variable d'environnement S3_BUCKET_TARGET sur l'écran de gestion.

En outre, enregistrez-le une fois jusqu'à présent et spécifiez la fonction __Lambda du côté S3: Spécifiez la fonction Lambda créée précédemment dans "Sélectionner parmi les fonctions Lambda" __.

en conclusion

Cela termine la fonction que Lambda incorpore le fichier d'inclusion au moment du téléchargement du fichier dans le compartiment S3 à des fins temporaires et le transfère vers le compartiment S3 public d'origine.

Je pense qu'il peut être stocké dans S3 comme s'il était téléchargé sur un serveur Web normal, donc si vous devez migrer un site qui utilise SSI vers S3 + CloudFront pour la migration de site, etc., il est courant que ce soit décrit dans SSI. Vous pouvez migrer des fichiers sans avoir à tous les remplacer en même temps. Si vous remplacez les fichiers communs gérés à l'origine par SSI par chaque fichier, les fichiers communs suivants seront codés en dur, ce qui augmentera la main-d'œuvre et les risques opérationnels. Pour être honnête, je ne veux pas en faire trop car il y a un risque d'erreur humaine dans le remplacement du lot lui-même. Compte tenu de cela, je me demande si cette fonction est assez pratique. Cependant, l'inconvénient est que cela coûte cher car il utilise deux seaux, et c'est un peu difficile à comprendre, il est donc nécessaire de le faire connaître correctement.

Maintenant, avec l'évolution de CI / CD et Docker, je pense qu'il y a moins de situations où vous vous inquiétez de ce qui précède. Il n'y a pas que de tels sites dans le monde, alors je me demande si la demande est si faible.

Tout cela vient du terrain.

Recommended Posts

[AWS] Faites des choses de type SSI avec S3 / Lambda
[AWS] Associez Lambda et S3 à boto3
Connectez-vous à s3 avec AWS Lambda Python
PyTorch avec AWS Lambda [importation Lambda]
[AWS] Que faire lorsque vous souhaitez piper avec Lambda
Exporter les journaux CloudWatch vers S3 avec AWS Lambda (Pythyon ver)
[AWS] Créer une API avec API Gateway + Lambda
Tests faciles d'AWS S3 avec MinIO
Notifier HipChat avec AWS Lambda (Python)
Envoyer les images prises avec ESP32-WROOM-32 vers AWS (API Gateway → Lambda → S3)
[AWS] Utilisation de fichiers ini avec Lambda [Python]
Je viens de faire FizzBuzz avec AWS Lambda
[AWS] Créez un environnement Python Lambda avec CodeStar et faites Hello World
Téléchargez ce que vous avez dans la demande vers S3 avec AWS Lambda Python
[AWS SAM] Créer une API avec DynamoDB + Lambda + API Gateway
Grattage sans serveur régulier avec AWS lambda + scrapy Part 1.8
Afficher les images sur S3 avec API Gateway + Lambda
Application sans serveur avec AWS SAM! (APIGATEWAY + Lambda (Python))
[AWS] Essayez de tracer API Gateway + Lambda avec X-Ray
Exporter un instantané RDS vers S3 avec Lambda (Python)
J'ai essayé de connecter AWS Lambda à d'autres services
Automatisation de la construction de l'infrastructure avec CloudFromation + troposphère + AWS Lambda
[AWS] Play with Step Functions (SAM + Lambda) Part.3 (Branch)
Déployer la fonction Python 3 avec Serverless Framework sur AWS Lambda
Créer une couche pour AWS Lambda Python dans Docker
[AWS] Play with Step Functions (SAM + Lambda) Part.1 (Basic)
Je veux AWS Lambda avec Python sur Mac!
Gérer la rétention des groupes de journaux Amazon CloudWatch avec AWS Lambda
Choses à faire lorsque vous commencez à développer avec Django
Créez des tweets ordinaires comme une flotte avec AWS Lambda et Python
[AWS] Play with Step Functions (SAM + Lambda) Part.2 (Paramètres)
Créer des couches Lambda avec Lambda
Agréger les données AWS S3
Faites Houdini avec Python3! !! !!
Tweet d'AWS Lambda
Téléchargeur S3 avec boto
Essayez les destinations AWS Lambda
[AWS] Essayez d'ajouter la bibliothèque Python à la couche avec SAM + Lambda (Python)
Essayez d'automatiser le démarrage / l'arrêt des instances EC2 avec AWS Lambda
Je viens de créer un environnement virtuel avec la couche AWS lambda
Créez rapidement une API avec Python, lambda et API Gateway à l'aide d'AWS SAM
[Python] Exportez régulièrement de CloudWatch Logs vers S3 avec Lambda
Surveillance du site et notification d'alerte avec AWS Lambda + Python + Slack