GitHub Actions를 활용한 개발 효율화

Oh jeongseok
네이버 플레이스 개발 블로그
15 min readJun 7, 2023

--

Intro

안녕하세요. 스마트플레이스서비스개발 1팀의 오정석입니다.

네이버 예약·주문 팀에서는 올해 초부터 본격적으로 GitHub Actions를 활용해 개발 효율화를 꾀하고 있습니다.

초기에는 GitHub Actions를 단순히 예약·주문 리포지토리에 PR Lint test 실행을 목적으로 도입되었습니다.

이 과정에서 Runner 머신 구축 뿐 아니라 PR에 커밋이 추가될 때마다 테스트가 중복 실행된다거나, PR 본문이 바뀌어도 린트 테스트가 실행되는 등 개선이 필요한 부분이 존재했습니다. 이 같은 개선점을 수정하던 중 Lint test 외에도 개발 효율성을 높여줄 만 한 다양한 Action들을 찾게 되었고 도입을 검토해보게 되었습니다.

약 6개월 동안 적용해본 Action들과 작성한 workflow들을 예시로 도입 과정과 장점들을 공유드리고자 합니다.

GitHub Actions

GitHub Action 구조

GitHub Actions란 GitHub에서 제공하는 CI/CD 플랫폼입니다.

특정 리포지토리에 트리거 이벤트가 발생할 경우 GitHub Action Runner에서 워크플로우 파일에 작성해 둔 일련의 작업들을 실행하는 구조입니다.

워크플로우 실행환경을 가리키는 GitHub Action Runner의 경우 GitHub에서 자체 제공하는 가상머신인 GitHub-hosted Runner와 직접 사용자가 환경을 구성하는 Self-hosted Runner가 있습니다.

과도한 워크플로우들이 실행되는 머신이 아닐 경우 GitHub-hosted Runner는 무료(GitHub Actions 요금 정보)로 사용이 가능하기 때문에 간편한 도입을 위해서는 GitHub-hosted Runner를 사용하는 것이 좋습니다. 하지만 사내 리포지토리에 GitHub Actions를 도입하는 경우 Github-hosted Runner 머신에 사내 코드가 노출되는 보안적인 문제를 가지고 있기 때문에 Self-hosted Runner를 구축해서 사용해야 합니다.

GitHub Actions는 기존 CI/CD 도구들과 비교했을 때 GitHub 플랫폼 하나에서 모든 CI/CD 과정을 해결할 수 있다는 장점을 가지고 있습니다. Runner 머신 구축 이후, 리포지토리 .github/workflows 디렉토리에 워크플로우 YAML 파일을 작성하기만 하면 별도의 설치, 세팅 없이도 간편하게 기능을 사용할 수 있습니다.

Workflow

워크플로우 구문에 대해 간단하게 설명드리려 합니다. GitHub Actions로 어떤 작업들을 만들어낼 수 있을지 구상하기 위해서는 workflow 구문을 자유롭게 활용할 수 있어야 합니다.

name

# Lint test 워크플로우 이름 예시
name: 'lint-on-pr'
  • 작성하고 있는 workflow의 명칭을 지정할 수 있습니다. name 속성을 생략할 경우 리포지토리 “Actions” 탭에서 워크플로우 파일 상대경로로 표시되기 때문에 지정해서 사용하는 것이 좋습니다.

on

on: push # 단일 트리거 이벤트 : 커밋 푸쉬 이벤트 발생 시 워크플로우 실행
on: [push, fork] # 다중 트리거 이벤트
  • on 구문을 통해 워크플로우를 실행할 트리거 이벤트를 명시할 수 있습니다.
