Je souhaite créer une page qui utilise AWS Lambda pour générer __dynamic HTML __. Avec Lambda, vous pouvez exécuter vos scripts Python préférés sans avoir à configurer votre propre serveur, je vais donc essayer de l'utiliser pour créer une page qui génère du HTML dynamique.
Il y a déjà pas mal de discussions sur la création de pages avec Lambda, mais l'intégration du proxy Lambda __API Gateway précédemment annoncée __ Le but de cette fois est de faire en sorte que cela se sente un peu mieux en combinant l'outil de déploiement de Lambda apex. De plus, template engine est indispensable pour cracher du HTML à partir du script, j'ai donc joué avec lui pour vérifier s'il peut réellement être utilisé en combinaison.
Quant au type de page à créer, cette fois j'ai décidé de construire un __ sanctuaire __.
L'un des moteurs de template les plus connus de Python est jinja2
, et j'ai décidé de créer un sanctuaire sans serveur.
(Mais c'est juste une page Web, juste au cas où)
Je veux en faire un échantillon d'une page dynamique, donc je vais mettre en place un compteur d'accès qui montre le nombre de fidèles. Eh bien, renvoyer l'heure actuelle est un bon exemple de dynamique, mais c'est aussi ennuyeux de faire ce que vous pouvez faire avec Javascript sur le serveur, et je pense que la plupart des choses qui nécessitent un traitement dynamique sont pour déranger la base de données. , J'ai choisi le compteur d'accès comme élément pratique. Gardez un œil sur le fait que le compteur d'accès lui-même est traité comme un fossile.
https://cloudcraft.co/view/67eed248-a460-46dc-91dd-fdb5a70f529f?key=D4aRY_6kyWIfbEKtYk78TQ
La configuration du serveur que je vais faire cette fois est la suivante. Lambda ne peut pas être atteint directement depuis le navigateur, j'ai donc mordu la passerelle API avant de la rendre accessible. De plus, DynamoDB est installé derrière lui pour enregistrer le nombre d'accès. DynamoDB est également une base de données clé-valeur qui peut être utilisée sans créer d'instance. C'est simple, mais c'est toujours une bonne architecture sans serveur.
Apex
Cette fois, j'ai décidé de déployer sur Lambda à l'aide d'un outil appelé Apex. Lorsque vous utilisez des bibliothèques externes avec Lambda, elles doivent être compressées et placées, mais cet outil appelé Apex est très pratique car il facilite le déploiement et l'exécution des scripts installés à partir de la ligne de commande.
Je n'entrerai pas dans les détails ici,
apex init
apex deploy
Vous pouvez déployer rapidement comme ça.
DynamoDB Préparez d'abord une table pour l'agrégation d'accès. Dans le cas de DynamoDB, il n'est pas nécessaire de définir toutes les colonnes à utiliser car il est sans schéma, mais il est nécessaire de décider à l'avance de la clé primaire pour l'analyse.
Cette fois, j'ai fait le tableau suivant.
Nous avons une clé de partition primaire nommée counter_id
.
En tant qu'utilisation, c'est comme préparer 10 compteurs avec counter_id de 0 à 9 et les spécifier de manière aléatoire à incrémenter. En préparant plusieurs compteurs, l'écriture n'est pas concentrée en un seul endroit et des performances constantes peuvent être maintenues.
Puisque DynamoDB n'a pas de transactions, j'ai pensé qu'écrire dans la même table en même temps la rendrait incohérente, mais il semble qu'un compteur atomique puisse être réalisé en incrémentant comme une expression en utilisant ʻupdate_item`. (Je viens d'apprendre)
Lors de la lecture, nous obtiendrons tous les compteurs et nous en rendrons la somme. Si vous n'utilisez pas la "cohérence forte", il semble que le résultat écrit ne sera pas reflété immédiatement, mais cette fois nous ne cherchons pas de rigueur, nous utilisons donc une cohérence faible raisonnable.
Le résultat de l'écriture à plusieurs reprises.
Je vais le faire immédiatement.
En plaçant le package Jinja2 et le modèle que je souhaite utiliser dans le dossier des fonctions Apex, j'ai pu utiliser le moteur de modèle avec Lambda sans aucun problème.
Structure des dossiers.txt
├── functions
│ └── jinja
│ ├── jinja2/Tel
│ ├── main.py
│ ├── requirements.txt
│ └── templates
│ ├── index.html
│ └── layout.html
├── project.json
La structure des dossiers vue depuis la racine du projet Apex est ci-dessus. Il existe un dossier appelé jinja dans le dossier appelé functions, qui est le dossier racine de la fonction Lambda définie cette fois. En créant plusieurs dossiers dans cette hiérarchie, il est possible de gérer différentes fonctions Lambda ensemble.
Pour utiliser jinja2
, vous devez lancer pip install -t .jinja2
dans le dossier jinja pour installer tout le paquet jinja2. Créez également un dossier pour les fichiers modèles que vous prévoyez d'utiliser.
main.py
# coding: utf-8
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader(path.join(path.dirname(__file__), 'templates'), encoding='utf8'))
template = env.get_template('index.html')
html = template.render()
Lors de l'appel, cela ressemble à ceci. Vous pouvez maintenant afficher les modèles dans templates / index.html.
Il est facile d'utiliser la bibliothèque officielle boto3
pour accéder à DynamoDB à partir de la fonction Lambda. Vous pouvez l'utiliser sans avoir à le mettre dans le package Apex (dans certains cas, vous pouvez le mettre explicitement car vous souhaitez corriger la version), et si vous spécifiez le rôle approprié pour Lambda, vous pouvez l'utiliser sans avoir à vous authentifier dans votre code.
main.py
import boto3
dynamodb = boto3.resource('dynamodb')
count_table = dynamodb.Table('lambda-jinja')
counts = count_table.scan(Limit=10)
Avec API Gateway, vous pouvez exécuter Lambda à partir de HTTP et recevoir les résultats. Cependant, avec la passerelle API conventionnelle, il était nécessaire de mapper quel type de requête provenait de quel type de chemin et quel type de réponse était retourné. C'est ~~ relativement gênant ~~ Je ne pouvais pas gérer des cas tels que ne pas pouvoir répondre à des requêtes arbitraires ou réutiliser un script en fonction du chemin, mais récemment un mécanisme merveilleux appelé intégration de proxy a été introduit. c'était fait. Si vous l'utilisez, les informations de requête et de chemin seront transmises au côté fonction, de sorte que les possibilités d'API Gateway + Lambda s'étendent immédiatement. J'ai tout de suite essayé cette fois.
Créez une méthode et une ressource pour l'itinéraire avec API Gateway de cette manière et associez-les à Lambda à créer cette fois.
swagger.yaml
---
swagger: "2.0"
basePath: "/jinja"
schemes:
- "https"
paths:
paths:
/:
x-amazon-apigateway-any-method:
produces:
- "application/json"
responses:
200:
description: "200 response"
schema:
$ref: "#/definitions/Empty"
/{proxy+}:
x-amazon-apigateway-any-method:
produces:
- "application/json"
parameters:
- name: "proxy"
in: "path"
required: true
type: "string"
responses: {}
definitions:
Empty:
type: "object"
title: "Empty Schema"
L'écriture en Swagger ressemble à ceci.
En listant la ressource comme / {proxy +}
, il est possible de traiter les requêtes de n'importe quel chemin avec le même Lambda.
Je ne pouvais pas récupérer l'accès à la racine uniquement avec / {proxy +}
, donc j'ai également défini une méthode séparée pour la racine.
La configuration côté API Gateway était facile, mais il y avait un problème côté Lambda. Je me demandais si je pouvais créer un Lambda qui renvoie du HTML et le connecter à API Gateway, et il renverrait la page, mais c'était un peu différent. Si vous renvoyez simplement du HTML, API Gateway renverra 502. Au début, je déconnais avec les paramètres ContentType et API Gateway, pensant que le format n'était pas JSON, mais que la cause était ailleurs.
Lors de l'utilisation de l'intégration Proxy, le script __ semble devoir renvoyer une réponse dans un format particulier __. C'était une ligne de frappe que si vous ne suivez pas ce format, vous obtiendrez 502 sans aucune question.
Cliquez ici pour le format fixe.
main.py
def handle(event, context):
html = ...
return {
"statusCode": 200,
"headers": {"Content-Type": "text/html"},
"body": html
}
Il est nécessaire de renvoyer le dictionnaire qui définit trois des «statusCode», «headers» et «body» de la fonction appelée par Lambda. API Gateway les examine et crée une réponse HTTP.
De plus, toutes les informations lors d'une demande à API Gateway sont transmises à la fonction handle
ʻevent` (premier argument). Dans cet exemple, le type de valeur transmise est affiché par pprint, veuillez donc vous y référer si vous le souhaitez.
https://teu24wc5u9.execute-api.ap-northeast-1.amazonaws.com/jinja/ Le sanctuaire a été achevé avec succès. Je voulais faire de la page un peu plus un sanctuaire, mais j'étais épuisée car je n'avais pas le temps. Je suis content de vous avoir dit ce que je veux transmettre techniquement.
Pouvez-vous voir que le nombre d'adorateurs affichés augmente chaque fois qu'ils sont consultés? J'ai pu créer une page Web dynamique sans créer une seule instance.
Le chemin d'accès est
/jinja/
/jinja/hoge
/jinja/fuga
/jinja/piyopiyo
Tout sera accepté. Les informations de demande «chemin» au bas de la page doivent également être prises correctement. Avec cela, il est facile d'ajouter votre propre processus de routage et d'afficher différentes pages.
En raison des restrictions d'API Gateway, la partie / jinja /
est une chaîne de version et ne peut pas être supprimée.
Pour accéder par root, il semble bon de mettre CloudFront etc. devant API Gateway. Vous ne pouvez pas héberger des fichiers statiques avec API Gateway uniquement.
J'ai essayé de créer une page dynamique avec Lambda avec un départ assez proche, mais c'était bien de pouvoir le faire en toute sécurité. J'avais peur d'utiliser quelque chose pour l'API en tant que page Web à cause du nom API Gateway, mais en fin de compte, il est puissant que même un service Web à part entière puisse être utilisé avec Lambda + API Gateway. Je l'ai senti. Le seul inconvénient de Lambda est que vous ne pouvez utiliser que Python2 ... Veuillez soutenir 3 dès que possible: priez:
https://github.com/pistatium/lambda_jinja_sample La source pour cette fois est ici.
Notre organisation Qiita A été faite la dernière fois. Je voudrais faire de mon mieux pour écrire autre que AdventCalender.
Recommended Posts