SAMをGithub Actionsでデプロイし、Slackへ通知しよう

technologies

目次

  1. はじめに
  2. 対象読者
  3. 前提条件
    1. 必要な前提知識
    2. 必要なツール
  4. 手順
    1. ローカル環境構築
    2. IAMロール作成
    3. デプロイ用のS3バケット作成
    4. SlackWebhookUrlを取得
    5. Github Actionsのワークフローファイルを作成
    6. Githubリポジトリを作成
    7. Git push→デプロイ確認
  5. まとめ

1.はじめに

お疲れ様です。
クワハラです。

以前、弊社ブログ内でServerless framework V4からの有償化に伴いCloudFormationからAWS SAMへLambda関数を移行する方法の記事が書かれておりますが、それを元に別案件でもSAMへの移行を行いました。

そして今回はGithub ActionsでSAMのCI/CDを組んでみましたので、記事にしてみました。

2.対象読者

下記に該当する方を対象読者としています。

  • GithubおよびGithub Actionsの基本的な知識がある方
  • SAMおよびSAM CLIの基本的な知識がある方
  • SAMを使った開発に興味がある方

3.前提条件

本記事では下記を前提条件としているため、詳細については割愛させていただきます。
また、Mac OSにて本記事の内容を検証していますので、Windows OSを使用されている方は適宜コマンドを読み替えてください。

3-1.必要な前提知識

  • AWSのマネジメントコンソールの基本操作
  • IAMの基本概念・基本操作
  • SAMの基本概念
  • Git、Github、 Github Actionsの基本操作・基本概念
  • コマンドライン操作の基礎知識

3-2.必要なツール

  • Gitがインストール済みであること
  • Githubのアカウントがあること

4.手順

4-1.ローカル環境構築

ローカル端末にて作業用ディレクトリを作成します。

mkdir hands-on-sam-github-actions
mkdir -p hands-on-sam-github-actions/sam/lambda

Lambda関数内で実行するソースコードを作成します。今回はPython3.13を使用します。

touch hands-on-sam-github-actions/sam/lambda/lambda_function.py

下記ソースコードをhands-on-sam-github-actions/sam/lambda/lambda_function.pyへコピー&ペーストします。
ハンズオンのためシンプルな処理内容としています。

import json
import logging
import os
from datetime import datetime  

# ログ設定
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    """
    基本的なLambda関数のハンドラー
    """
    try:
        # 環境変数の取得
        environment = os.environ.get('ENVIRONMENT', 'unknown')
        function_name = context.function_name

        # リクエスト情報のログ出力
        logger.info(f"Function: {function_name}, Environment: {environment}")
        logger.info(f"Event received: {json.dumps(event)}")

        # レスポンスデータの作成
        response_data = {
            'message': 'Hello from Lambda!',
            'timestamp': datetime.now().isoformat(),
            'environment': environment,
            'function_name': function_name,
            'request_id': context.aws_request_id,
            'event_data': event
        }

        # 成功ログ
        logger.info(f"Response: {json.dumps(response_data)}")

        return response_data

    except Exception as e:

        # エラーログ
        logger.error(f"Error occurred: {str(e)}")
        error_response = {
            'error': 'Internal server error',
            'message': str(e),
            'timestamp': datetime.now().isoformat()
        }

    return error_response

次に、SAMテンプレートを作成しましょう。

touch hands-on-sam-github-actions/sam/template.yaml

下記ソースコードをhands-on-sam-github-actions/sam/template.yamlにコピー&ペーストします。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'SAM template for basic Lambda function - converted from CloudFormation'  

Resources:
  # Lambda実行用のIAMロール
  SamLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 'sam-basic-lambda-function-execution-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: CloudWatchLogsPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/sam-basic-lambda-function*'

  # Lambda関数定義
  SamBasicLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: 'sam-basic-lambda-function'
      Description: 'Basic Lambda function for SAM import tutorial'
      CodeUri: lambda/
      Handler: lambda_function.lambda_handler
      Runtime: python3.13
      Timeout: 30
      MemorySize: 128
      Role: !GetAtt SamLambdaExecutionRole.Arn
      Environment:
        Variables:
          ENVIRONMENT: 'test'
          LOG_LEVEL: 'INFO'

  # CloudWatch Logs グループ
  SamLambdaLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: '/aws/lambda/sam-basic-lambda-function'
      RetentionInDays: 14

現時点では下記のようなディレクトリ構成になっていると思います。

hands-on-sam-github-actions/
└── sam/  
    ├── template.yaml
    └── lambda/
        └── lambda_function.py

4-2.Github Actions用のIAMロール作成

AWSクレデンシャルを設定するActionsとしてaws-actions/configure-aws-credentials@v4を使用します。
そこではOIDCの利用を推奨しているため、今回はそれらを用いてAWS環境へデプロイするようにします。
GitHub – aws-actions/configure-aws-credentials: Configure AWS credential environment variables for use in other GitHub Actions.

まずはIDプロバイダの設定を行います。

