0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWSの無料期間が終了するのでEC2からlambdaに移行した

Last updated at Posted at 2022-11-20

EC2の無料期間が終了してしまう(まずい)

AWSのEC2を使って、アニメの配信通知をつぶやくTwitterボットを動かしているのですが、私のアカウントのAWS無料期間が2022年12月で終わってしまうため、その後は毎月約3000円の料金が発生してしまいます(もったいない!)。
費用圧縮のためにLambdaに移行しようと作業していた所、つまづいた箇所がいくつかありました。
同じようなことで困っている方の参考になればと思います。

lambda(ラムダ)で出来ること

Lambda は必要に応じて関数を実行し、1 日あたり数個から 1 秒あたり数千個のリクエストまで自動的にスケーリングします。課金は実際に消費したコンピューティング時間に対してのみ発生します。コードが実行されていない場合、料金は発生しません。

引用元:Amazon

1) フォルダごと圧縮しても動かない

lambdaでは、プログラムを「lambda_function.py」という名前で作り、圧縮・アップロードして利用します。
しかし、pythonファイルが入っているフォルダをそのまま圧縮しても動いてはくれません。
スクリーンショット 2022-11-20 17.55.51.png

スクリーンショット 2022-11-20 17.55.30.png

エラー内容

"errorMessage": "Unable to import module 'lambda_function': No module named 'lambda_function'",

ターミナルで「lambda_function.py」が置いてあるフォルダまで移動してから、以下のコマンドで圧縮してやる必要があります。

zip -r lambda_function.zip ./*

2) パッケージの追加が必要

圧縮ファイルをアップロードし、実行しようとすると

No module named ‘*****’

というエラーで失敗しました。
パッケージを組み込む必要があります。

パッケージ追加方法その1. ARN

lambdaの関数の画面の下の方に移動すると、「レイヤーの追加」というボタンがあるので、そちらを押します。
スクリーンショット 2022-11-20 18.07.38.png

レイヤーソース欄で「ARNを指定」を選択します。
スクリーンショット 2022-11-20 18.09.05.png

「ARNを指定」の行には、エラー画面で求められたパッケージのARNをこちらから探して入力します。
※自分のPythonバージョンとAWSリージョンを選択。
スクリーンショット 2022-11-20 18.13.01.png

パッケージ追加方法その2. フォルダ内に保存

利用したいパッケージが上記URLにない場合、パッケージを「lambda_function.py」と同じフォルダに保存してから、圧縮 → アップロードしてやる必要があります。
「パッケージ名 ダウンロード」などで検索してソースを拾ってきます。
スクリーンショット 2022-11-20 18.18.22.png

3) IAMでS3読み書き権限の追加が必要

設定情報CSVファイルの置き場として、AWSのS3を利用します。
lambdaからS3を利用するには、読み書きの権限をIAMで設定する必要があります。

1. IAM管理画面からポリシーを作成

以下のような内容でポリシーを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": [
                "arn:aws:s3:::*****(S3のバケット名)"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::*****(S3のバケット名)/*"
            ]
        }
    ]
}

2. lambdaの設定画面からロールを開く

スクリーンショット 2022-11-20 18.31.00.png
ロール名のリンクをクリック。

3. ポリシーをアタッチ

スクリーンショット 2022-11-20 18.32.41.png
IAMで作成したポリシーを追加します。

4) datetimeの比較ができない

lambdaではタイムゾーンを日本時間に固定できないようです。
「pytz.timezone('Asia/Tokyo')」を使うことにしました。

import datetime
import pytz
dt_now = datetime.datetime.now(pytz.timezone('Asia/Tokyo'))

すると、EC2では動いていた日時の比較がエラーを出すようになってしまいました。

TypeError: can't compare offset-naive and offset-aware datetimes

これまでタイムゾーン情報を付加していなかった変数を以下のように変更しました。

dateFormatter = "%Y-%m-%d %H:%M%z"
progDateTime = datetime.datetime.strptime(YMD +" "+ HourMin + "+09:00", dateFormatter) 

これで、

if  dt_now >= progDateTime

が動くようになりました。

5) tmpフォルダへの保存が必要

pandasモジュールのpd.read_csvで、S3のCSVを直接読み込むことはできませんでした(何か方法はあるかもしれませんが)。
そこで、CSVファイルをlambdaの一時フォルダに保存してから、pd.read_csvを使います。

import pandas as pd
import boto3

def lambda_handler(event, context):

    # S3からCSV読み込み
    s3 = boto3.resource('s3')
    response = s3.Object(bucket_name, savepath).get()
    body = response['Body'].read()
    decodedBody = body.decode(encoding)
    
    # 一時ファイルの生成
    tmpfilename = "/tmp/" + 'TWBot_' + str(time_now) + '.csv'
    with open(tmpfilename, "w") as f:
        f.write(decodedBody)

    # read_csvでCSV読み込み
    arr = pd.read_csv(tmpfilename)

    ### なんやかんや処理

    # 変更した一時ファイルをS3にアップロード
    s3.meta.client.upload_file(tmpfilename, bucket_name, savepath)

    # 一時ファイル削除
    os.remove(tmpfilename)

6) タイムアウトしてしまう

初期設定の3秒だとタイムアウトエラーになることが多かったので、10秒に変更したら動くようになりました。
スクリーンショット 2022-11-20 18.50.45.png
lambdaの設定画面、一般タブ ⇨ 「編集」ボタンをクリック。

スクリーンショット 2022-11-20 18.51.53.png
「タイムアウト」の秒数を変更して「保存」。

7) トリガーのcronの書き方がEC2と違う

定時実行するために「トリガー」を関数に追加してやります。
この時のcron式の書き方がEC2のcronbtabとは少し異なりました。

EC2の場合(毎時0分に実行)

0 * * * * /usr/bin/python3 /home/ec2-user/*****.py

lambdaのトリガーの場合(毎時0分に実行)

0 * * * ? *

cron(Minutes Hours Day-of-month Month Day-of-week Year)
というAmazonの説明の通り、
左から3番目が日付、左から5番目が曜日になります。
この2つのどちらかをハテナに設定する必要があります。

8) トリガーで実行したログの見方

トリガーで実行した結果は、lambdaの関数の画面から「モニタリング」タブ → 「CloudWatchのログを表示」から確認可能です。
スクリーンショット 2022-11-20 19.01.13.png

スクリーンショット 2022-11-20 19.02.36.png
「ログストリーム」に各時間の実行結果へのリンクがあります。

以上です。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?