tl;dr
- 管理ソースが多くなるにつれていちいちコンソールで編集やアップロードが面倒になったのでCIからデプロイで自動化したくなった
- LambdaへのデプロイをLambdaにやらせるのが手っ取り早そう
- CI(zip化してS3デプロイ) -> S3 -> イベントトリガーでLambda起動(デプロイ) -> Lambda関数の更新
用意するもの
- CI(よしなに)
- zip放置用のS3
- デプロイ実行用のLambda関数
- デプロイされるLambda関数
CI(よしなに)
- 好きなものをどうぞ
- ビルド -> zip化 -> S3までデプロイする感じで
import boto3
import glob
import os
import shutil
import mimetypes
from datetime import datetime
from datetime import timedelta
import traceback
import json
BUILD_DIR = "YOUR_BUILD_DIR"
LAMBDA_PROJECT_LIST_JSON = "./YOUR_PROJECT.json"
AWS_ACCESS_KEY = "YOUR_AWS_ACCESS_KEY"
AWS_ACCESS_SECRET = "YOUR_AWS_ACCESS_SECRET"
AWS_S3_BUCKET = "YOUR_AWS_S3_BUCKET"
AWS_REGION = "YOUR_AWS_REGION"
def run():
# YOUR_BUILD_DIRディレクトリ削除
# YOUR_BUILD_DIRディレクトリ作成
# zipファイル作ってYOUR_BUILD_DIRに突っ込む
# s3デプロイ
with open(LAMBDA_PROJECT_LIST_JSON,"r") as l:
lambda_project_list = json.load(l)
try:
if (AWS_ACCESS_KEY in os.environ)==False or (AWS_ACCESS_SECRET in os.environ)==False:
raise "undefined access_key"
except:
traceback.print_exception()
return
session = boto3.session.Session(
aws_access_key_id=os.environ[AWS_ACCESS_KEY],
aws_secret_access_key=os.environ[AWS_ACCESS_SECRET],
region_name=AWS_REGION,
)
client = session.client('s3')
shutil.rmtree(BUILD_DIR, ignore_errors=True)
os.makedirs(BUILD_DIR, exist_ok=True)
keys = lambda_project_list.keys()
for keyname in keys:
val = lambda_project_list[keyname]
shutil.make_archive(BUILD_DIR+"/"+val["lambda"], 'zip', root_dir="./"+keyname)
file_list = glob.glob(BUILD_DIR+"/*.zip")
now = datetime.today()
expires = now+timedelta(hours=1)
print("DEPLOY:"+AWS_REGION)
for val in file_list:
mimetype = mimetypes.guess_type(val)[0]
fileneme = os.path.basename(val)
with open(val,"rb") as f:
try:
response = client.put_object(
ACL='private',
Body=f,
Key=fileneme,
Bucket=AWS_S3_BUCKET,
ContentType=mimetype,
Expires=expires,
)
print("UPLOAD:"+fileneme)
except:
traceback.print_exception()
break
if __name__ == "__main__":
run()
ビルドははしょり(懺悔)subprocess使えばいいんじゃなかろうか(適当)
デプロイ実行用のLambda関数
IAMはよしなに付与しましょう
import sys
import boto3
import os
AWS_REGION = "YOUR_AWS_REGION"
def lambda_handler(event, context):
# s3に上がったzipを取得
# lambdaへデプロイ
if len(event["Records"])==0:
return
s3_data = event["Records"][0]["s3"]
_,ext = os.path.splitext(s3_data["object"]["key"])
# zip以外にアップロードされたものは除外
if ext != ".zip":
return
function_name = s3_data["object"]["key"].split(".")[0]
session = boto3.session.Session(
region_name=AWS_REGION,
)
client = session.client("lambda")
response = client.update_function_code(
FunctionName=function_name,
S3Bucket=s3_data["bucket"]["name"],
S3Key=s3_data["object"]["key"],
DryRun=False,
)
print(response,file=sys.stderr)
DryRun=False
は必須。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.update_function_code
DryRun (boolean) -- Set to true to validate the request parameters and access permissions without modifying the function code.
zip放置用のS3
- よしなに作成。
- リージョンは
デプロイ実行用のLambda関数
と合わせた方が楽。 - バケットの
プロパティ > Events
から PUTでデプロイ実行用のLambda関数
が起動するように設定
デプロイされるLambda関数
- よしなに指定。
- リージョンは合わせる
-
LAMBDA_PROJECT_LIST_JSON
に放り込んでいく
課題
- 雑に作ったのでビルドやってないので後日作る(といいなあ)
参考
https://dev.classmethod.jp/cloud/aws/2018-solo-boto3-advent-calendar-day14/
https://qiita.com/asahi0301/items/a88760dd38fe0f5fcee1