目的
こちらの記事は、以下の記事の第1, 2回目となります。
Lambdaを使用して、スクレイピングします。
また、Lambda Layerを使用して、Pythonで使用するパッケージを読み込ませます。インポートするパッケージをLambda Layerから読み込んでハンドラーと切り分けることで、デプロイするLambdaの容量を減らし、大規模なLambda関数を作成可能にするとともに、デプロイするまでの時間を短縮させます。
環境
$ sw_vers
ProductName: macOS
ProductVersion: 11.6
BuildVersion: 20G165
$ sls -v
Framework Core: 2.65.0
Plugin: 5.5.1
SDK: 4.3.0
Components: 3.17.2
$ npm -v
8.1.0
$ docker -v
Docker version 20.10.8, build 3967b7d
ディレクトリ構成
ディレクトリ構成は以下。
.
├── README.md
├── lambda
│ ├── handler.py
│ └── serverless.yml
├── layer
│ ├── requirements.txt
│ └── serverless.yml
└── package.json
ちなみに、ディレクトリ構成を他の人に共有したい時は、treeコマンドを実行すると良いことに気がつきました。-Iオプションをつけると、node_modules
とかの共有したくないディレクトリは排除してくれます。
Lambda Layerの作り方
(1). serverless
コマンドを実行し、適当なテンプレートで作成する。私はAWS - Python - Scheduled Task
を選択しました。
(2). layerディレクトリに移動し、serverless-python-requirementsをインストールする。npm i serverless-python-requirements
(3). Lambda Layerに入って欲しい、requirements.txt定義する。今回デプロイするLambdaには以下を定義しておく。
beautifulsoup4>=4.10.0
requests>=2.26.0
lxml>=4.6.4
(4). serverless.ymlを作り、以下のようにする。
service: python-requirements-layer
plugins:
- serverless-python-requirements
provider:
name: aws
runtime: python3.8
region: us-east-1
custom:
pythonRequirements:
dockerizePip: true
layer: true
resources:
Outputs:
PythonRequirementsLambdaLayerExport:
Value:
Ref: PythonRequirementsLambdaLayer
ポイントとしては、2つ。
- pythonRequirementsの箇所にdockerizePipとlayerを定義しておくこと。
- OutputsにPythonRequirementsLambdaLayerExportを定義しておくこと。
1では、dockerでパッケージ化したファイルをLambda Layerに入れることになる。結果として、一意なパッケージとなり、どこで実行しても同じパッケージになる。
2では、デプロイするLambdaからLambda Layerを読み込むためのCloudFormationへのOutputを定義している。次の章で使用する。
(5)sls deploy
する。
デプロイするコード
import datetime
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
import requests
import sys
sys.path.append("lib.bs4")
from bs4 import BeautifulSoup
target_url = 'https://www.yahoo.co.jp/'
def run(event, context):
current_time = datetime.datetime.now().time()
name = context.function_name
logger.info("Your cron function " + name + " ran at " + str(current_time))
r = requests.get(target_url)
soup = BeautifulSoup(r.text, 'lxml')
a_tag = soup.find('a')
logger.info(a_tag)
デプロイするserverless.yml
org: ShiroUz
app: aws-python-scheduled-cron-project
service: aws-python-scheduled-cron-project
frameworkVersion: '2'
provider:
name: aws
runtime: python3.8
logRetentionInDays: 1
iamRoleStatements:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- "*"
lambdaHashingVersion: 20201221
custom:
default_stage: dev
stage: ${opt:stage, self:custom.default_stage}
requirements_service: python-requirements-layer
requirements_export: PythonRequirementsLambdaLayerExport
requirements_layer: ${cf:${self:custom.requirements_service}-${self:custom.stage}.${self:custom.requirements_export}}
prune:
automatic: true
number: 5
functions:
cronHandler:
handler: handler.run
layers:
- ${self:custom.requirements_layer}
上記コードのポイントは以下の3つ。
- Lambda Layerをハンドラーで読み込む。
- IAMロールを設定する。
- pruneを設定する。
1について、customの中で、設定しているrequirements_layerを読み込んで、Lambda Layer化する。
2について、providerでIAMロールを定義して、ログの出力を有効化する。
3について、pruneを設定しておくことで、Lambdaの古いバージョンが残らなくなる。npm i serverless-prune-plugin
でインストールする。
上記、serverless.ymlとhandler.pyを適応させた状態で、sls deploy
することで、AWSにデプロイできる。
参考
以下、とっても参考にさせていただきました。ありがとうございます。
https://blog.ikedaosushi.com/entry/2019/04/07/012612