こつつみ

コツコツ積み上げる

GitHub Actionsで「 CloudFormationで構築したLambdaにS3を介さずに自動でデプロイする」を作る

はじめに

以前の記事でLambda + CloudWatch Event でインフラをコード化した。

kotsutsumi.hatenablog.com

今回は、GitHubで管理しているLambdaに上げるコードをmasterブランチを更新するたびに、 AWS S3を介さずにデプロイする方法について書く。

CloudFormation

CloudFormationについては以前の記事でも記載したが、再度掲載する。

AWSTemplateFormatVersion: 2010-09-09

Description: Lambda for git commit count bot

Parameters:
  GitHubAccessToken:
    Type: String
  SlackApiToken:
    Type: String

Resources:
  GitCommitCountBotLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: git-commit-count-bot
      Handler : lambda_function.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.9
      Timeout: 10
      Environment:
        Variables:
          GITHUB_ACCESS_TOKEN: !Ref GitHubAccessToken
          SLACK_API_TOKEN: !Ref SlackApiToken
      Code:
        ZipFile: |
          def lambda_handler(event, context):
              print('dummy')

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: git-commit-count-bot-role
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource:
                  - '*'

  CloudWatchEventRule:
    Type: AWS::Events::Rule
    Properties:
      Name: schedule-every-day-0am-event
      ScheduleExpression: cron(0 15 * * ? *) # 日本時間で 0:00
      State: ENABLED
      Targets:
        - Arn: !GetAtt GitCommitCountBotLambda.Arn
          Id: git-commit-count-bot-lambda

  LambdaEventPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref GitCommitCountBotLambda
      Principal: events.amazonaws.com
      SourceArn: !GetAtt CloudWatchEventRule.Arn

GitHub Actions

GitHub Actionsとは?

GitHub Actionsとは、GitHub上でプッシュ・Issue・リリースなどのイベントをトリガーに起動し、対応するアクションを組み合わせてワークフローの自動化が行える。 いわゆるCI/CDツールです。類似のものですと、CircleCIやJenkinsなどがある。

ドキュメントや公開されているActionが多数あるので、これらを活用することで簡単に自動化の実装ができる。また、Github ActionsはYamlファイルを書くだけで良いため1つサンプルを準備すると、 同様の設定をエンジニア以外でも作成することができる。公開されているActionを使うことで自分で作らなくても良いものもある。

CloudFormationで構築したLambdaにS3を介さずに自動でデプロイする

適宜ファイルにコメントをつけて説明する

name: deploy

on:
  push:
    branches:
      - master  # masterにイベントが発生した場合をトリガーに起動する

jobs:
  lambda-cd:
    name: Zip the code to be deployed to AWS Lambda
    runs-on: ubuntu-latest
    env:
      ZIP_FILE_NAME: package.zip  # jobs全体に適用される環境変数を設定する
    steps:
      - name: Checkout
        uses: actions/checkout@v2  # 公式が提供しているGitHub Actions, イベントがあったブランチを仮想環境上に置く(チェックアウトする)

      - name: Setup Python
        uses: actions/setup-python@v2 # 公式が提供しているGitHub Actions, Python環境を準備する
        with:
          python-version: 3.9

      - name: Zip the code
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt -t ./   # Lambda上でpip installできないので、サードパーティーのライブラリのソースコードを置く 
          zip -r ${{ env.ZIP_FILE_NAME }} ./*  # サードパーティーのライブラリのソースコード と 自身のコードをZip化する
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1   # こちらもGitHub Actionsで公開されている, AWSの認証を行う
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: deploy to AWS Lambda
        env:
          TEMPLATE_FILE: cloudformation/git_commit_count_bot.yml   # CloudFormationのYamlファイルのパス
          STACK_NAME: git-commit-count-bot-cfn  
          LAMBDA_FUNCTION_NAME: git-commit-count-bot
        run: |
          aws cloudformation deploy \
            --template-file $TEMPLATE_FILE \
            --stack-name $STACK_NAME \
            --capabilities CAPABILITY_NAMED_IAM \
            --parameter-overrides \
            GitHubAccessToken=${{ secrets.ACCESS_TOKEN }} \
            SlackApiToken=${{ secrets.SLACK_API_TOKEN }}     # AWS上に環境を構築する
          aws lambda update-function-code \
            --function-name $LAMBDA_FUNCTION_NAME \   # CloudFormationのYamlファイルに変更がない限り変更コードが反映されない
            --zip-file fileb://${{ env.ZIP_FILE_NAME }} --publish   # そこで毎回Zipファイルを指定してLambdaのコードを更新する

このようにすれば、masterブランチを更新するたびに、AWS S3を介さずにデプロイできる。

最後に

今回はこのようにして行ったが、CloudFormationで AWS::Serverless::Function を用いれば簡単にできるかもしれないと後になって気づいた。 しかし、試していないので今度試してみて出来れば記事にしたいと思う。

docs.aws.amazon.com