【小ネタ】GitHub ActionsでLambda Layerをデプロイするときに困った話

【小ネタ】GitHub ActionsでLambda Layerをデプロイするときに困った話
この記事をシェアする

はじめに

こんにちは、CloudBuildersのsugawaraです。

先日、GitHub ActionsでLambdaとCDKのコードを自動デプロイしようとしたとき、Lambda Layerのデプロイ部分でちょっとつまってしまいました。今回はそのときの話を小ネタとして書いていきたいと思います。これを読んでいただき、自分のようなミスをしないようにしていただければと思います。

さきに結論

今回の件で自分が学んだのは下記の2点です。(ここを読んで理解納得できれば次節以降は読まなくて大丈夫だと思います!)

  • Lambda LayerをGitHub Actionsのワークフロー内でzip化し、CDKのコードとともにデプロイする場合、zipファイルをアーティファクトとしてGitHub Actions上へアップロードする必要がある。
  • アーティファクトはワークフロー間では渡すことができないため、ジョブ間で渡す(ダウンロードする)ようにする。

やりたいこと

  • GitHub ActionsでCDKのコードとその一部であるLambdaのコードを自動デプロイする
  • Lambda用のワークフロー内でLambda Layerはzip化する

実行環境

$ node --version
v20.12.2

$ cdk --version
2.138.0 (build 6b41c8b)

$ aws --version
aws-cli/2.13.25 Python/3.11.5 Linux/5.10.16.3-microsoft-standard-WSL2 exe/x86_64.ubuntu.22 prompt/off

当初の構成

ディレクトリ構成

.github/workflows配下のワークフローファイルはLambdaとCDKの2つを作成していました。また、infrastructure配下にはCDKのコード、lambda配下にはLambda(Node.js)とLambda Layerのコードを配置しています。

.
├── README.md
├── .github/workflows
│   ├── lambda.yml
│   └── infrastructure.yml
├── infrastructure
│   ├── bin
│   │   └── infrastructure.ts
│   ├── cdk.context.json
│   ├── cdk.json
│   ├── lib
│   │   └── infrastructure-stack.ts
│   ├── node_modules
│   ├── package-lock.json
│   └── package.json
└── lambda
    ├── lambda-layer
    │   └── nodejs
    └── src
        └── samplecode

ワークフローファイル

独立した2つのワークフローファイルを作成し、それぞれは異なるトリガーで起動するようにしていました。簡単にまとめると、下記のようになります。

  • GitHubにCDKのコードの更新がプッシュされたら、CDK用のワークフローが起動する。
  • GitHubにLambdaのコードの更新がプッシュされたら、Lambda用のワークフローが起動する。問題がなければ、次にCDK用のワークフローが起動する。

↓↓Lambda用のワークフローファイル

name: "Lambda Build and Test"

on:
  push:
    branches:
      - develop
    paths:
      - "lambda/**/*.mjs"
      - ".github/**/lambda.ya?ml"
  workflow_dispatch:

defaults:
  run:
    working-directory: lambda/src
    shell: bash

jobs:
  build-test-deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: actionlint
        uses: actions/checkout@v4
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm
          cache-dependency-path: ./lambda/src/package-lock.json
          cache-dependency-path: lambda/lambda-layer/nodejs/package-lock.json
      - name: Setup dependencies
        run: npm ci
        working-directory: lambda/lambda-layer/nodejs
      - name: Run Unit Tests
        run: npm test
      - name: Build
        run: npm run build

↓↓CDK用のワークフローファイル

name: "CI/CD for CDK"

on:
  push:
    branches:
      - develop
    paths:
      - "infrastructure/**"
      - ".github/**/infra.ya?ml"
  pull_request:
    branches:
      - main
  workflow_dispatch:
  workflow_run:
    workflows: ["Lambda Build and Test"]
    types:
      - completed

defaults:
  run:
    working-directory: infrastructure
    shell: bash

permissions:
  id-token: write
  contents: read

jobs:
  build-test-deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: actionlint
        uses: actions/checkout@v4
      - name: Checkout repository code
        uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_ARN }}
          aws-region: ap-northeast-1
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm
          cache-dependency-path: ./infrastructure/package-lock.json
      - name: Setup dependencies
        run: npm ci
      - name: Bootstrap CDK
        run: npx cdk bootstrap
      - name: Build
        run: npm run build
      - name: CDK Diff Check
        run: npx cdk diff
      - name: CDK Deploy
        if: github.ref == 'refs/heads/develop'
        run: npx cdk deploy --require-approval never