以下のGithubの公式ドキュメントに則って対応します。
アマゾン ウェブ サービスでの OpenID Connect の構成 – GitHub ドキュメント

マネジメントコンソールからIAM > IDプロバイダ > プロバイダ作成ボタンを押下します。

以下を設定し、プロバイダ追加ボタンを押下します。

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

続いて任意の名前でポリシーを作成します。

{{AWS_ACCOUNT_ID}}を適宜ご自身のAWSアカウントIDに置き換えて、以下のJSONをポリシーエディタにコピー&ペーストします。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CloudFormationDeployOnly",
      "Effect": "Allow",
      "Action": [
        "cloudformation:CreateStack",
        "cloudformation:UpdateStack",
        "cloudformation:CreateChangeSet",
        "cloudformation:ExecuteChangeSet",
        "cloudformation:DeleteChangeSet",
        "cloudformation:DescribeStacks",
        "cloudformation:DescribeStackEvents",
        "cloudformation:DescribeChangeSet",
        "cloudformation:GetTemplateSummary",
        "cloudformation:ListStackResources"
      ],
      "Resource": "*"
    },
    {
      "Sid": "S3ForSamArtifacts",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetBucketLocation",
        "s3:PutObject",
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::hands-on-sam-github-actions-deploy-bucket",
        "arn:aws:s3:::hands-on-sam-github-actions-deploy-bucket/*"
      ]
    },
    {
      "Sid": "IamForExecutionRoleDeployOnly",
      "Effect": "Allow",
      "Action": [
        "iam:CreateRole",
        "iam:GetRole",
        "iam:AttachRolePolicy",
        "iam:PutRolePolicy",
        "iam:TagRole"
      ],
      "Resource": "arn:aws:iam::{{AWS_ACCOUNT_ID}}:role/sam-basic-lambda-function-execution-role"
    },
    {
      "Sid": "PassRoleToLambdaOnly",
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::{{AWS_ACCOUNT_ID}}:role/sam-basic-lambda-function-execution-role",
      "Condition": {
        "StringEquals": {
          "iam:PassedToService": "lambda.amazonaws.com"
        }
      }
    },
    {
      "Sid": "LambdaDeployOnly",
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:UpdateFunctionCode",
        "lambda:UpdateFunctionConfiguration",
        "lambda:GetFunction",
        "lambda:TagResource",
        "lambda:UntagResource"
      ],
      "Resource": "arn:aws:lambda:ap-northeast-1:{{AWS_ACCOUNT_ID}}:function:sam-basic-lambda-function"
    },
    {
      "Sid": "LogsDeployOnly",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:PutRetentionPolicy",
        "logs:DescribeLogGroups",
        "logs:TagResource",
        "logs:UntagResource"
      ],
      "Resource": [
        "arn:aws:logs:ap-northeast-1:{{AWS_ACCOUNT_ID}}:log-group:/aws/lambda/sam-basic-lambda-function",
        "arn:aws:logs:ap-northeast-1:{{AWS_ACCOUNT_ID}}:log-group:/aws/lambda/sam-basic-lambda-function:*"
      ]
    },
    {
      "Sid": "CallerIdentity",
      "Effect": "Allow",
      "Action": "sts:GetCallerIdentity",
      "Resource": "*"
    }
  ]
}

確認し問題なければポリシーを作成します。

続いてIAMロールの作成を行います。

以下を選択し、次へ。

  • 信頼されたエンティティタイプ: ウェブアイデンティティ
  • アイデンティティプロバイダー: token.actions.githubusercontent.com
  • Audience: sts.amazonaws.com
  • GitHub organization: ご自身の組織名
  • GitHub repository: hands-on-sam-deploy-with-github-actions
  • GitHub branch: main

作成したインラインポリシーを選択します。

確認し問題なければ、ロール名を任意の名前で作成します。

作成したIAMロールのARNをコピーします。

これでdeploy用のOIDCを使用したIAMロールが作成できました。

4-3.デプロイ用のS3バケットを作成

マネジメントコンソールからS3 > 汎用バケット > バケットを作成ボタンを押下します。

任意のS3バケット名で作成し、後はデフォルトのまま作成します。
なおS3バケット名はグローバルで一意になるようにしてください。また、S3バケット名は小文字、数字、ハイフンのみ使用可能です。

4-4.Slackのwebhook URLを取得

弊社では主にSlackを用いてコミュニケーションを取っております。
今回はGithubActionで簡易的に通知できるようにslackのwebhook urlを取得し、そちらへ通知するようにします。

組織のSlackのMarketPlaceからIncoming Webhookを検索し、該当のSlackアプリをクリックします

Slackに追加を押下し、対象のチャネルを選択。
その後、Incoming Webhook インテグレーションの追加ボタンを押下。

するとWebhook URLが表示されますので、コピーします。
(対象のチャネルにはインテグレーションが追加されます。)

4-5.Github Actionsのワークフローファイルを作成

