AWS PR

AWS SAMとCDKでバックエンドサーバ(Lambda)を開発・運用してみる

aws-sam-cdk-lambda-golang-sample
記事内に商品プロモーションを含む場合があります

開発環境

もはやDockerすら面倒!
簡単な開発にはGitHub Codespacesを使います。
※node/Golangなどがセットアップ済みなのでラクなのです

AWS CDKの準備

AWS CDKのインストール

1. CDKのインストール

npm i -g aws-cdk

2. CDKのバージョン確認(簡単だなぁ助かる〜!)

cdk --version

AWS CLIのインストール

CDKの認証にはAWS CLIも使う?
そうなのでインストールしておく。

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version

認証情報やリージョンの設定もしておきましょう〜。

aws configure

テストなのでIAMの権限は下記のような感じ。
※本運用時は権限絞ってくださいね〜。

CDK セットアップ

CDKプロジェクトを初期化します。
※TypeScriptを使用。

cdk init app --language typescript

こんな↓感じになります。

cdk-sample-init

Lambda関数を作成する

1. Lambda関数用のコードを作成する
※Golangを使用

mkdir -p lambda/bin
touch lambda/main.go

2. Goのモジュールを使うので、初期化します。

go mod init lambda-sample

3. Lambda用のモジュールを追加します。

go get github.com/aws/aws-lambda-go/lambda

3. Goのコードを書きます。Hello World!

package main

import (
    "github.com/aws/aws-lambda-go/lambda"
)

type Response struct {
    Message string `json:"message"`
}

func Handler() (Response, error) {
    return Response{
        Message: "Hello World!",
    }, nil
}

func main() {
    lambda.Start(Handler)
}

SAMを使って、ローカル実行

さて、ここで一旦ローカルでLambdaを実行するために
SAMを使います〜。

SAM CLIのインストール

AWSの公式サイトを参考に進めます。

1. SAMのダウンロード

wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip

2. ZIPの解凍

unzip aws-sam-cli-linux-x86_64.zip -d sam-installation

3. SAMのインストール

sudo ./sam-installation/install

バージョン確認!簡単にセットアップできました〜。

sam --version

SAMでLambdaをローカル実行する

1. cdk synth --no-staging > template.yaml
AWS Cloud Development Kit (CDK) コマンドで、
CDKアプリケーションのCloudFormationテンプレートを生成します。
※--no-stagingオプションはアセットのステージングをスキップし、

cdk synth --no-staging > template.yaml

2. sam local invoke HelloHandlerXXXXXXXX --no-event
AWS SAM (Serverless Application Model) コマンドで、
ローカル環境でLambda関数HelloHandlerXXXXXXXXをトリガーイベントなしで実行します。
--no-eventオプションは、関数にイベントを渡さずに実行する
 HelloHandlerXXXXXXXX はCDKが自動生成するので適宜置き換えること

sam local invoke HelloHandlerXXXXXXXX --no-event
cdk-sample-lambda-template

3. Hello Worldが出ればOK!

AWS CDKでデプロイしてみる

AWS CLIで認証設定はしてあるので、デプロイしてみます。
1. まずはcdk bootstrapコマンドで初期化。

cdk bootstrap aws://[AWSアカウントID]/ap-northeast-1

このコマンドは、特定のAWSリージョン
(今回はアジアパシフィック(東京)リージョン、ap-northeast-1)に
対してCDKアプリケーションのデプロイメントに必要なリソースをプロビジョニングします。
実行すると、CDKは指定されたAWSアカウントとリージョンに
CloudFormationテンプレートをデプロイし、
後続のCDKデプロイメントのための基本的なリソースと構成をセットアップします。
※CDKアプリケーションを初めてデプロイする際に一度だけ必要です。

2. デプロイ

cdk deploy

AWS ConsoleからLambdaのTestしてみます。良い感じですね!

3. お金もかかるので環境を削除しておきましょう〜。
cdk bootstrapで実行された内容はクリーンアップされません。
(同じアカウント、リージョンでデプロイする際に利用されます。)

cdk destroy

おまけ(ApiGatewayも追加してみた)

とりあえず以下のような感じにしてみました。
誰でも呼べるAPIではセキュリティ的に良くないので
IAM認証を追加してます。

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
import { RestApi, AuthorizationType, LambdaIntegration } from 'aws-cdk-lib/aws-apigateway'
import * as  lambda from 'aws-cdk-lib/aws-lambda';

export class BackendStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    //IAM
    const lambda_basic_policy = new iam.ManagedPolicy(this, 'Lambda_basic_policy', {
      managedPolicyName: 'lambda_basic_policy',
      description: 'Lambda basic execution policy',
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ['logs:*'],
          resources: ['arn:aws:logs:*:*:*'],
        }),
      ],
    });

    const function_role = new iam.Role(this, 'Sample_Function_role', {
      roleName: 'Sample_Function_role',
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
    });
    function_role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMReadOnlyAccess'));
    function_role.addManagedPolicy(lambda_basic_policy);

    const invokeUser = new iam.User(this, 'User', {
      userName: `backend-invoke-user`,
    });

    //Lambda
    const sampleFunction = new lambda.Function(this, 'SampleFunction', {
      runtime: lambda.Runtime.GO_1_X,
      code: lambda.Code.fromAsset('../../src/lambda/sample/bin'),
      handler: 'main',
      role: function_role,
    })

    //API
    const sampleApi = new RestApi(this, 'sampleApi', {
      restApiName: 'Sample Api',
    })
    const sampleApiResource = sampleApi.root.addResource('api').addResource('v1').addResource('sample')
    sampleApiResource.addMethod(
      'GET', 
      new LambdaIntegration(sampleFunction),
      {
        authorizationType: AuthorizationType.IAM,
      }
    );

    invokeUser.attachInlinePolicy(
      new iam.Policy(this, 'Policy', {
        statements: [
          new iam.PolicyStatement({
            actions: ['execute-api:Invoke'],
            effect: iam.Effect.ALLOW,
            resources: [sampleApi.arnForExecuteApi()],
          }),
        ],
      }),
    );
  }
}

これで作られたIAMユーザにKeyを追加して、
Curlなどで–aws-sigv4をつけて呼んでやれば、確認できます!

curl -X GET https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/api/v1/sample --aws-sigv4 aws:amz:ap-northeast-1:execute-api --user [AccessKey]:[SecretKey]

まとめ

本記事では、
AWS SAM(Serverless Application Model)と
AWS CDK(Cloud Development Kit)を使用して、
Lambda+Golangベースのバックエンドサーバーを試す方法について説明しました。

AWS SAMでサーバーレスアプリケーションのビルドとローカル実行を簡素化し、
AWS CDKで、TypeScriptでインフラストラクチャをコード化、
デプロイしてみました!

SAMでデプロイもできますが、デプロイするリソースが多いと
CDKが活きてくるのかなと思います。

誰かの参考になれば幸いです!!