8 min read

깃헙 액션으로 경계가 명확한 CI/CD 파이프라인 구현하기

Justin Yoo

지난 포스트에서는 깃헙 액션의 기본적인 사항들을 이용해서 워크플로우를 만들어 봤다. 이 포스트에서는 이를 좀 더 응용해서 빌드와 배포를 분리시켜보자.

이 포스트에서 사용한 샘플 코드는 이 깃헙 리포지토리에서 다운로드 받을 수 있다.

빌드와 배포 분리하기

지난 포스트에서 언급한 바와 같이 가장 기본적인 네 가지 개념 – 워크플로우, 이벤트, 러너, 액션만 알면 깃헙 액션을 사용할 수 있다. 그런데, 빌드와 배포를 분리하기 위해서는 이라는 추가적인 개념을 알아두면 좋다. 러너액션의 논리적인 묶음인데 워크플로우 안에서 여러 개의 을 정의하고 이를 동시에 실행시키거나 연속적으로 실행시키거나 하는 등의 설정을 할 수 있다.

아래 워크플로우는 지난 포스트에서 작성한 것이다. jobs 속성 아래 build_and_publish 라는 이름으로 을 정의한 것이 보인다.

name: Publish Static Web App to Azure Blob Storage
on: push
jobs:
build_and_publish:
runs-on: ubuntu-latest
steps:
- name: Checkout the repo
uses: actions/checkout@v1
- name: Login to Azure
uses: Azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Install npm packages
shell: bash
run: |
cd $GITHUB_WORKSPACE/src/WebApp
npm install
- name: Build app
shell: bash
run: |
cd $GITHUB_WORKSPACE/src/WebApp
npm run build
- name: Test app
shell: bash
run: |
cd $GITHUB_WORKSPACE/src/WebApp
npm run test:unit
- name: Publish app
uses: Azure/cli@v1.0.0
with:
azcliversion: latest
inlineScript: |
az storage blob upload-batch -s $GITHUB_WORKSPACE/src/WebApp/dist -d \$web --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }}

빌드 잡 재정의

맨 마지막 액션이 Publish app인데, 사실 이 부분은 배포를 위한 직전 단계로서 아티팩트를 업로드하는 것으로 바꾸는 것이 좀 더 정확하다. 따라서, 이 부분을 아래와 같이 바꿔 보도록 하자. 여기서 사용한 액션은 upload-artifact이다. 아티팩트 이름을 app으로 지정했다.

- name: Upload app
uses: actions/upload-artifact@v1
with:
name: app
path: src/WebApp/dist

이렇게 수정한 후 워크플로우 파일을 깃헙으로 푸시하면 빌드가 돌아가고 마지막 단계에서 애저 블롭 저장소로 배포하는 대신, 아티팩트를 파이프라인상에 생성한다.

이렇게 해서 기존의 빌드에 해당하는 을 새로 정의했다. 이제 여기서 업로드한 아티팩트를 이용해서 배포를 하는 잡을 만들어 보자.

배포 잡 정의

애플리케이션 배포 시나리오는 상당히 다양하다. 아주 간략한 시나리오를 예상한다면 크게 다음과 같은 두 가지 시나리오가 가능할 것이다. 첫번째 시나리오는 빌드/테스트가 끝난 후 연속적으로 개발 환경, 테스트 환경, 라이브 환경으로 배포하는 방식이고, 두번째 시나리오는 빌드/테스트가 끝난 후 동시에 개발 환경, 테스트 환경, 라이브 환경으로 배포하는 방식이다.

첫번째 시나리오에서는 개발 환경 배포 은 직전 단계인 빌드/테스트 에 의존성을 가지고, 테스트 환경 배포 은 개발 환경 배포 에, 라이브 환경 배포 은 테스트 환경 배포 에 의존성을 갖는다. 다른 말로 하면 직전 이 실패할 경우에는 이어지는 은 더이상 실행되지 않는다. 따라서 워크플로우를 정의할 때 의존성 선언을 아래와 같이 정의하면 된다.