続いてGithub Actionsの実行ファイルを作成していきましょう

mkdir -p hands-on-sam-github-actions/.github/workflows
touch hands-on-sam-github-actions/.github/workflows/sam-deploy-actions.yml

下記ソースコードをhands-on-sam-github-actions/.github/workflows/sam-deploy-actions.ymlにコピー&ペーストします。
今回は一旦mainブランチへpush時に起動するようにしています
なお、envプロパティのDEPLOY_BUCKET_NAMEは先ほど作成したデプロイ先のS3バケットのバケット名を指定してください。

name: Deploy SAM with GitHub Actions

on:
  push:
    branches:
      - main
    paths:
      - 'sam/**'
      - '.github/workflows/sam-deploy-actions.yml'

env:
  AWS_REGION: ap-northeast-1
  SAM_STACK_NAME: hands-on-sam-github-actions-basic-lambda-stack
  DEPLOY_BUCKET_NAME: [S3バケット名] # 【注意】先ほど作成したS3バケット名に置き換えてください。
  AWS_ASSUME_ROLE: ${{ secrets.AWS_ASSUME_ROLE }}
  SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

permissions:
  id-token: write
  contents: read

jobs:
  deploy-sam:
    name: Deploy SAM with GitHub Actions
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Notify Slack of Start
        uses: lazy-actions/slatify@master # Slack通知用アクション
        if: always()
        with:
          type: ${{ job.status }}
          job_name: ':rocket: *sam-cicd デプロイ開始*'
          url: ${{ env.SLACK_WEBHOOK }}

      # PythonのLambdaを使用するためのセットアップ
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'

      - uses: aws-actions/setup-sam@v2 # SAM CLIのインストール
        with:
          use-installer: true # installを高速化

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ env.AWS_ASSUME_ROLE }}
          aws-region: ${{ env.AWS_REGION }}
          role-session-name: GitHubActionsSamDeploySession

      - name: SAM Build
        run: sam build
        working-directory: sam

      - name: SAM Deploy
        run: |
          sam deploy \
            --stack-name "${SAM_STACK_NAME}" \
            --region "${AWS_REGION}" \
            --s3-bucket "${DEPLOY_BUCKET_NAME}" \
            --capabilities CAPABILITY_NAMED_IAM \
            --no-confirm-changeset \
            --no-fail-on-empty-changeset
        working-directory: sam

      - name: Notify Slack of Results
        uses: lazy-actions/slatify@master
        if: always()
        with:
          type: ${{ job.status }}
          job_name: ':rocket: *sam-cicd デプロイ結果*'
          url: ${{ env.SLACK_WEBHOOK }}

最終的に下記のようなディレクトリ構成になっていると思います。

hands-on-sam-github-actions/
├── .github/workflows/
│   └── sam-deploy-actions.yml
└── sam/  
    ├── template.yaml
    └── lambda/
        └── lambda_function.py

ここで一旦Gitのコミットを作成しましょう。
以下のコマンドを実行し、Gitのコミットを作成します。

cd hands-on-sam-github-actions
git init

git add .github/workflows/sam-deploy-actions.yml sam/lambda/lambda_function.py sam/template.yaml

git commit -m "init SAM deploy with GitHub Actions"

4-6.GitHubリポジトリを作成

Githubで新規リポジトリを作成します。
なお、今回はhands-on-sam-deploy-with-github-actionsという名前でリポジトリを作成します。

GitHubリポジトリでSecrets Keyを作成します

Settings > Secrets and variables > Actionsをクリックし、New repository secretボタンを押下します。

そして、以下のSecrets情報を入力し、Add secretボタンを押下します。

  • AWS_ASSUME_ROLE: 先ほど取得したIAMロールのARN
  • SLACK_WEBHOOK: 先ほど取得したSlackのWebhook URL

設定が完了すると以下の状態になっているかと思います。

これでGithub Actionsを利用する準備が整いました。

4-7.Git push→デプロイ

それでは実際にgit pushしてGithub Actionsを動かしてみましょう。
{{YourOrg}}をご自身が所属するGithubの組織名あるいは個人名に置き換えて、下記を実行します。

git remote add origin https://github.com/{{YourOrg}}/hands-on-sam-deploy-with-github-actions.git
git branch -M main
git push -u origin main

Github Actionsが起動するので完了まで待ち、StatusがSuccessとなれば成功です。

その際に、Slackの通知も届いているはずです。

※なお失敗時は以下のような通知です。

AWSマネジメントコンソールからも無事にデプロイが成功していることが確認できています。

念の為、AWSマネジメントコンソールでLambda関数、IAM RoleおよびCloudWatch Logsのリソースが存在していることを確認しましょう。

各種リソースが存在していることを確認できました。
これで、Github ActionsでAWS SAMへのデプロイができました。

5.まとめ


本記事では、AWS SAMとGithub ActionsによるCI/CD化について解説させていただきました。
思っていたより簡単に作成できたのではないでしょうか。

皆さんの一助になれば幸いです!

Related posts