Github Action의 Triggering을 이용한 간단한 CI 구성해보기

Dahun Yoo·2021년 9월 13일
3

Lessons learned

목록 보기
4/16
post-thumbnail

Github Action과 Github API를 이용하여 Trigger를 구성하고, 이를 통해 간단한 CI 구축해봅니다!


Github에는 Github Action 이라는, Github repository를 기반으로 일정한 Workflow를 자동화할 수 있는 툴이 있습니다. 각 repository에 들어가면 상단 탭에서 확인할 수 있습니다.
이 것을 이용하여 Github의 특정 branch에 push하면, unit test를 실행한다거나, 빌드하여 원하는 서버로 업로드한다거나 하는 것을 자동화할 수 있습니다.

오늘은 기존에 작성해놓은 API Server 토이프로젝트를, Heroku 서버로의 deploy 후 API Test까지 자동으로 실행하는 흐름을 만들어보고자 합니다.

Workflow

제가 원하는 흐름은 아래와 같습니다.

1. Local에서 작업후 에 Github master 브랜치에 push를 하면,
2. heroku에 다시 push를 해주고, push가 완료되면
3. Test code가 있는 다른 repository로 POST API를 호출하여
4. 해당 repository의 Github action을 이용해 heroku에 배포되어있는 서버 코드에 대해 API Test를 실행

하는 흐름입니다.


repository_dispatch Event that trigger Github action

Github action를 발동시키는 트리거에는 몇가지가 있습니다. 일단 널리 알려진대로는 push, pull request, 그리고 schedule 이 있습니다. 이 이벤트들이라면 대부분의 경우에 대응할 수 있긴할 것 입니다. 그러나 외부에서의 다른 이벤트를 이용해 Github action을 실행시키고 싶을 수 있을텐데요, 이럴 때 사용하는 것이 repository_dispatch (Github webhook의 한 종류)입니다.
위 이벤트를 발동시키기 위해서는, 아래 endpoint로 POST Request를 보내야합니다.

https://api.github.com/repos/:owner/:repo/dispatches

위 Endpoint는, 특정 repository로 repository_dispatch를 발생시키는 endpoint이긴 합니다만, 만일 위 endpoint를 이용한 여러개의 Github action이 있다면 event_type 이라는 파라미터를 이용하여 구분해야할 필요가 있습니다.

상세 파라미터는 아래와 같습니다.

NameTypeInDescription
AcceptstringheaderSetting to application/vnd.github.v3+json
ownerstringpath
repostringpath
event_typestringbodyRequired. A custom webhook event name
client_payloadobjectbodyJSON payload with extra information about the webhook event that your action or workflow may use.

https://docs.github.com/ja/rest/reference/repos#create-a-repository-dispatch-event

저는 Github A repo의 Github action에서 curl을 이용하여 해당 endpoint로 request를 날려 실행시키고자 합니다.


Build Github action trigger

일단 A repo와 B repo에 각각 test용 action을 만들고, 그 이후 heroku 배포용 action도 추가해보겠습니다.

1. Create Access token


Github에서 프로필 사진을 누르고, Settings로 이동합니다.


이후 좌측 메뉴에서 Developer settings 를 선택하시고 Personal access tokens 를 발급받습니다.
이미 Github로의 push를 이용하기 위해 토큰을 발급받으셨다면, 그것을 이용하셔도 되고 새로 발급받으셔도 됩니다.

발급하실 때의 권한 설정은 아래 정도를 해주셔도 될 것 같습니다.
admin:repo_hook, repo, workflow

이렇게 발급 받으신 토큰은 어딘가 안전한 곳에 복사해서 붙여넣기해놓습니다.

2. Setting access token repository

Endpoint를 실행할, A repo에 Access token 정보를 입력해야합니다.

Repo의 Settings에서 Secrets로 이동하시면, 각종 중요정보를 입력할 수 있는 창이 뜹니다. 여기에 ACESS_TOKEN 으로 입력합니다. (사실 key값은 편하신대로 입력하시면 됩니다.)
value값으로는 username:token 의 형태로 입력합니다.

3. Create Github action on B Repository

일단 A repo의 action은 master branch에 push할 때 마다 실행시킬 것이므로, 먼저 trigger당하는 B repo의 action을 생성해보겠습니다.

일단 만드는 방법은 다른 분들께서도 잘 작성해주셔서 생략하나.. 적당히 어느 한 분의 글을 링크해드립니다.

https://jonnung.dev/devops/2020/01/31/github_action_getting_started/

# /.github/workflows/~~.yml 
# 파일명은 임의이며, Github repository에서 action을 만들 경우,
# 보통은 branch이름으로 생성됩니다.
name: Triggering test

on:
  repository_dispatch:
    types: [TRIGGER_API_TEST]
    #repository_dispatch가 발생할 때, 이 Action이 실행됩니다.
    #여기서 types란, 위에서 설명한 endpoint의 payload의 event_type입니다.
    #받는 쪽에서 지정한 특정 event_type을 가진 request가 있다면, 실행합니다.
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Check Github action trigger
        run:  |
          echo "Event '${{ github.event.action }}' received from '${{ github.event.client_payload.repository }}'"

일단 간단하게, Trigger를 받아 실행된 action에서 간단한 문자열을 출력해보도록 합니다.
여기서 action 이란 event_type을 뜻하고, client_payload 는 제가 임의로 보내는 데이터를 의미합니다.

4. Create Github action A repository

다음으로는 A Repo에서의 action을 생성해봅니다.

name: Deploy to heroku
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      # Trigger Test repository   
      - name: Send Trigger
        run: |
          curl -X POST https://api.github.com/repos/:owner/:repo/dispatches \
          -H 'Accept: application/vnd.github.v3+json' \
          -u ${{ secrets.ACCESS_TOKEN }} \
          -d '{"event_type": "TRIGGER_API_TEST", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}'

