2024. 5. 22. 23:09ㆍProgramming/Infra Structure
목차
- 목적
- CI 빌드 살펴보기
ci.yml
파일에서 불필요한 과정 찾기Prisma ORM Setting
Install Package
- 최종적으로 완성된
ci.yml
파일
- RECOMMEND FOR YOU & REFERENCE
목적
내가 직접 인프라를 관리하고 배포를 하는 등의 DevOps 작업을 한 건 이번 프로젝트가 처음이었다.
그런데 이상하리라만치 배포 속도가 느렸고, 이를 개선하고자 한다.
CI 빌드 살펴보기
우선 현재 사용중인 CI 빌드의 yml
파일을 살펴보자.
name: CI
on:
pull_request:
branches:
- dev
- prod
jobs:
ci-build:
runs-on: ubuntu-20.04
steps:
- name: checkout
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: install package manager - pnpm
run: npm install -g pnpm
- name: env set
working-directory: ./
run: |
touch .env
echo POSTGRESQL_DB_URL=${{secrets.POSTGRESQL_DB_URL}} >> .env
echo JWT_PRIVATE=${{secrets.JWT_PRIVATE}} >> .env
echo JWT_SECRET=${{secrets.JWT_SECRET}} >> .env
echo PORT=${{secrets.PORT}} >> .env
echo SALT=${{secrets.SALT}} >> .env
echo ORIGIN=${{secrets.ORIGIN}} >> .env
- name: Install package
run: pnpm i
- name: prisma set
run: |
npx prisma db push
npx prisma migrate deploy
npx prisma generate
- name: Test unit
run: pnpm test:prod
# - name: Test E2E
# run: pnpm test:e2e
- name: test
run: |
pnpm build
timeout ${{ vars.SLEEP }} nohup node dist/main.js > app.log || code=$?; if [[ $code -ne 124 && $code -ne 0 ]]; then exit $code; fi
cat app.log
dev
또는 prod
브랜치에서 PR이 등록될 때마다 실행된다.
ubuntu 20.04
버전에서 실행되며, node-version
은 20으로 가져간다.
pnpm
을 설치하고, .env
파일을 생성해 환경변수를 설정한 다음 패키지 설치와 ORM 세팅을 진행한다.
마지막으로 가장 중요한 테스팅을 3단계에 거쳐 실행한다.
첫 번째로는 단위 테스트를 실행하고, 두 번째로는 통합 테스트를 실행한다 (다만 통합 테스트 코드는 아직 작성하지 못하였으므로 실행할 수 없어 주석처리해두었다).
마지막으로는 실제 실행을 하고, 일정 시간 (GH Action 환경변수로 등록해두었다) 이후 자동으로 종료한 이후 로그를 출력하도록 설정했다.
ci.yml
파일에서 불필요한 과정 찾기
어디서 어떤 작업을 하느라 시간이 오래 걸리는 걸까?
가장 오래 걸렸던 작업을 찾아보자.
최근 실행된 작업 6개를 기준으로 살펴보았을 때, 평균 실행 시간이 1.5초 이상인 작업의 평균 실행시간은 다음과 같았다.
Prisma ORM Setting
: 14.5sec / 최대 17secExecute Test
: 14.3sec / 최대 15secUnit Test
: 7.6sec / 최대 8secInstall Package
: 6.8sec / 최대 7secSet Up Node.js
: 1.8sec / 최대 5secInstall Package Manage - pnpm
: 1.6sec / 최대 2sec
yml
파일만으로 줄일 수 있는 부분은 Prisma ORM Setting
, Install Package
정도라고 생각한다.
Prisma ORM Setting
prisma orm setting
step을 좀 더 자세히 살펴보자.
npx prisma db push
npx prisma migrate deploy
npx prisma generate
- db를
prisma
에 동기화하고, - deploy 환경에서 동기화를 진행한 후
prisma/client
를 생성하는 방식이다.
효율적으로 진행하려면 어떻게 해야할지 몇 가지 고민을 해보았다.
그때 이런 생각이 들었다. 굳이 동기화를 해야 할까?
prisma/client는 매번 생성해주어야 하는 것이 맞지만, 동기화는 크게 필요 없다고 생각한다.
로컬 환경에서 사용할 수 있는 act로 테스트를 진행한 후 GH Action에 PR을 올렸다.
결과적으로 해당 부분을 커밋하였을 때, 약 7초 (기존 대비 12% 가량) 정도의 실행 시간 감소가 일어났다.
괄목할 만한 성과이다.
Install Package
Install Package
step을 보자. (중간의 .env
세팅은 제외하였다)
- name: install package manager - pnpm
run: npm install -g pnpm
- name: Install package
run: pnpm i
이 코드를 보면서 나는 두 가지 고민을 했다.
첫 번째는 "굳이 패키지 매니저와 패키지 설치를 따로 나누어야 할까?"라는 고민이었고,
두 번째로는 "패키지를 매 번 새로 설치해야 할까?"라는 고민이었다.
pnpm
을 사용하는 이유 중 하나가 중복으로 설치를 하지 않아서 때문이었는데, 그 장점이 상쇄되는 느낌이 들었다.
때문에 GH Action에서 캐싱을 할 수 있는 방법을 찾아보던 중 actions/cache@v3
패키지를 찾을 수 있었다. (Reference 참조)
해당 액션을 사용하여 node_modules
를 캐싱하고, 일치할 경우 굳이 설치하지 않음으로써 설치에 드는 시간을 줄일 수 있다.
다음과 같이 코드를 작성해 액션을 사용하였다.
- name: Caching dependencies
id: cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{runner.os}}-node-${{ hashFiles('**/package-lock.json')}}
restore-keys: |
${{ runner.os }}-node-
${{ runner.os }}
- name: Install package
if: steps.cache.outputs.cache-hit != 'true'
run: |
npm install -g pnpm
pnpm i --frozen-lockfile
Caching dependencies
에서 \*\*/node\_modules
에 있는 파일들을 캐싱하고, key는 ${{ runner.os }}-node-${{ hashFiles('\*\*/pnpm-lock.json') }}
로 지정한다.
restore-keys
에서는 ${{ runner.os }}-node 또는 ${{ runner.os }}
를 prefix로 포함하는 키가 있는지 확인하고, 일치하는 키가 있을 경우 가장 최근의 캐시를 가져온다.
해당 부분을 수정 후 올렸는데, 첫 캐싱이라 그런지 시간이 조금 더 걸렸다.
그렇다면 다른 부분을 수정하고 다시 올린다면 전체적인 시간이 줄어들까?
run all-job rerunning
을 통해 모든 작업을 재실행했다.
그리고 실패했다.
아니 도대체 왜...? 라고 묻고 싶었지만, pnpm
은 글로벌로 설치한 탓에 캐싱이 안되는 모양이었다.
일반 설치를 시도해봤지만 여전히 실패하고, 결국 pnpm
은 따로 깔기로 했다...
그렇게 yml
파일을 수정하고 다시 한 번 커밋하여 캐싱의 위력을 확인해본 결과
2초 가량 줄였다!
prisma
빌드 작업을 최소화하여 줄였을 때 대비해서는 약 4%, 최적화되지 않았던 빌드 대비해서는 15% 이상 절감한 셈이다.
완성한 ci.yml
파일
name: CI
on:
pull_request:
branches:
- dev
- prod
jobs:
ci-build:
runs-on: ubuntu-20.04
steps:
- name: checkout
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: install pnpm
run: npm i -g pnpm
- name: Caching dependencies
id: cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{runner.os}}-node-${{ hashFiles('**/pnpm-lock.json')}}
restore-keys: |
${{ runner.os }}-node-
${{ runner.os }}
- name: Install package
if: steps.cache.outputs.cache-hit != 'true'
run: pnpm i --frozen-lockfile
- name: env set
working-directory: ./
run: |
touch .env
echo POSTGRESQL_DB_URL=${{secrets.POSTGRESQL_DB_URL}} >> .env
echo JWT_PRIVATE=${{secrets.JWT_PRIVATE}} >> .env
echo JWT_SECRET=${{secrets.JWT_SECRET}} >> .env
echo PORT=${{secrets.PORT}} >> .env
echo SALT=${{secrets.SALT}} >> .env
echo ORIGIN=${{secrets.ORIGIN}} >> .env
- name: prisma set
run: npx prisma generate
- name: Test unit
run: pnpm test:prod
# - name: Test E2E
# run: pnpm test:e2e
- name: test
run: |
pnpm build
timeout ${{ vars.SLEEP }} nohup node dist/main.js > app.log || code=$?; if [[ $code -ne 124 && $code -ne 0 ]]; then exit $code; fi
cat app.log
RECOMMEND FOR YOU
[Infra] NestJS & Github Action 빌드 개선하기 (2 : CD build - cd.yml 파일 개선) : https://iio-nff.tistory.com/5
REFERENCE
Github Actions 캐시 조금 더 알아보기(Pozafly님) : https://pozafly.github.io/dev-ops/cache-and-restore-keys-in-github-actions/
'Programming > Infra Structure' 카테고리의 다른 글
[Infra] NestJS & Github Action 빌드 개선하기 (2 : CD build - cd.yml 파일 개선) (0) | 2024.05.27 |
---|