AWS SAM と GitHub Actions で爆速でサーバーレス API をデプロイする

Kenta Kobayashi

2025.2.17

こんにちは。スリーシェイクの小林です。

本日は AWS Serverless Application Model(以下、AWS SAM)と GitHub Actions を用いて サーバーレス API の作成からデプロイの自動化までを触ってみたいと思います。

AWS SAM とは

AWS SAM とは、AWS でサーバーレスアプリケーションを構築および実行する エクスペリエンスを簡素化および改善するオープンソースのデベロッパーツールです。

AWS SAM の利点としては、AWS のサーバーレスサービスを用いたアプリケーションの開発に特化しており、 AWS SAM CLI を使用してサーバーレスアプリケーションを開発、デバッグ、デプロイすることができます。

サーバーレス API の実装

早速 SAM CLI を使ってサーバーレス API を作成してみましょう。 今回はクイックスタートのために用意されているテンプレートから作成します。

SAM CLI のインストールについては こちら を参照してください。

まずは sam init でプロジェクトを作成します。

~$ sam init
You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

1 - AWS Quick Start Templates を選択すると、いくつかのテンプレートから作成するリソースを選択できます。

今回は Lambda + API Gateway が含まれる 1 - Hello World Example を選択します。

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Data processing
        3 - Hello World Example with Powertools for AWS Lambda
        4 - Multi-step workflow
        5 - Scheduled task
        6 - Standalone function
        7 - Serverless API
        8 - Infrastructure event management
        9 - Lambda Response Streaming
        10 - GraphQLApi Hello World Example
        11 - Full Stack
        12 - Lambda EFS example
        13 - Serverless Connector Hello World Example
        14 - Multi-step workflow with Connectors
        15 - DynamoDB Example
        16 - Machine Learning
Template: 1

テンプレートを選択した後は、ランタイムやモニタリングの選択に移りますが 今回は以下の通りで進めましたが、こちらはお好みで変えてください。 (変更してもこれ以降の手順が変わることはないです)

Use the most popular runtime and package type? (python3.13 and zip) [y/N]: y

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N

Would you like to enable monitoring using CloudWatch Application Insights?For more info, please view <https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html> [y/N]: N

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: N

Project name [sam-app]:

全ての入力を完了すると sam-app というフォルダが作成されていると思います。

SAM プロジェクトのリソースの確認

本記事の本筋とは逸れますが、先ほどの 1 - Hello World Example で作成された SAM プロジェクトで作成される AWS リソースをみてみましょう。

AWS SAM で管理・デプロイされる AWS リソースは template.yaml によってコード管理されています。

AWS::Serverless::Function というタイプのリソースが Lambda に、Events プロパティに定義されている Api の定義が Lambda と紐づく API Gateway に対応しており、 今回のテンプレートでは /hello という GET のエンドポイントをひとつデプロイする構成になっています。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-app

  Sample SAM Template for sam-app

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    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: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          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: /hello
            Method: get

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
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

CodeUriHandler に定義されている通り Lambda 関数のソースコードは sam-app/hello_world/app.py に記述されておりlambda_handler メソッドがエントリーポイントになります。

lambda_handler メソッドは {"message": "hello world"} という JSON 文字列を返すだけの単純なものになっています。

# hello_world/app.py (一部抜粋)

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
        }),
    }

デプロイ時の挙動の修正

デフォルトのままだと、デプロイ時に利用する sam deploy コマンドにおいて ChangeSet の確認を要求されるため GitHub Actions の実行自体が失敗してしまいます。

samconfig.tomldeploy.parameters で定義されている confirm_changesetfalse に変更し、ChangeSet の確認をせず、そのままデプロイできるようにしましょう。

[default.deploy.parameters]
capabilities = "CAPABILITY_IAM"
- confirm_changeset = true
+ confirm_changeset = false
resolve_s3 = true

ID プロバイダの作成

さて、SAM プロジェクトの下準備が整ったので GitHub Actions 側で必要なものを整えていきます。

まずは GitHub が IAM ロールを使えるように ID プロバイダを作成していきます。

GitHub Actions では OpenID Connect (OIDC) がサポートされています。 OIDC を使用することにより長期間有効なアクセスキーなどを用意することなく AWS 認証を行うことができます。

IAM のメニューから ID プロバイダ を選択し、プロバイダを追加します。

以下の項目を選択・入力し、プロバイダの作成をします。

プロバイダのタイプOpenID Connect
プロバイダの URLhttps://token.actions.githubusercontent.com
対象者sts.amazonaws.com

IAM ロールの作成

GitHub Actions で使用する IAM ロールを作成します。 ロールの信頼関係には、先ほど作成した OIDC の ARN を記載します。

また、Condition には GitHub のリポジトリ・ブランチ名を入力することで、 指定されたリポジトリ・ブランチからのみしか、本ロールに Assume Role できないよう制限します。

{AccountId} などと仮置きしている箇所については、適宜お使いのアカウントやリポジトリに置き換えてみてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::{AccountId}:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub": "repo:{GitHubUserName}/{GitHubRepositoryName}:ref:refs/heads/{BranchName}"
                }
            }
        }
    ]
}

GitHub Actions の作成

GitHub Actions を定義するためには、リポジトリ上の.github/workflows 配下にファイルを配置する必要があります。

今回は .github/workflows/deploy-sam-app.yaml を作成してみましょう。


name: run sam deploy

on:
  push:
    branches:
      - {BranchName}

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Branch
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.12
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: {Region}
          role-to-assume: arn:aws:iam::{AccountId}:role/GitHubActionsRole
      - name: Deploy
        run: |
          cd ./sam-app
          sam deploy

これでサーバーレス API を含む SAM プロジェクトの作成、そのデプロイを担う GitHub Actions の準備ができました!

デプロイの確認

IAM ロールの Condition および GitHub Actions で指定したブランチに sam-app および deploy-sam-app.yaml をプッシュします。

プッシュしたら GitHub リポジトリの Actions タブから実行状況を確認してみましょう。

今までの設定を済ませていれば自動で GitHub Actions が発火し、デプロイジョブが完了していることを確認できるはずです。

動作確認

さて、AWS コンソールでもデプロイの結果を見てみましょう。 CloudFormation のコンソールから sam-app というスタックが作成されています。

sam-app スタックの出力タブを確認すると、API Gateway のエンドポイント情報を見ることができます。

実際にエンドポイントにアクセスすると、Hello World とレスポンスが返ってくることが確認できました!

おわりに

いかがでしたでしょうか。

本記事では触れませんでしたが AWS SAM では Lambda や API Gateway だけでなく、 DynamoDB や StepFunctions など、サーバーレスで提供しているそのほかの AWS サービスもサポートされています。

参考:AWS SAM リソースとプロパティ

本記事ではデプロイの自動化をメインに説明したため AWS SAM で作成されたソースコードや使い方自体にはあまり触れませんでしたが、 非常に簡単に AWS リソースを作成・コード管理・デプロイができることを感じていただけたかなと思います。

携わっているプロジェクトでサーバーレスソリューションを検討している方で IaC やデプロイの自動化に悩んでいる方の参考になれば嬉しいです。

次回は、AWS SAM のより深い使い方やそのほかの自動化についても触れていきたいと思います。

ブログ一覧へ戻る

お気軽にお問い合わせください

SREの設計・技術支援から、
SRE運用内で使用する
ツールの導入など、
SRE全般についてご支援しています。

資料請求・お問い合わせ