A 에서 curl 을 사용하여 trigger를 발생시켜줍니다.

  • :owner 에는 Github username
  • :repo 에는 B repository의 이름

을 기재하면 됩니다.
여기서 secrets.ACCESS_TOKEN 이, 나중에 실행하면 2. Setting access token repository 에서 등록한 ACCESS_TOKEN 값이 들어가게 됩니다.

이후 local에서 작업하셨다면 Github로 push하시거나, Github에서 직접 action을 작성하셨다면 commit change 하시면 기본적으로 mastermain branch로 커밋될 것이고, Action에 정의한 on 조건으로 인하여 자동으로 실행될 것 입니다.

5. Check execution result

A repository action


B repository action

잘 실행되는 것을 확인할 수 있었습니다.


6. ADD Heroku deploy action on A Github action

잘 동작하는 것을 확인하였으니, 저의 원래 목적인 Heroku 배포 액션을 추가해봅니다.

Github action marketplace에 올라와있는 heroku-deploy 을 사용해 보았습니다.

https://github.com/AkhileshNS/heroku-deploy

name: Deploy to heroku
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
    #########################
      - name: Deploy to Heroku
         uses: AkhileshNS/heroku-deploy@v3.12.12
         with:
           heroku_api_key: ${{secrets.HEROKU_API_KEY}}
           heroku_app_name: "practice-flask-restful-dh"
           heroku_email: ${{secrets.HEROKU_EMAIL}}
    #########################
      # Trigger Test repository   
      - name: Send Trigger
        run: |
          curl -X POST https://api.github.com/repos/:owner/:repo/dispatches \
          -H 'Accept: application/vnd.github.v3+json' \
          -u ${{ secrets.ACCESS_TOKEN }} \
          -d '{"event_type": "TRIGGER_API_TEST", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}'

HEROKU_API_KEYHEROKU_EMAIL 역시 A repo의 Secret에 등록해주었습니다.
Action은 기본적으로 위에서 아래로 실행되기 때문에, 각각의 step의 순서를 고려해야합니다. 저는 배포가 완료되면, 그 다음 trigger를 발동시켜야 하므로 Trigger의 전 단계에 기재하였습니다.

7. ADD command on B Github action

# /.github/workflows/~~.yml 
# 파일명은 임의이며, Github repository에서 action을 만들 경우,
# 보통은 branch이름으로 생성됩니다.
name: Triggering test

on:
  repository_dispatch:
    types: [TRIGGER_API_TEST]
    #repository_dispatch가 발생할 때, 이 Action이 실행됩니다.
    #여기서 types란, 위에서 설명한 endpoint의 payload의 event_type입니다.
    #받는 쪽에서 지정한 특정 event_type을 가진 request가 있다면, 실행합니다.
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Check Github action trigger
        run:  |
          echo "Event '${{ github.event.action }}' received from '${{ github.event.client_payload.repository }}'"
      - name: Set up JDK 14
        if: github.event.action == 'TRIGGER_API_TEST'
        uses: actions/setup-java@v1
        with:
          java-version: 14
      - name: Test project with Maven
        run: mvn test    
           

저는 API Test code를 JAVA 로 작성하였고, dependency관리로 maven 을 사용하였기에 관련 내용을 작성해주었습니다.
참고로 중간에 if문이 보이는데, on 에서 조건을 명시하지 않아도, if 를 이용하여 특정 조건인 경우에 실행할 step도 나누어줄 수 있습니다.

mvn test 를 이용하여 관련 library의 설치 및 테스트까지 한 번에 실행합니다.

8. Check B Action executed result

이제 A를 push한 후 B Action의 실행결과를 확인합니다.

A result

Heroku 배포하는데에 46초가 걸렸습니다.
저는 Unit test code를 작성하지 않았지만, 배포 전 단계에서 build후 Unit test 실행 후 배포의 흐름을 만든다면 더욱 완벽할 것 같습니다.

B result

Build 및 Test단계에서, API Testcode의 build 후 Test완료까지 16.365 초가 소요되었고, 해당 step종료는 총 19초 가 걸린 것을 알 수 있습니다.

Summary

간단하게 Github Action을 이용하여 API server의 배포 및 API Test까지 실행해보았습니다. 혼자서 포트폴리오를 만드려하니, Circle CITravis CI 는 결제를 해야하거나 체험판기간이 있어서 조금 부담되더라구요.
어쩌다보니 공부 차 AWS EC2에 Jenkins를 설치해놓은 Instance가 있긴한데, 이번에는 Github action을 사용하게 되었습니다.
yaml 파일에 정의해주는 방법도 공부할 수 있어서 좋았습니다.
Jenkins를 이용하면 각종 Add-on 들 덕분에 이쪽도 쉽게했을지도 모르겠습니다만...

이번 포스트를 통해서 API test code를 이용한 Integration Test까지 실행해보았습니다. 이후에 Marketplace의 여러 action을 이용하여 Test결과 혹은 Action실행 결과등을 Slack이나 Email로 받아볼 수 있으면 좋을 것 같습니다.
IT가 완료되면 Production Server로의 배포까지 실행시켜, CI/CD 환경 또한 구축해볼 수 있을 것 같습니다.
(Dev -> UT/IT 실행 -> QA 서버로의 연속적인 배포라던지)


Ref.

profile
QA Engineer

5개의 댓글

comment-user-thumbnail
2021년 9월 13일

유익한 글이네요. 잘 읽었습니다.

1개의 답글
comment-user-thumbnail
2021년 10월 22일

안녕하세요? 혹시 workflow 작성 툴 어떤거 사용하시나요? 상당히 깔끔한 것 같아서

1개의 답글