본문 바로가기

GitHub

Github Action 으로 AWS Lambda 자동 배포하기(2)

반응형
 

Github Action 으로 AWS Lambda function 자동 배포하기

회사 업무로인해 CTO님이 Node로 작성하신 AWS Lambda 함수를 수정하는 역할을 맡게 되었다.(난 java spring이긴한데....) 이후 수정내역을 CTO님께 보고 드리면서 AWS Lambda 함수를 자동으로 배포하는 작업

xddsr123.tistory.com

 

결론부터 말하자면 본인은 만족하는 유익한 업무이자 학습 시간이 되었다.

 

코드는 아래와 같다.

name: Deploy lambda function
on:
  push:
    branches:
      - main
      - dev
      - 'feature/test'
      - 'feature/test2'

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_REGION: ${{ secrets.AWS_REGION }}
  PROD_FUNC_NM: ${{ secrets.PROD_FUNC_NM }}
  DEV_FUNC_NM: ${{ secrets.DEV_FUNC_NM }}
  DEV_ALIAS_NM: ${{ secrets.DEV_ALIAS_NM }}

jobs:
  deploy_source:
    name: Deploy lambda by github push
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install Node Module
        if: github.ref != 'refs/heads/feature/test2'
        run: npm install

      - name: Compress Code to Zip File
        run: zip -r9 code.zip *

      - name: Upload code to prod
        if: github.ref == 'refs/heads/main'
        run: aws lambda update-function-code --function-name $PROD_FUNC_NM --zip-file fileb://code.zip

      - name: Upload code to test
        if: contains(fromJSON('["refs/heads/feature/test", "refs/heads/feature/test2"]'), github.ref)
        run: aws lambda update-function-code --function-name $DEV_FUNC_NM --zip-file fileb://code.zip

  publish_version:
    needs: deploy_source
    name: Publish version old lambda function
    runs-on: ubuntu-latest
    outputs:
      nv: ${{ steps.nv.outputs.NEW_VERSION }}
    steps:
      - name: Publish test
        id: nv
        if: github.ref == 'refs/heads/feature/test'
        run: |
          NEW_VERSION=$(aws lambda publish-version --function-name $DEV_FUNC_NM --description test2 --query Version --output text)
          echo "NEW_VERSION=$NEW_VERSION" >> "$GITHUB_OUTPUT"

      - name: Publish test2
        if: github.ref == 'refs/heads/feature/test2'
        run: aws lambda publish-version --function-name $DEV_FUNC_NM --description test2

  inquire_alias:
    needs: publish_version
    name: Inquire Alias Information
    runs-on: ubuntu-latest
    outputs:
      ov: ${{ steps.ov.outputs.OLD_VERSION }}
      nv: ${{ needs.publish_version.outputs.nv }}
    steps:
      - name: Inquire dev lambda alias information
        id: ov
        if: github.ref == 'refs/heads/feature/test'
        run: |
          OLD_VERSION=$(aws lambda get-alias --function-name $DEV_FUNC_NM --name dev --query FunctionVersion --output text)
          echo "OLD_VERSION=$OLD_VERSION" >> "$GITHUB_OUTPUT"

  update_alias:
    needs: inquire_alias
    name: Update Alias Information
    runs-on: ubuntu-latest
    steps:
      - name: Update dev lambda alias information
        if: github.ref == 'refs/heads/feature/test'
        run: aws lambda update-alias --function-name $DEV_FUNC_NM --function-version ${{ needs.inquire_alias.outputs.ov }} --routing-config AdditionalVersionWeights={"${{ needs.inquire_alias.outputs.nv }}"=0.1} --name $DEV_ALIAS_NM

 

이전에 비해서 상당히 길어지도 뭔가 추가되고 눈에 보기에 복잡해졌다.

 

많은 시행착오를 거치고 이건 필요한데 어떻게 안될까? 라는 고민으로 탄생한 초보자의 결과물 이지만 후일 더 나은 발전을 위해 기록하고자 한다.

 

진행 단계는 다음과 같다.


1. 타게팅

  1. name : 깃허브 액션 탭에서 좌측에 표시될 해당 작업의 이름
  2. on : "push"를 하는데 "branches"아래 정의된 브랜치에 푸시될때 동작
name: Deploy lambda function
on:
  push:
    branches:
      - main
      - dev
      - 'feature/test'
      - 'feature/test2'

 

 

2. 노드의 .env, java의 yml 파일과 같은 환경변수 정의

  1. Github secrets에 정의하여 사용
  2. 정의할 레포지토리 > Settings > Secrets and variables > Actions > New repository secret
  3. Github Action에 env 로 등록

AWS를 사용하므로 키값과 리전 정의

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_REGION: ${{ secrets.AWS_REGION }}
  PROD_FUNC_NM: ${{ secrets.PROD_FUNC_NM }}
  DEV_FUNC_NM: ${{ secrets.DEV_FUNC_NM }}
  DEV_ALIAS_NM: ${{ secrets.DEV_ALIAS_NM }}

 

3. TODO의 느낌

  1. jobs에 해야할 일을 정의 및 정리
  2. 첫번째 할일의 제목 정하기
  3. 일의 제목을 정했으니 세부로 들어가기 위한 부재로 name 정하기
  4. 부재가 정해졌으니 해당 액션을 돌릴 기반 runs-on 정하기 -> [runs-on]
  5. 어렸을 때 작성한 생화계획표마냥 단계 만들기
