概要
この記事では、AWS のサービスを利用したサーバーレス API の開発を示し、AWS 環境内で継続的インテグレーション/継続的デプロイメント (CICD) パイプラインを確立します。
パート 1: API ゲートウェイからのリクエストを処理し、サーバーレス アプリケーション モデルを使用してデータを DynamoDB に保存する Lambda 関数の作成について説明します。
パート 2: AWS で CodeCommit リポジトリを設定し、リポジトリへの新しい変更の送信時にビルド プロセスを自動的に開始する CICD パイプラインを設定するために必要な手順を詳しく説明します。
前提条件
このプロジェクトには、AWS アカウントが必要です (無料利用枠で十分です)。次の AWS コンポーネントが使用されます。
- AWS APIゲートウェイ
- AWSラムダ
- AWSダイナモDB
- AWS コードコミット
- AWS コードビルド
- AWS コードパイプライン
- AWS S3
- その他 - CloudWatch、IAM など
ローカル開発環境が次のように設定されていることを確認してください。
AWS CLI をインストールする:ここのガイドに従って、AWS コマンドライン インターフェイスをインストールします。
AWS SAM (サーバーレス アプリケーション モデル) のインストール: ここの手順に従って SAM CLI をインストールします。
IDE を選択する: 開発には IntelliJ または同様の IDE を使用します。私はIntelliJの方が好きです
パッケージ化用の Maven : アプリケーションをパッケージ化するために Maven がインストールされていることを確認してください。
オプション: Docker (Lambda 関数をローカルでテストする必要がある場合): Lambda 関数をローカルでテストする予定がある場合は、Docker をインストールします。
これらのツールとコンポーネントがプロジェクトの基礎を形成します。
パート 1: 開発
このセクションでは、ハンドラー クラスの完成、構築、AWS へのデプロイ、Postman を使用したテストの実施など、AWS SAM を使用してスターター プロジェクトを作成するプロセスについて説明します。
環境設定
AWS のセットアップ:
https://aws.amazon.com/console/の AWS コンソールに移動し、管理者ユーザーの認証情報を使用してログインします。
- IAM でユーザーを作成します。
- IAM で、ローカル開発および CLI/SAM の使用専用のユーザーを作成します。
- DynamoDB テーブルを作成します。
- 名前: "users"、主キー: "id" (タイプ: 文字列)
- IAM でユーザーを作成します。
ローカルマシンで AWS CLI を設定します。
- ターミナルを開いて
$ aws configure
を実行します - 以前に作成した IAM ユーザーのアクセス キーとその他のデフォルト値を指定します。
- ターミナルを開いて
AWS サーバーレス アプリケーション モデル (SAM) を使用してプロジェクトを初期化します。
- ターミナルを開いて
$ sam init
を実行します - AWS クイック スタート テンプレートを選択します。
- 「Hello World」の例を選択します。
- Java 11 または 17、パッケージ タイプを zip として選択し、依存関係マネージャーとして Maven を使用します。
- CloudWatch と XRay を使用してログ記録とモニタリングを有効にします。
- ターミナルを開いて
プロジェクトの名前を変更する: プロジェクトの名前を好みの名前に変更します。
IntelliJ でプロジェクトを開く: IntelliJ を起動し、プロジェクトを開きます。
依存関係を pom.xml に追加します。
必要な依存関係を
pom.xml
ファイルに追加します。他の依存関係は SAM によって自動的に組み込まれるため、DynamoDB を追加するだけで済みます。<dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-events</artifactId> <version>3.11.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-dynamodb</artifactId> <version>1.12.573</version> </dependency> </dependencies>
ハンドラークラスを書く
lambda 関数の場合、sam によって自動的に生成されたハンドラー クラスを編集し、次のコードを追加します。これは単純なコードですが、実際のプロジェクトでは、よりモジュール化されたコードを使用することもできます。
public class UserRequestHandler implements RequestHandler<Map<String,String>, Map<String,String>> { private AmazonDynamoDB amazonDynamoDB; private String DYNAMODB_TABLE_NAME = "users"; private Regions REGION = Regions.US_EAST_1; @Override public Map<String,String> handleRequest(Map<String,String> input, Context context) { this.initDynamoDbClient(); LambdaLogger logger = context.getLogger(); logger.log("Input payload:" + input.toString()); String userId = UUID.randomUUID().toString(); String firstName= input.get("firstName"); String lastName= input.get("lastName"); Map<String, AttributeValue> attributesMap = new HashMap<>(); attributesMap.put("id", new AttributeValue(userId)); attributesMap.put("firstName", new AttributeValue(firstName)); attributesMap.put("lastName", new AttributeValue(lastName)); logger.log(attributesMap.toString()); amazonDynamoDB.putItem(DYNAMODB_TABLE_NAME, attributesMap); Map<String, String> response = new HashMap<>(); response.put("id", userId); response.put("firstName", firstName); response.put("lastName", lastName); return response; } private void initDynamoDbClient() { this.amazonDynamoDB = AmazonDynamoDBClientBuilder.standard() .withRegion(REGION) .build(); } }
SAM テンプレート ファイルを更新する
SAM テンプレート ファイルは、AWS への変更を構築してデプロイする際に重要な役割を果たします。プロジェクトのファイルを更新します。このファイル内で注目すべき重要な要素は、Lambda 関数名と API Gateway エンドポイントです。これらはサーバーレス アプリケーションの機能の中心となります。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > pc-aws-user-api Sample SAM Template for pc-aws-user-api # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 20 MemorySize: 128 Tracing: Active Api: TracingEnabled: true Resources: UserRequestHandlerLambdaFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: PcAwsUsersApi Handler: com.pc.aws.users.UserRequestHandler::handleRequest Runtime: java11 Architectures: - x86_64 MemorySize: 512 Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object Variables: PARAM1: VALUE JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1 # More info about tiered compilation https://aws.amazon.com/blogs/compute/optimizing-aws-lambda-function-performance-for-java/ Events: PcUsers: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /users Method: post ApplicationResourceGroup: Type: AWS::ResourceGroups::Group Properties: Name: Fn::Sub: ApplicationInsights-SAM-${AWS::StackName} ResourceQuery: Type: CLOUDFORMATION_STACK_1_0 ApplicationInsightsMonitoring: Type: AWS::ApplicationInsights::Application Properties: ResourceGroupName: Ref: ApplicationResourceGroup AutoConfigurationEnabled: 'true' Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api PcAwsUsersApi: Description: API Gateway endpoint URL for Prod stage Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/users/" UserRequestHandlerLambdaFunction: Description: Lambda Function ARN Value: !GetAtt UserRequestHandlerLambdaFunction.Arn UserRequestHandlerLambdaFunctionIamRole: Description: Implicit IAM Role created Value: !GetAtt UserRequestHandlerLambdaFunctionRole.Arn
SAM を使用したコードのビルドとデプロイ
IntelliJ でターミナルを開き、次のコマンドを実行します。
$ sam build
$ sam deploy –guided
プロンプトが表示されたら、スタック名として「PcAwsUsersApi」を入力し、デフォルトのオプションを選択します。
出力には、作成された CloudFormation スタックが表示され、API ゲートウェイ エンドポイントも提供されます。
APIをテストする
API をテストする前に、SAM によって作成された Lambda ロールへの DynamoDB アクセスを許可します。
- AWS コンソールで Lambda 関数を開きます。
- 「権限」に移動し、ロール名を見つけます。
- このロールに「DynamoDBFullAccess」権限を追加します。
このステップにより、Lambda 関数が DynamoDB と対話するために必要な権限を持っていることが保証されます。
API Gateway に移動し、次の手順に従ってサービスの URL を取得します。
AWS コンソールで API ゲートウェイに移動します。
API を選択します。
左側のサイドバーで「ステージ」をクリックします。
「ステージ」で「本番」ステージを選択します。
Stage Editor セクションに「Invoke URL」があります。この URL をコピーします。
- Postman アプリケーションを起動します。
- POST リクエストの作成: 次の詳細を使用して新しいリクエストを設定します。
- メソッド: POST
- URL: 先ほど取得した API Gateway エンドポイント URL を貼り付けます。
- ヘッダーの設定: 必要なヘッダーを追加します (例:
Content-Type: application/json
)。
- リクエスト本文の追加: リクエストで送信するユーザー データを表す JSON オブジェクトを作成します。これは、DynamoDB に保存されることが予想されるデータになります。
パート II CICD パイプラインの実装
このセクションでは、AWS CodeCommit、CodeBuild、CodePipeline を使用して CICD パイプラインを構築する方法を説明します。パイプラインは、リポジトリからコードを取得し、ビルド ファイルを使用してコードをビルドし、CloudFormation をトリガーしてスタックを作成するビルド プロセスを開始します。
CodeCommit リポジトリの作成
AWS にログインし、CodeCommit サービスを検索します。
AWS CodeCommit で新しいリポジトリを作成し、プロジェクトのソースコードを保存します。
コードをリポジトリにコミット
IntelliJ でターミナルを開き、次のコマンドを入力して、手順 I で作成したコードをコミットします。
$ git init → This initialize local git $ git add . → This will stage files $ git commit -m "commit to CodeCommit"
変更をリモート リポジトリにプッシュする
aws コンソールから CodeCommit リポジトリ URL をコピーします。
$ git remote add origin <repo URL> $ git push --set-upstream origin master --> This will prompt for user/password
AWS CodeBuild プロジェクトを作成する
アプリケーションの構築方法を指定する CodeBuild プロジェクトを設定します。これには、ビルド環境、ビルド コマンド、依存関係の定義が含まれます。
- ビルド ファイルを保存するための S3 バケットを作成します。
- AWS Code Build を検索し、新しいプロジェクトを作成し、コードのソースとして CodeCommit を提供し、アーティファクト ストレージとして S3 を提供します。
CodeBuild を設定するには、プロジェクト ディレクトリにbuildspec.yml
という名前のビルド仕様ファイルを作成する必要があります。このファイルには、CodeBuild のビルド コマンドと手順が含まれます。
buildspec.yml
ファイルの作成に関する詳細な手順については、こちらの公式ドキュメントを参照してください。
version: 0.2 phases: install: runtime-versions: java: corretto11 pre_build: commands: - echo Nothing to do in the pre_build phase... build: commands: - echo Build started on `date` - sam build - sam package --output-template-file pcoutputtemplate.yaml --s3-bucket com-appsdev-pc-001 post_build: commands: - echo Build completed on `date` artifacts: files: - pcoutputtemplate.yaml
新しいファイルをローカルからリポジトリにプッシュします。
この後、プロジェクトをビルドして、コードがリポジトリからプルされ、アーティファクトがビルドされるかどうかを確認できます。
コードパイプラインを作成する
- AWS CodePipeline で新しいパイプラインを作成します。
- パイプラインをソースとして CodeCommit リポジトリに接続します。
- CodeBuild をビルドステージとして使用するようにパイプラインを構成します。
- 作成したテンプレートを使用して CloudFormation をトリガーするデプロイ ステージを追加します。
パイプラインは、git コミットに基づいてコードを自動的に構築し、デプロイします。
パイプラインをテストする
- IntelliJ でプロジェクトを開きます。
- ファイルの 1 つに小さな変更を加えます。たとえば、別のロガー行を追加します。
- 変更をローカル Git リポジトリにコミットします。
- コミットを CodeCommit リポジトリにプッシュします。
$ git branch CR01 $ git checkout CR01 $ git add . $ git commit -m “CR01” $ git push --set-upstream origin CR01 You cand also create a pull request in aws code commit, just for simplicity I am merging from local $ git checkout master $ git merge --ff-only CR01 $ git push
- AWS CodePipeline コンソールに移動します。
- パイプラインが自動的に開始されるのが確認できるはずです。リポジトリから最新のコードを取得し、CodeBuild を使用してプロジェクトを構築し、CloudFormation を使用してデプロイします。
- CodePipeline ダッシュボードで進行状況を監視します。
これにより、コードに変更を加えてリポジトリにプッシュし、CICD パイプラインが自動的にトリガーして更新されたコードをデプロイするプロセスがシミュレートされます。
この記事では、AWS API Gateway、Lambda、DynamoDB、CodeCommit、CodeBuild、および CodePipeline を利用して、復元力のある自動化されたデプロイメント プロセスを構築する方法を示します。
読んでくれてありがとう。あなたのサーバーレスへの取り組みが成功と革新をもたらしますように!