コンテンツにスキップ

terraformで構築済みのLambdaをGitHubActionsでデプロイする

概要

GitHubActionsを使って、terraformで構築したLambdaをデプロイする方法を紹介します。

ディレクトリ構成

uml diagram

ワークフロー

deploy.yml

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
name: Deploy SampleLambda

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      aws_environment:
        description: 'AWS Environment(dev2 or stg2 or prd)'
        required: true
        default: 'prd'
      aws_region:
        description: 'AWS region'
        required: true
        default: 'ap-northeast-1'
      actions_role_name:
        description: 'IAM Role name (excluding environment names)'
        required: true
        default: 'improvement-role-github-actions-deployment'
      function_name:
        description: 'Lambda function name'
        required: true
        default: 'SampleLambda'
      function_dir:
        description: 'Current directory'
        required: true
        default: 'lambda/SampleLambda'
      dependencies_zip_name:
        description: 'Dependencies zip name'
        required: true
        default: 'SampleLambdaUtils.zip'
      s3_bucket:
        description: 'Dependencies S3 bucket (excluding environment names)'
        required: true
        default: 'improvement-input-file'
      lambda_function_zip_name:
        description: 'Lambda function zip name'
        required: true
        default: 'SampleLambda.zip'
      lambda_layer_name:
        description: 'Lambda layer name'
        required: true
        default: 'improvement-create-slo-report-utils'

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'

    - name: Set default environment variables
      run: |
        echo "AWS_ENVIRONMENT=${{ github.event.inputs.aws_environment || 'prd' }}" >> $GITHUB_ENV
        echo "AWS_REGION=${{ github.event.inputs.aws_region || 'ap-northeast-1' }}" >> $GITHUB_ENV
        echo "ACTIONS_ROLE_NAME=${{ github.event.inputs.actions_role_name || 'improvement-role-github-actions-deployment' }}" >> $GITHUB_ENV
        echo "FUNCTION_NAME=${{ github.event.inputs.function_name || 'SampleLambda' }}" >> $GITHUB_ENV
        echo "FUNCTION_DIR=${{ github.event.inputs.function_dir || 'lambda/SampleLambda' }}" >> $GITHUB_ENV
        echo "DEPENDENCIES_ZIP_NAME=${{ github.event.inputs.dependencies_zip_name || 'SampleLambdaUtils.zip' }}" >> $GITHUB_ENV
        echo "S3_BUCKET=${{ github.event.inputs.s3_bucket || 'improvement-input-file' }}" >> $GITHUB_ENV
        echo "LAMBDA_FUNCTION_ZIP_NAME=${{ github.event.inputs.lambda_function_zip_name || 'SampleLambda.zip' }}" >> $GITHUB_ENV
        echo "LAMBDA_LAYER_NAME=${{ github.event.inputs.lambda_layer_name || 'improvement-create-slo-report-utils' }}" >> $GITHUB_ENV

    - name: Set AWS account ID
      id: set-aws-account-id
      run: |
        if [ "${{ env.AWS_ENVIRONMENT }}" = "prd" ]; then
          echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_prd }}" >> $GITHUB_ENV
        elif [ "${{ env.AWS_ENVIRONMENT }}" = "dev2" ]; then
          echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV2 }}" >> $GITHUB_ENV
        else
          echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_STG2 }}" >> $GITHUB_ENV
        fi

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.ACTIONS_ROLE_NAME }}-${{ env.AWS_ENVIRONMENT }}
        role-session-name: GithubActions
        aws-region: ${{ env.AWS_REGION }}

    - name: Get Caller Identity is Allowed to Run on Role.
      run: aws sts get-caller-identity

    - name: Install dependencies
      run: |
        cd ${{ env.FUNCTION_DIR }}
        python -m pip install --upgrade pip
        pip install -r requirements.txt -t lib/python
        rm -r lib/python/matplotlib/tests/
        rm -r lib/python/pandas/tests/
        rm -r lib/python/numpy/tests/

    - name: Archive dependencies
      run: |
        cd ${{ env.FUNCTION_DIR }}/lib
        zip -r ../${{ env.DEPENDENCIES_ZIP_NAME }} python

    - name: Upload dependencies to S3
      run: |
        aws s3 cp ${{ env.FUNCTION_DIR }}/${{ env.DEPENDENCIES_ZIP_NAME }} s3://${{ env.S3_BUCKET }}-${{ env.AWS_ENVIRONMENT }}/

    - name: Remove lib directory
      run: |
        cd ${{ env.FUNCTION_DIR }}
        rm -rf lib/
        rm -f ${{ env.DEPENDENCIES_ZIP_NAME }}

    - name: Archive Lambda function script
      run: |
        cd ${{ env.FUNCTION_DIR }}
        find . -type d -name 'tests' -prune -o -type f -name '*.py' -print > py_files_list.txt
        zip -@ ${{ env.LAMBDA_FUNCTION_ZIP_NAME }} < py_files_list.txt
        rm py_files_list.txt

    - name: Upload Lambda function to S3
      run: |
        aws s3 cp ${{ env.FUNCTION_DIR }}/${{ env.LAMBDA_FUNCTION_ZIP_NAME }} s3://${{ env.S3_BUCKET }}-${{ env.AWS_ENVIRONMENT }}/

    - name: Update Lambda layer
      run: |
        LAYER_VERSION=$(aws lambda publish-layer-version \
          --layer-name ${{ env.LAMBDA_LAYER_NAME }} \
          --content S3Bucket=${{ env.S3_BUCKET }}-${{ env.AWS_ENVIRONMENT }},S3Key=${{ env.DEPENDENCIES_ZIP_NAME }} \
          --compatible-runtimes python3.11 --region ${{ env.AWS_REGION }} \
          --output text --query Version)
        echo "LAYER_VERSION=$LAYER_VERSION" >> $GITHUB_ENV

    - name: Get current environment variables
      id: get-env-vars
      run: |
        aws lambda get-function-configuration \
          --function-name ${{ env.FUNCTION_NAME }} \
          --region ${{ env.AWS_REGION }} \
          --query 'Environment.Variables' > current_env_vars.json
        cat current_env_vars.json

    - name: Merge new environment variables
      id: merge-env-vars
      run: |
        jq -n \
          --argjson current "$(cat current_env_vars.json)" \
          --argjson new '{"API_KEY":"${{ env.DATADOG_API_KEY }}","APP_KEY":"${{ env.DATADOG_APP_KEY }}","DATADOG_ENV":"${{ env.DD_ENVIRONMENT }}"}' \
          '$current + $new' > merged_env_vars.json
        cat merged_env_vars.json

    - name: Update Lambda function configuration
      run: |
        env_vars=$(cat merged_env_vars.json | jq -r '. | to_entries | map("\(.key)=\(.value | tostring)") | join(",")')
        aws lambda update-function-configuration \
          --function-name ${{ env.FUNCTION_NAME }} \
          --environment "Variables={$env_vars}" \
          --layers arn:aws:lambda:${{ env.AWS_REGION }}:${{ env.AWS_ACCOUNT_ID }}:layer:${{ env.LAMBDA_LAYER_NAME }}:$LAYER_VERSION \
          --region ${{ env.AWS_REGION }}
        aws lambda wait function-updated \
          --function-name ${{ env.FUNCTION_NAME }} \
          --region ${{ env.AWS_REGION }}

    - name: Update Lambda function code
      run: |
        aws lambda update-function-code \
          --function-name ${{ env.FUNCTION_NAME }} \
          --s3-bucket ${{ env.S3_BUCKET }}-${{ env.AWS_ENVIRONMENT }} \
          --s3-key ${{ env.LAMBDA_FUNCTION_ZIP_NAME }} \
          --region ${{ env.AWS_REGION }}

コメント