3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

レコチョクAdvent Calendar 2023

Day 18

AWS LambdaのCI・CD環境を構築してみた

Last updated at Posted at 2023-12-17

この記事は レコチョク Advent Calendar 2023 の18日目の記事となります。

はじめに

こんにちは、株式会社レコチョク新卒1年目エンジニアの笹野です。
サーバーサイドエンジニアとして、主にdヒッツというサービスに携わっています。

好きな音楽はK-POPとヴィジュアル系全般で、おすすめアーティストはENHYPENとΛrlequiΩ(アルルカン)です!
好きなAWSのサービスはLambdaで、プライベートで作成したAPIはよくLambdaに置いて使っています。

今回は、そんな大好きなLambdaの開発体験を向上させるべくCI・CD環境を構築してみました。

CI・CDとは?

  • CI(Continuous Integration)
    • CIとは継続的インテグレーションのことで、ビルドとテストを自動化します。
  • CD(Continuous DeliveryもしくはContinuous Deploy)
    • CDとは継続的デリバリーのことで、リリース作業を自動化します。

CI・CD環境を構築すると、生産性、開発速度、コード品質の向上といったたくさんの嬉しいことがあります。

今回使用するAWSについて

  • AWS Lambda
    • Lambdaは関数単位でコードを実行できるサービスであり、サーバレス環境で動きます。ちなみに内部的にはAWS側のサーバに実行用のコンテナを作成→そのコンテナで関数を実行→実行が終了してしばらく経った後に実行用のコンテナを削除という流れでサーバレスを実現しているそうです。
  • AWS CodeCommit
    • ソース管理サービスです。今回はLambda関数のGitリポジトリとして使います。
  • AWS CodeBuild
    • ソースコードのコンパイル、テスト、デプロイを自動化するサービスです。
  • AWS CodePipeline
    • デプロイまでの作業を可視化と自動化するサービスです。CodeCommitとCodeBuildを一連のプロセスとして管理してくれます。
  • Amazon Simple Storage Service (Amazon S3)
    • ストレージサービスです。今回はビルドしたパッケージファイルを一時保存する場所として使います。
  • AWS CloudFormation
    • AWSリソースを自動で構築するサービスです。Lambda関数の作成と更新をするために使います。

わかりやすい図

Pasted image 20231204014912.png

  1. CodeCommitにPushされたコードの変更をCodePipelineで検知
  2. CodeBuildでテストとビルド
  3. CloudFormationでLambdaにデプロイ

という流れになるよう構築していきます。

構築手順

  1. CodeCommitでリポジトリを作る
  2. CodePipelineを作成する
    • CodeBuildでCI環境を作る
    • CloudFormationでCD環境を作る

CodeCommitでリポジトリを作る

リポジトリを作る

まずはAWSコンソールで「CodeCommit」と検索し、リポジトリを作成します。
適宜リポジトリ名を入力し、作成ボタンを押下でリポジトリの作成は完了です!
Pasted image 20231204052846.png

リポジトリをクローンする

クローンするには、Git認証情報が必要なのでIAMで設定していきます。
AWSコンソールで「IAM」と検索し、現在ログインしているユーザを選択します。
セキュリティ認証情報を開き、認証情報を生成ボタンを押下するとクローンに必要なGit認証情報が作成されます。
Pasted image 20231128122950.png
表示されたユーザ名とパスワードは忘れずダウンロードするかメモっておきましょう。

そして、接続のステップに表示されているクローンコマンドを実行します。
Pasted image 20231205112750.png

git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/test-sasano-lambda-cicd-rep

適宜Git認証情報を入力し、リポジトリのクローンは完了です!

CodePipelineを作る

作成したリポジトリを絡めて、CodePipelineを作成していきます。
AWSコンソールで「CodePipeline」と検索し、パイプラインを作成します。
パイプライン名を入力し、パイプラインタイプは一旦V1を選択してください(あとから変更可)。そして、今回は新しいサービスロールを作成します。
Pasted image 20231204054834.png

次に、ソースプロバイダーはCodeCommitを選択し、リポジトリ名には作成したリポジトリ名を入力してください。
Pasted image 20231204054910.png

CodeBuildでCI環境を作る

先程の画面で次へを押下するとビルドステージの追加ステップに移ります。
プロバイダーはCodeBuildを選択します。そして、プロジェクトを作成するを押下し、CodeBuildを作っていきます。
Pasted image 20231204032000.png

CodeBuildを作る

適宜、好きなプロジェクト名を入力してください。
Pasted image 20231204055008.png

次に環境はLambdaを選択し、作成するLambdaの環境を選択してください。
今回はPython3.11x86_64のLambdaを作成します。ここでも新しいサービスロールを作成します。
Pasted image 20231204055106.png

buildspecファイルを使用するを選択して、CodeBuildの作成は完了です。
Pasted image 20231204055130.png

CodePipelineの作成に戻りますが、一旦デプロイの設定はスキップし、CodePipelineを作っちゃいます。

CodePipelineが動きますが、一度もリポジトリにPushしていないのでSourceは失敗でOKです。
Pasted image 20231204055345.png

Lambda関数を作る

メインとなるソースコードを準備します。
今回は渡された2つの数値の合計を返す関数とそのテストをPythonで簡単に作りました。

lambda_function.py
def lambda_handler(event, context):

	return {
		"result": (event["first_num"] + event["second_num"])
	}
test_lambda.py
import pytest
from lambda_function import lambda_handler

def test_lambda_handler():
	event = {
		"first_num": 3,
		"second_num": 2
	}

	result = lambda_handler(event, {})
	assert (result["result"] == 5)

