Lambda上に適当に置いてあったコードをちゃんと管理する(個人開発)
この記事はPython Advent Calendar 2022の17日目の記事です。
2019年に Lambda へデプロイした Python コードが今日まで動いていますが、これが何も管理されていなかったので、そろそろ重い腰を上げてちゃんとやっていこうと思います。
アプリケーションの説明
Twitterで自分の名前の後ろに、東京都の天気予報の結果を表示します。これは1時間毎に自動更新されます。
やること
1. コード管理
(なし) -> Git & GitHub
今動いているコードが何も管理されておらず、なお且つ、開発をしていたPCがお亡くなりになったので、ローカル環境にコードがない状況です。
とりあえず、 Lambda 上にデプロイされたコードが有るので、こちらを DL して Git と GitHub でコード管理を行うようにします。
2. パッケージ管理
(なし) -> Pipenv
おそらく pip で管理されていたはずでしたが、ソースコードのデプロイ時(デプロイ用のzip作成時)にrequirements.txt
入れてなかったため、何も管理がされていない状態になっていました。
今回は pip ではなくPipenvを利用します。
3. インフラ管理
コンソール -> Serverless Framework
Lambda は CloudWatch Events からの定期実行になっています。
構成はとてもシンプルなサーバーレスアーキテクチャとなっているので、IaC化する上でサーバーレスアーキテクチャに特化した Serverless Framework を採用しました。
Git & GitHub の初期設定
まずはコードの置き場所となるディレクトリと、 GitHub 上のリポジトリを作成します。
mkdir twitter-username-weather/
cd twitter-username-weather/
GitHubでリポジトリを作って、いつものコードをコピペします。
echo "# twitter-username-weather" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:your-user-name/twitter-username-weather.git
git push -u origin main
Serverless Framework のセットアップ
Serverless Framework でアプリケーションの管理をするので、aws-python3で作成します。
serverless create --template aws-python3 --name twitter-username-weather
すると、以下のようにファイルが自動生成されます。
.
├── .git/
├── .npmignore
├── handler.py
└── serverless.yml
自動生成されたserverless.yml
からちょっと設定を変えて、ランタイムをLambdaで利用可能な最新バージョンにあげ、リージョンを東京にします。
- runtime: python3.8
- # region: us-east-1
+ runtime: python3.9
+ region: ap-northeast-1
そして、Pythonで外部ライブラリを利用するため、 Serverless Framework でもプラグインを使います。
sls plugin install -n serverless-python-requirements
sls deploy
を実行して、東京リージョンにLambdaアプリケーションが追加されていればOK。
コードのコピー
これまで管理されていなかったコードを Git で管理し、 GitHub で公開するにあたり、まずはAPIキーなどがコードにハードコードされていないか確認します。
もし、ハードコードされていたら、必ず環境変数から取ってくるように書き換えます。
os.environ.get("OPEN_WEATHER_MAP_API_KEY")
環境変数は.env
ファイルに書き込むことで、 Serverless Framework から Lambda の環境変数として設定することが出来ます。
.env
ファイルから環境変数を読み込む場合は、useDotenv
をtrue
にすることで${env:OPEN_WEATHER_MAP_API_KEY}
のように環境変数へアクセスできるようになります。
そして、各関数の中のenvironment:
の下に環境変数を書くことで、デプロイ時に Lambda 関数へ環境変数が設定されます。
+ useDotenv: true
...
functions:
hello:
handler: handler.hello
+ environment:
+ OPEN_WEATHER_MAP_API_KEY: ${env:OPEN_WEATHER_MAP_API_KEY}
...
また、コピペするとハンドラーとなる関数名がhello
ではなくなるかと思います。その時はserverless.yaml
を書き換えます。
- handler: handler.hello
+ handler: handler.lambda_handler
実行環境のセットアップ
Lambdaのランタイムと合わせて Python 3.9 の実行環境を用意します。ここでは Pipenv を利用します。
pipenv --python 3.9
次に外部ライブラリを入れます。
今回のコードではRequestsとrequests-oauthlibのライブラリを使っているので、これらをインストールします。
pipenv install requests requests-oauthlib
これで動作環境が整備されました。とりあえずローカル環境で試してみます。if __name__ == '__main__':
でlambda_handler
から呼び出される関数をprintしてみます。
if __name__ == '__main__':
w = get_weather()
name = get_user_name()
print(name, w)
pipenv でこの Python ファイルを実行します。この時.env
ファイルは自動で読み込まれます。
pipenv run python ./handler.py
これで適当な情報がprintされればOKです。そうしたらLambdaへデプロイします。
sls deploy
無事デプロイされたらコンソールからテストを実行します。入力データは不要です。
各設定に問題がなければ、以下の様なResponseが返ってきて、Twitterの自分のアカウント名が変わっているかと思います。(最近のTwitter Blueの話はわからないです。)
定期実行の設定
Lambdaの動作確認できたので、これを定期実行するようにします。1時間に1回実行されうようにするのでserverless.yaml
へ cron を設定します。
functions:
main:
handler: handler.lambda_handler
environment:
OPEN_WEATHER_MAP_API_KEY: ${env:OPEN_WEATHER_MAP_API_KEY}
TWITTER_AS: ${env:TWITTER_AS}
TWITTER_AT: ${env:TWITTER_AT}
TWITTER_CK: ${env:TWITTER_CK}
TWITTER_CS: ${env:TWITTER_CS}
+ events:
+ - schedule: cron(0 * * * ? *)
これで、毎時0分のときに定期実行され、天気が変わればデプロイ完了です。
後片付け
まず Lambda 関数を定期実行している EventBrige を削除して、最後に Lambda 関数そのものを削除します。
もともと CloudFormation で管理されているわけではないですが、この2つしか使われているサービスがなかったので、これですべて完了です。お疲れさまでした!
完成したコード
注意 Pipenv のバージョンについて
これまで serverless-python-requirements で Pipenv の requirements を取得する時、内部的にはpipenv lock --requirements
を実行していたようですが、これが deprecated となり、削除されたようです。
serverless-python-requirements は6.0.0のリリースでこの問題に対応しました。そのため、上の記事で紹介されているようなpip install pipenv==2022.8.5
をする必要はなくなりました。
しかし、今回のリリースは破壊的な修正となったため、逆に古いバージョンの Pipenv は使えなくなりました。
もし、古いバージョンの pipenv を利用していて、特別な理由がなければ普通にバージョンアップしたほうが良いです。
python3 -m pip install --upgrade pipenv
Discussion