jobs:
  deploy_source:
    name: Deploy lambda by github push
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install Node Module
        if: github.ref != 'refs/heads/feature/test2'
        run: npm install

      - name: Compress Code to Zip File
        run: zip -r9 code.zip *

      - name: Upload code to prod
        if: github.ref == 'refs/heads/main'
        run: aws lambda update-function-code --function-name $PROD_FUNC_NM --zip-file fileb://code.zip

      - name: Upload code to test
        if: contains(fromJSON('["refs/heads/feature/test", "refs/heads/feature/test2"]'), github.ref)
        run: aws lambda update-function-code --function-name $DEV_FUNC_NM --zip-file fileb://code.zip

 

name: Checkout > git에서 특정 브랜치로 checkout하는거랑 같습니다.

 

name: Install Node Module > 노드모듈들을 설치 하는데!

if: github.ref != 'refs/heads/feature/test2' > feature/test2 브랜치 일때는 패스

run: npm install > 설치

 

name: Compress Code to Zip File > 현재 브랜치에 올라온 파일들 압축하는데

zip -r9 code.zip * > 이 명령어로 압축

 

name: Upload code to ~~~ > 업로드 할껀데 어디에?

if: ~~~ > 특정 브랜치면 특정 Lambda 함수에 그리고 어떻게?

run: aws lambda update-function-code --function-name ~~~ --zip-file fileb://code.zip > aws lambda update-function-code 라는 함수를 이용하여 코드 업로드(업데이트)

 

위처럼 if문에 or 형태로 분기쳐야할때는?

contains(fromJSON('["refs/heads/feature/test", "refs/heads/feature/test2"]'), github.ref)

이런식으로 가능합니다.

 

주의 : runs-on에 따라 aws 명령어가 사용되지 않을 수 있습니다.

 

 

여기서부터는 불필요의 영역일 수 있습니다.

 


4. 버전관리, 이력관리, 히스트관리

  1. 만약 핫픽스로 급하게 새로이 올린 코드에 문제가 발생하거나 의도치 않은 동작으로 이전 코드로 되돌려야할 경우를 대비하여 현재 코드의 버전을 부여하여 git처럼 버전을 관리해야 할 경우
  publish_version:
    needs: deploy_source
    name: Publish version old lambda function
    runs-on: ubuntu-latest
    outputs:
      nv: ${{ steps.nv.outputs.NEW_VERSION }}
    steps:
      - name: Publish test
        id: nv
        if: github.ref == 'refs/heads/feature/test'
        run: |
          NEW_VERSION=$(aws lambda publish-version --function-name $DEV_FUNC_NM --description test2 --query Version --output text)
          echo "NEW_VERSION=$NEW_VERSION" >> "$GITHUB_OUTPUT"

      - name: Publish test2
        if: github.ref == 'refs/heads/feature/test2'
        run: aws lambda publish-version --function-name $DEV_FUNC_NM --description test2

outputs: > 추후 Lambda의 Alias 기능을 사용하면서 최신 버전을 자동으로 사용할 목적이라면 기입 :: run으로 동작한 코드의 결과값을 지역변수로 선언한다고 생각하시면 됩니다.

또한 여러개의 변수가 다른 작업에서 선언되어야 한다면 id: ~ 옵션을 이용하시면 됩니다.

 

needs: ~~~ > 선행되어야 하는 작업이 존재하며 해당 작업이 완료된 후에 실행이 되어야하는 작업이라면 위 정의된 name 부분을 기입해야합니다.

 

run: | > "|" 를 사용하여 여러행의 명령어를 실행. 터미널에서 "&&"과 비슷

+ 변수명=$(~~~) "$"와 "()"로 감싼부분은 --query 옵션에 선언된 변수를 찾아 --output옵션에 정의된 형태로 "변수명"에 저장됩니다.

 

5. Lambda의 Alias기능 사용을 위해 기존 Alias 정보 조회

  inquire_alias:
    needs: publish_version
    name: Inquire Alias Information
    runs-on: ubuntu-latest
    outputs:
      ov: ${{ steps.ov.outputs.OLD_VERSION }}
      nv: ${{ needs.publish_version.outputs.nv }}
    steps:
      - name: Inquire dev lambda alias information
        id: ov
        if: github.ref == 'refs/heads/feature/test'
        run: |
          OLD_VERSION=$(aws lambda get-alias --function-name $DEV_FUNC_NM --name dev --query FunctionVersion --output text)
          echo "OLD_VERSION=$OLD_VERSION" >> "$GITHUB_OUTPUT"

4번과 대부분이 비슷하며 outputs 부분에 위 선행된 작업의 변수를 참조하여 가져오기 위해

${{ needs.job_name.outputs.output_name }} 의 형태로 선언합니다.

 

6. Lambda Alias 추가 혹은 수정

  update_alias:
    needs: inquire_alias
    name: Update Alias Information
    runs-on: ubuntu-latest
    steps:
      - name: Update dev lambda alias information
        if: github.ref == 'refs/heads/feature/test'
        run: aws lambda update-alias --function-name $DEV_FUNC_NM --function-version ${{ needs.inquire_alias.outputs.ov }} --routing-config AdditionalVersionWeights={"${{ needs.inquire_alias.outputs.nv }}"=0.1} --name $DEV_ALIAS_NM

run: 부분을 보시게 되면 아래와 같은 옵션이 존재합니다.

--routing-config AdditionalVersionWeights={"${{ needs.inquire_alias.outputs.nv }}"=0.1}

위 코드는 0.1은 Alias 선언시 가중치를 선언하는 부분으로 해당 버전이 10%의 가중치를 갖도록 합니다.

 

안타깝게도 2개만 되고 3개 이상은 안되서 매우 아쉬워했습니다.....

 

반응형