以前にFastAPI+lambdaで機械学習推論APIを作成しました。
ここでは、中身の修正があると、毎回手作業でECRへのpush、およびlambda関数の更新を行う必要があり手間でした。
今回は、AWSのcodepiplineとgithubを使用し、最小限のCI/CD環境を構築したので、その方法をまとめておきます。
今回のコードレポジトリ GitHub - koy0208/lambda-cicd
役に立つ人
- lambda関数をECRにあるdocker-imageから作成しており(以下docker-lambdaとする)、CI/CDパイプラインがない方
最終形態
最終的な構成とリポジトリ構造は以下のようになります。
├── Dockerfile ├── README.md ├── app │ └── app.py ├── buildspec.yml └── requirements.txt
下準備
今回は、すでに作成ずみのdocker-lambdaを自動更新することを想定しているため、下記作業の詳細は割愛します。
githubレポジトリ作成
lambda関数およびdockerファイルなどを置いておく。
ECRレポジトリの作成とイメージのpush
dockerイメージを格納するためのレポジトリを作成する。作成後に表示されるプッシュコマンドを参考に、イメージをプッシュする。今回はlambda-cicd
という名前で作成
docker-lambda作成
ECRのdockerイメージからlambdaを作成する。testを実行し、正常に動作するか確認する。今回はcicd-test
という名前でシンプルなlambda関数を使用する。
import json def lambda_handler(event, context): return {"statusCode": 200, "body": json.dumps("Hello from Lambda!!")}
テストの実行結果は以下のとおり
buildspec.ymlファイルの設定
ここからcodepipelineの設定に入っていきます。
buildspec.yml
とは、codepipeline実行時の動作仕様を決めるものです。ここでは、ECRへのdockerイメージpush、およびlambdaの更新を行うように記述しています。
version: 0.2 phases: pre_build: commands: - echo Logging in to Amazon ECR... - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com build: commands: - echo Build started on `date` - echo Building the Docker image... - IMAGE_TAG=$(date "+%Y-%m%d-%H%M%S") - echo IMAGE_TAG is $IMAGE_TAG - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG . - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - echo Build completed on `date` - echo Pushing the Docker image... - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG - echo Remove latest Tag from Current Docker image... - aws ecr batch-delete-image --repository-name $IMAGE_REPO_NAME --image-ids imageTag=latest - echo Set latest Tag To New Docker image... - MANIFEST=$(aws ecr batch-get-image --repository-name $IMAGE_REPO_NAME --image-ids imageTag=$IMAGE_TAG --query images[].imageManifest --output text) - aws ecr put-image --repository-name $IMAGE_REPO_NAME --image-tag latest --image-manifest "$MANIFEST" - aws lambda update-function-code --function-name $LAMBDA_FUNC_NAME --image-uri $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
CodePipelineの作成
AWSのコンソール画面から、CodePipelineを作成していきましょう。今回は、lambda-cicdという名前にします。
次にソースの選択です。今回はgithub(バージョン2)を選択し、対象のレポジトリとブランチ名を選択ます。初期は、Githubとの接続設定がいるので、画面の指示にしたがって進めてください。
最後はビルドステージの設定です。ここで、新たなビルドプロジェクトを作成していきます。
環境は事前に作成してあるECRイメージを選択します。 また、特権付与にはチェックをいれてください。これがないと、dockerを使うことができなくなります。ビルドプロジェクトを作成したら、codepipeline作成に戻ります。
設定の最後にbuildspec.yml
内で使用する環境変数を指定します。これでcodepipeline設定は完了です。
IAMの設定
デフォルトでは、権限が不足しているため、ECRの更新とlambdaの更新が行えるように権限を追加します。 作成されたロールのpolicyを直接編集すると、エラーがでてしまうため、インラインポリシーで権限付与しています。
policyの中身は以下のとおりです。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:BatchGetImage", "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload", "ecr:PutImage", "ecr:GetRepositoryPolicy", "ecr:DescribeRepositories", "ecr:ListImages", "ecr:DescribeImages", "ecr:BatchDeleteImage" ], "Resource": "*" } ] }
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": [ "lambda:UpdateFunctionCode" ], "Resource": "*" } ] }
パイプラインを実行
さて、これで準備が整いました。lambda関数の中身を以下のように修正し、コードをpushしてみます。
import json def lambda_handler(event, context): return {"statusCode": 200, "body": json.dumps("Hello from Update Lambda!!")}
すると、githubの変更を検知し、codepipelineが動き出します。(わくわく)
パイプラインが完了したら、もう一度lambdaのテストしてみます。
メッセージが、Hello from Lambda!
から、Hello from Update Lambda!!
に変わってますね!うまくlambdaが更新されたようです。
まとめ
今回は最小構造で、lambda更新のCI/CD環境を作ってみました。さらなる展望として、lambdaやECRの作成にCloudformationを使うと、保守運用しやすいのですが、それは今後の課題
codepipelineを使うと、CI/CD環境を簡単につくれるので、活用していきたいですね。
※本記事は筆者が個人的に学んだこと感じたことをまとめた記事になります。所属する組織の意見・見解とは無関係です。
参考
CodePipelineのソースにGitHubのリポジトリを利用する方法@CloudFormation
GitHub に push したら AWS Lambda が更新されるようにする
チュートリアル:Amazon ECS による標準デプロイ CodePipeline - AWS CodePipeline