なお、AWSへのデプロイはGitHub ActionsのOpenID Connect用のIAMロールを作成して実行しています。OIDCについては下記の記事をご参照ください。

また、GitHub Actionsの学習についても記事を書いていますので、こちらも見ていただけると嬉しいです。

問題点と改善案

実際にワークフローを起動してみると、CDK用のワークフロー上でLambda Layerのzipファイルを取得できずにエラーに。

GitHubのActionsタブで確認してみると、LambdaのワークフローではLambda Layerがzip化されてGitHub上にアーティファクトとしてアップロードされていることは確認できました。しかし、CDK用のワークフロー上では、アップロードされたzipファイルのダウンロード時にNot Foundのエラーが出ているということがわかりました。

公式ドキュメントにてアーティファクトを見てみると、同一のワークフロー内なら別のジョブへアーティファクトを渡すことができるとわかりました。つまり、そもそも別ワークフローには渡せないということでした。

最終的な構成

ディレクトリ構成

2つのワークフローは統合して1つのワークフローに修正しました。

.
├── README.md
├── .github/workflows
│   └── cicd.yml       ## ここを修正して一元化
├── infrastructure
│   ├── bin
│   │   └── infrastructure.ts
│   ├── cdk.context.json
│   ├── cdk.json
│   ├── lib
│   │   └── infrastructure-stack.ts
│   ├── node_modules
│   ├── package-lock.json
│   └── package.json
└── lambda
    ├── lambda-layer
    │   └── nodejs
    └── src
        └── samplecode

ワークフローファイル

別々のワークフローだったものを2つのジョブに修正することで、アーティファクトをアップロード&ダウンロードできるようにしています。

name: "CI/CD for Lambda and CDK"

on:
  push:
    branches:
      - develop
    paths:
      - "lambda/**/*.mjs"
      - "infrastructure/**"
      - ".github/**.yml"
  pull_request:
    branches:
      - main
  workflow_dispatch:

defaults:
  run:
    shell: bash

permissions:
  id-token: write
  contents: read

jobs:
  build-lambda-and-lambda-layer:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: actionlint
        uses: actions/checkout@v4
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
      - name: Setup dependencies
        run: npm ci
        working-directory: ./lambda/lambda-layer/nodejs
      - name: Package Lambda Layer
        run: zip -r layer.zip nodejs
        working-directory: ./lambda/lambda-layer
      - name: Upload Lambda Layer Artifact
        uses: actions/upload-artifact@v4
        with:
          name: lambda-layer
          path: ./lambda/lambda-layer/layer.zip
      - name: Build Lambda
        run: npm run build
        working-directory: ./lambda/src
      - name: Test
        run: npm test

  deploy-cdk:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    needs: build-lambda-and-lambda-layer
    steps:
      - name: actionlint
        uses: actions/checkout@v4
      - name: Checkout repository code
        uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_ARN }}
          aws-region: ap-northeast-1
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm
          cache-dependency-path: ./infrastructure/package-lock.json
      - name: Setup dependencies for CDK
        run: npm ci
        working-directory: ./infrastructure
      - name: Download Lambda Layer Artifact
        uses: actions/download-artifact@v4
        with:
          name: lambda-layer
          path: ./lambda/lambda-layer
      - name: Bootstrap CDK
        run: npx cdk bootstrap
        working-directory: ./infrastructure
      - name: Build CDK
        run: npm run build
        working-directory: ./infrastructure
      - name: CDK Diff Check
        run: npx cdk diff
        working-directory: ./infrastructure
      - name: CDK Deploy
        if: github.ref == 'refs/heads/develop'
        run: npx cdk deploy --require-approval never
        working-directory: ./infrastructure

上記に修正することで、問題なくLambda Layerも含めてCDKのデプロイができるようになりました。

おわりに

今回は実際にGitHub Actionsで自分がつまづいたことを記事にしました。今回の失敗からアーティファクトやワークフロー、ジョブについての理解がちょっと深まりました。やはり自分でやってみるのことが一番学びにつながりますね。

まだまだ上記のワークフローファイルは改善の余地があるので、引き続き学習を進めたいと思います。

この記事をシェアする
著者:sugawara
元高校英語教員。2023&2024 Japan AWS All Certifications Engineers。IaCやCI/CD、Platform Engineeringに興味あり。