# 명시된 브랜치 목록들을 base branch로 하는 PR이 [생성, 재생성, head 브랜치 동기화, draft PR 리뷰 준비 완료] 이벤트 발생 시 워크플로우 동작
on:
pull_request:
branches:
- main
- develop
- feature/*
- release/*
- hotfix/*
types: [opened, reopened, synchronize, ready_for_review] # 해당 타입들은 github webhook payload 타입 목록을 따릅니다
  • on 구문은 단순한 트리거 이벤트 지원은 물론 워크플로우 실행 시기를 좀 더 세밀하게 제어하기 위해 옵션들을 적절히 제공하고 있습니다.
  • 위 코드는 네이버 예약·주문 리포지토리 Lint test 워크플로우의 on 구문입니다. 이처럼 on.<event_name>.type 형태로 구체적인 브랜치 필터, 이벤트 타입 등을 세부적으로 지정할 수 있습니다.
name: 'create-weekly-report-issue'
on:
schedule:
- cron: '0 8 * * THU' # 매주 목요일 17시에 수행
  • 이 뿐 아니라 Cron Expression을 이용해 스케쥴을 생성하고 주기적으로 워크플로우를 실행할 수도 있습니다.
on:
workflow_dispatch:
  • 이 외에도 on.workflow_dispatch 구문을 활용하면 특정 이벤트 없이도 리포지토리 Actions 탭에서 임의로 워크플로우를 실행시킬 수 있습니다.
workflow 수동 실행
  • workflow_dispatch 옵션을 작성한 워크플로우의 경우 위와 같이 Run workflow 버튼이 노출되고 수동 실행이 가능해집니다. 주로 워크플로우 실행 테스트를 진행하거나 수동 실행이 필요한 케이스의 동작에서 사용하기에 유용한 옵션입니다.

jobs

jobs:
first-job:
second-job:
needs: first-job
third-job:
needs: [first-job, second-job] # 조건부 실행
  • jobs 구문은 기본적으로 워크플로우에서 병렬적으로 실행되는 작업 단위를 의미합니다. 각 job들을 직렬, 조건부 실행하기 위해선 jobs.<job_id>.needs 옵션을 활용하면 특정 job이 실행 완료되었을 경우 다음 job을 실행하는 등의 동작도 가능합니다.

steps

jobs:
steps:
- name: first-step
- name: second-step
  • step은 job을 구성하는 하나의 작은 작업 단위를 의미합니다. steps는 jobs와 달리 순차적으로 실행되며 서로 의존적입니다. 우리는 이 step 단위로 Action들과 스크립트를 실행하며 원하는 작업들을 구성하게 됩니다.

GitHub Contexts

워크플로우 작성법을 살펴보면서 GitHub Actions 도구는 설정이 손쉽고 이벤트 트리거를 보다 세부적으로 제어할 수 있다는 장점을 확인할 수 있었습니다.

여기서 다음으로 소개할 GitHub Contexts를 활용하면 우리는 현재 워크플로우의 상태와 이벤트에 대한 정보들에 손쉽게 접근할 수 있게 됩니다.

이는 워크플로우를 구성할 때 조건부를 다양하게 구성하고 특정 환경에 맞게 동작을 세팅할 수 있어 워크플로우를 더욱 유연하게 관리할 수 있게 해줍니다.

GitHub Contexts의 경우 그 종류가 매우 다양하여 모두 살펴보기에는 양이 많습니다. 필요한 컨텍스트는 때에 따라 GitHub Docs를 참조하면 좋습니다. 이번 공유에서는 실제로 네이버 예약·주문의 워크플로우에서 활용한 컨텍스트들을 예시로 살펴보고자 합니다.

# PR 자동 승인 동작을 수행하는 step
steps:
- name: auto approve
uses: place-actions/auto-approve-action@v3
with:
pull-request-number: ${{ github.event.number }}
github-token: ${{ secrets.GITHUB_TOKEN }}

예약·주문에서는 git flow 브랜치 전략에 따라 main 브랜치에 PR이 머지되면 develop 브랜치 현행화를 위해 자동으로 develop <- main PR이 생성되고 있습니다. 해당 PR은 별도의 리뷰 없이 바로 머지해도 되는 케이스임에도 2명의 PR 승인을 강제하고 있어 번거로움이 존재했습니다. 이를 해결하기 위해 GitHub bot이 자동으로 승인을 처리하는 auto-approve-action을 워크플로우에 활용하고 있습니다.

여기서 파라미터로 넘기는 코드를 보면 두 개의 GitHub context를 활용하고 있습니다. github.event.number의 경우 현재 이벤트에 연결된 이슈, PR의 넘버를 의미합니다. 또 대부분의 Action 인증에 활용되는 secrets.GITHUB_TOKEN은 워크플로우에서 리포지토리 정보를 얻어오는 GitHub API를 호출할 때 권한을 제공해줍니다.

secrets.GITHUB_TOKEN을 Personal access token(PAT)과 동일한 것으로 오해할 수 있지만 두 토큰 간에는 차이점이 있습니다. 우선 Personal access token의 경우 유저가 직접 생성하고 관리해야 하지만 secrets.GITHUB_TOKEN의 경우 워크플로우가 실행될 때 자동으로 생성되며 워크플로우 종료 후 제거되는 토큰입니다. 따라서 워크플로우 내부에서 인증 권한이 필요할 경우 개인 토큰을 코드에 삽입하지 않고 secrets.GITHUB_TOKEN을 사용하는 것이 편의성과 보안성을 따져보았을 때 바람직한 방법입니다. 추가적으로 secrets.GITHUB_TOKEN은 워크플로우 실행 리포지토리 범위 내에서만 권한을 가지고 있기 때문에 다른 리포지토리에 대한 접근은 제한됩니다.

# 일본 예약 리포지토리 강제 푸쉬 워크플로우 : 일본, 한국 두 개의 저장소를 모두 관리해야 하는 번거로움을 줄이기 위해 한국 리포지토리에 코드 머지 시 일본 리포지토리에 자동 푸쉬하기 위한 워크플로우
steps:
- name: Connect vpn # 일본 GitHub Enterprise 접속을 위한 VPN 연결
env:
PASSWORD: ${{ secrets[env.VPN_USER_UPPER] }}

secrets 컨텍스트는 secrets.GITHUB_TOKEN 외에도 리포지토리의 Settings > Secrets 탭의 암호화된 환경 변수 값에 접근이 가능합니다.

secrets 컨텍스트를 활용한 예시를 보면 일본 리포지토리 자동 푸쉬 워크플로우 과정에서 vpn 접속을 위해 Secret 변수로 저장되어 있는 password 값에 접근하는 코드를 살펴볼 수 있습니다.

jobs:
push-to-jp:
env: # step 코드 작성 전 재사용될 만한 환경 변수 값들 선언
OSS_SENDER: ${{ github.event.sender.login }} # github.event.sender.login : 현재 이벤트를 트리거한 github 유저 이름을 의미하는 컨텍스트
TARGET_BRANCH: ${{ github.ref_name }} # github.ref_name : 현재 타겟 브랜치명을 얻어오는 컨텍스트
JP_REPO: {일본 GitHub Enterprise 리포지토리 이름 기입}
JP_VPN_URL: {VPN 접속 URL 기입}
JP_URL: {일본 GitHub Enterprise URL 기입}

일본 예약 리포지토리 자동 푸쉬 워크플로우를 이어서 보겠습니다. 해당 워크플로우 코드를 보면 env 컨텍스트를 활용해 각 step에서 재사용되는 환경 변수를 선언하고 있는 것을 확인 할 수 있습니다. 이처럼 환경 변수를 선언해서 사용하게 되면 반복되는 값들을 재작성할 필요가 없어지며 조건부 구문에서 활용도가 높습니다.

컨텍스트의 항목을 일일이 알아둘 순 없지만 우리는 GitHub Contexts를 적절히 활용하면 워크플로우의 동적인 작업 흐름을 만들어내기 용이해집니다.

또 GitHub Contexts는 일일이 GitHub API를 호출하여 리포지토리 정보를 얻어와야 하는 번거로움을 가볍게 해소하며 GitHub 플랫폼 하나에서 모든 CI/CD 과정을 해결할 수 있게끔 큰 도움을 주는 역할을 합니다.

GitHub Actions Marketplace

GitHub Actions의 가장 큰 장점은 활발한 커뮤니티 생태계가 형성되고 있는 Marketplace입니다.

GitHub Actions Marketplace는 개발자들이 자신의 액션을 공유할 수 있는 온라인 상점입니다. 이 액션들을 적절하게 사용하면 필요한 기능을 직접 구현할 필요없이 간편하게 액션을 적용시켜 원하는 작업을 이어갈 수 있습니다.

또한 Marketplace의 액션들은 GitHub의 검토 및 승인을 바탕으로 제공하고 있기 때문에 품질과 보안성이 어느정도 보장되는 장점 또한 가지고 있습니다.

# develop <- main 브랜치 현행화 PR의 자동 승인 및 머지 준비 완료 알림 기능을 수행하는 워크플로우
jobs:
update-develop:
steps:
- name: auto approve
uses: place-actions/auto-approve-action@v3
with:
pull-request-number: ${{ github.event.number }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: place-actions/wait-for-green@v1.1.1 # 해당 PR의 status-check 완료 여부를 판단해주는 Action
id: wait-for-status
with:
token: '${{ secrets.GITHUB_TOKEN }}'
ignored_checks: 'update-develop'
max_attempts: 60
- name: Create ready-to-merge comment
uses: public-actions/create-or-update-comment@v2 # 특정 PR, issue에 코멘트를 달아주는 Action
with:
issue-number: ${{ github.event.number }}
body: |
@${{ github.actor }}
**"Update develop from main" PR 머지 준비가 완료되었습니다 ! !**
if: steps.wait-for-status.outputs.success == 'true'

예약·주문 리포지토리 git flow 브랜치 전략 효율화를 위한 update-develop-from-main.yml 워크플로우를 예시로 살펴보겠습니다.

해당 코드는 특정 PR의 status check 완료 여부를 확인하고 코멘트를 남겨주는 동작을 포함하고 있는 워크플로우입니다.

만약 Marketplace의 Action을 활용하지 않고 해당 기능을 GitHub API 호출 스크립트로 구성하려 한다면 생각보다 귀찮은 작업이 진행되어야 할 것입니다.

하지만 간편하게 wait-for-green, create-or-update-comment 두 가지의 마켓플레이스 액션들을 활용하여 쉽게 해결한 모습을 확인할 수 있습니다.

단, 외부 마켓플레이스의 github action들은 세팅없이 바로 GitHub Enterprise에 적용되지 않는 경우가 있습니다.

GitHub Enterprise에서는 보안상의 이유로 checkout과 같은 github 공식 액션 외의 마켓플레이스 액션들을 github.com과 아웃바운드 커넥션 없이는 사용할 수 없습니다.

그래서 현재 네이버 사내 GitHub에서는 GitHub 공식 Actions 외 Marketplace 대부분의 액션을 사용하기 위해선 별도의 클론 과정이 필요합니다.

실제로 이렇게 클론해온 Actions들은 네이버 전사적인 측면에서 하나의 그룹에서 관리되고 있습니다. 이를 통해 외부 Action들이 중복 복제되어 사용되지 않고 통합 관리되고 있습니다.

외부 액션을 복제해오는 경우엔 물론 보안성 검토도 필요합니다. 대부분의 액션들은 octokit과 같은 GitHub API 호출용 라이브러리만을 활용해 동작을 구성하고 있는 경우가 많기 때문에 불필요한 별도 패키지의 사용 여부를 잘 판단하시고 도입을 진행하시는 것이 좋습니다.

마켓플레이스 액션들을 사용하다 보면 내 입맛에 맞게 커스터마이징이 필요한 경우도 있습니다. 이럴 경우 코드에 직접 컨트리뷰션하거나 마켓플레이스에 내가 필요한 액션을 직접 구현해보는 것도 GitHub Action 생태계 활성화에 기여해보는 흥미로운 경험이 될 것입니다.

마치며

앞서 살펴본 것처럼 GitHub Actions은 GitHub 플랫폼 내부에서 모든 CI/CD를 해결할 수 있을 뿐 아니라 커뮤니티 생태계가 잘 형성되어 있는 큰 장점을 가지고 있는 서비스입니다.

워크플로우 작성이 매우 간단하기 때문에 Runner 머신만 세팅되어 있다면 누구나 짧은 시간 안에 도입이 가능합니다.

단순한 CI/CD 동작 뿐 아니라 마켓플레이스를 살펴보다 보면 번거롭게 개발자의 작업이 들어가야 했던 저장소 관리 작업들이 몇 개의 액션 조합을 통해 놀랍도록 간편한 자동화를 실현할 수 있습니다. 실제로 네이버 예약·주문에서도 불필요하게 오픈되어 있는 이슈를 정리한다거나 주간보고 이슈 생성, PR 라벨링 등의 작업들을 GitHub Action을 통해 자동으로 관리하고 있습니다.

아직 팀에서 GitHub Action을 도입하지 않았거나, 단순한 작업들만 워크플로우로 구성되어 있다면 이번 기회에 GitHub Action을 활용하여 다양한 개발 효율화 작업을 고민해보는 것은 어떨까요?

--

--