...
jobs:
build_and_publish:
runs-on: ubuntu-latest
...
deploy_to_dev:
needs: build_and_publish
runs-on: ubuntu-latest
...
deploy_to_test:
needs: deploy_to_dev
runs-on: ubuntu-latest
...
deploy_to_prod:
needs: deploy_to_test
runs-on: ubuntu-latest
...

반면에 두번째 시나리오는 개별 배포 환경은 오로지 빌드/테스트 에만 의존성을 갖는지라 개별 배포 환경은 서로 의존성을 갖지 않는다. 따라서 워크플로우를 정의할 때 의존성 선언을 아래와 같이 정의하면 된다.

...
jobs:
build_and_publish:
runs-on: ubuntu-latest
...
deploy_to_dev:
needs: build_and_publish
runs-on: ubuntu-latest
...
deploy_to_test:
needs: build_and_publish
runs-on: ubuntu-latest
...
deploy_to_prod:
needs: build_and_publish
runs-on: ubuntu-latest
...

이 포스트에서는 두 개의 정적 웹사이트로 배포한다. 여기서는 추가로 download-artifact 액션을 사용했다.

- name: Download app
uses: actions/download-artifact@v1
with:
name: app
path: src/WebApp/dist

이 액션을 바탕으로 아래와 같이 deploy_to_devdeploy_to_prod를 정의한다.

deploy_to_dev:
needs: build_and_publish
runs-on: ubuntu-latest
steps:
- name: Download app
uses: actions/download-artifact@v1
with:
name: app
path: src/WebApp/dist
- name: Login to Azure
uses: Azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Publish app
uses: Azure/cli@v1.0.0
with:
azcliversion: latest
inlineScript: |
az storage blob upload-batch -s $GITHUB_WORKSPACE/src/WebApp/dist -d \$web --account-name ${{ secrets.STORAGE_ACCOUNT_NAME }}
deploy_to_prod:
needs: deploy_to_dev
runs-on: ubuntu-latest
steps:
- name: Download app
uses: actions/download-artifact@v1
with:
name: app
path: src/WebApp/dist
- name: Login to Azure
uses: Azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Publish app
uses: Azure/cli@v1.0.0
with:
azcliversion: latest
inlineScript: |
az storage blob upload-batch -s $GITHUB_WORKSPACE/src/WebApp/dist -d \$web --account-name ${{ secrets.STORAGE_ACCOUNT_NAME_2 }}

여기서 명심해야 할 부분이 한가지 있는데, 개별 은 각자의 러너 위에서 돌아가고 이 끝나면 러너 역시 삭제된다. 이 말인 즉슨, 직전 에서 애저 로그인을 했다고 해서 그 로그인 상태가 다음 으로 이어지지 않는다. 따라서, 위 워크플로우 정의와 같이 개별 마다 애저 로그인 액션을 선언해 줘야 한다.

이렇게 새롭게 정의한 워크플로우 파일을 푸시한 후 결과를 보자. 아래는 첫번째 빌드/테스트 실행 결과이다.

그리고 아래는 마지막 deploy_to_prod 실행 결과이다.

여기서는 deploy_to_dev deploy_to_prod 안에서 오직 아티팩트를 다운로드 받고 배포하는 액션만 있지만, 상황에 따라 개별 마다 좀 더 다른 액션을 추가할 수도 있다. 예를 들어 통합 테스트라든가 종단간 테스트라든가 하는 것들이 될 수도 있는데, 이는 좀 더 풍부한 비지니스 요구사항과 시나리오에 따라 얼마든 추가될 수 있는 요소이기도 하다.


지금까지 깃헙 액션을 통해 단계별로 을 분리해서 CI/CD 파이프라인 안에서 명확한 책임의 경계를 만드는 방법에 대해 알아 보았다.