buildspec.ymlを作る

CodeBuildでビルドするために、buildspecを作成します。

buildspec.yml
version: 0.2

phases:
	install:
		runtime-versions:
			python: 3.11
		commands:
			- pip install pytest

	pre_build:
		commands:
			- python -m pytest test_lambda.py

	build:
		commands:
			- sam package --template-file template.yml --s3-bucket codepipeline-ap-northeast-1-621537184721 --output-template-file package.yml
	
	artifacts:
		files:
			- package.yml

installでは使用するライブラリをインストールします。もちろんrequirements.txtを使ったインストールもできます。
pre_buildではテストを実行します。テストが通らなかった場合、ちゃんとビルド作業が止まります。
buildではsam packageコマンドとtemplate.ymlを使ってパッケージングしたものをS3に保存します。指定するS3はCodePipelineの作成と同時に作られたバケットでも良いです。その場合、バケットポリシーで暗号化されていないオブジェクトのアップロードを拒否する権限を削除する必要があることに気をつけてください。

template.yml
AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Resources:
	Function:
		Type: "AWS::Serverless::Function"
		Properties:
			FunctionName: calcSum
			Handler: lambda_function.lambda_handler
			Runtime: python3.11
			CodeUri: .

このテンプレートは、calcSumというLambdaを作成(すでに存在していれば更新)するテンプレートになっています。Python3.11をランタイムとし、ルートディレクトリにあるlambda_functionファイルのlambda_handler関数のLambdaを作るというものです。

これらファイルたちをPushしてみましょう。
Pasted image 20231204060443.png

無事にビルドフェーズまで成功しました!

CloudFormationでCD環境を作る

作成したパイプラインを編集してデプロイフェーズを追加していきます。
まず、編集するボタンを押下して編集画面を開きます。
Pasted image 20231204060630.png

次にBuildの下のステージを追加するボタンを押下します。
Pasted image 20231204060836.png

ステージ名はDeployにしましょう。
Pasted image 20231204060907.png

無事にDeployステージが追加されました。
次に、アクショングループを追加するボタンを押下…と行きたいところですが、
その前にCloudFormation用のロールを新たに作成しておきましょう。
IAMからロールを作成します。サービスはCloudFormationを選択します。
Pasted image 20231204061406.png

取り急ぎ、CloudFormationのFullAccess権限をアタッチします。
Pasted image 20231204061548.png

それに加え、下記の操作も許可してください。

iam:CreateRole
iam:DetachRolePolicy
iam:DeleteRole
iam:AttachRolePolicy
iam:GetRole
iam:PassRole
lambda:GetFunction
lambda:CreateFunction
lambda:DeleteFunction
lambda:TagResource
lambda:UpdateFunctionCode
lambda:ListTags
s3:GetObject

これらはLambdaのデプロイに必要な操作になるため許可が必要です。

適宜ロール名を入力し、CloudFormation用のポリシーは完成です!
Pasted image 20231204061519.png

CloudFormation用のポリシーができたところで、アクショングループを追加していきます。
Pasted image 20231204061011.png

まずは変更セットを作成または更新するアクションを追加します。
アクション名をCreateUpdateChangeSetとし、アクションプロバイダーはCloudFormationを選択、入力アーティファクトはBuildArtifactを選択します。
Pasted image 20231204062135.png

アクションモードは変更セットを選択または交換するを選択し、適宜スタック名とセット名を入力します。テンプレートはBuildArtifactのpackage.ymlを選択します。そして、このアクションはIAMリソースの作成があり得るのでCAPABILITY_IAMを追加します。ロールは先程作成したCloudFormation用のロールを選択します。
Pasted image 20231204062124.png

できた変更セットを実行するため、もう一つアクションを追加します。
アクション名はExecuteChangeSetとし、アクションプロバイダーはCloudFormationを選択します。入力アーティファクトはBuildArtifactを選択し、アクションモードは変更セットを実行するを選択します。
Pasted image 20231204062240.png

これで一連の流れが出来上がりました!パイプラインの変更をリリースするボタンを押下して動きを確かめてみましょう。
Pasted image 20231204062312.png

無事、デプロイまで成功しました!
Pasted image 20231204062543.png

Lambdaを見てみると新たにLambda関数が作成されていることが確認できます。

では、試しにPythonのコードを下記に変更してPushしてみましょう。(ステータスコードを追加しています)

lambda_function.py
def lambda_handler(event, context):

    return {
        "statusCode": 200,
        "result": (event["first_num"] + event["second_num"])
    }

Push後、無事にPipelineの流れはすべて成功し、Lambdaのコードが更新されていることまで確認できました!
Pasted image 20231204063610.png

これでLambdaのCI・CD環境は完成です!

おわりに

本記事ではLambdaのCI・CD環境を構築しました。
サーバレスのCI・CD環境といっても、特別な工程が必要になったりせず、シンプルな構成でCI・CDを実現できました。今後はLambda関数のデプロイを検証環境と本番環境とで分けたり、API Gatewayと絡めたりしてみたいと思いました。これらについてはtemplate.ymlの追記でなんとかなりそうな気がしたので、これから試しつつ作ってみよう思います。

最後まで読んでいただきありがとうございました!

明日のレコチョク Advent Calendar 2023は19日目 「バイナリを読みながらJPEG画像が壊れた原因を探る」となります。お楽しみに!

参考文献

以下の情報を参考にさせていただきました!


この記事はレコチョクのエンジニアブログの記事を転載したものとなります。

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?