기존 Jenkins 설정을 활용한 배포 과정
Jenkins를 활용한 빌드-배포도 나쁘진 않았다
근데 GitHub Action을 쓰다보니 다신 못 돌아가겠다
Jenkins - Groovy 기반 스크립트는 뭔가 어색하다
- Jenkins Pipeline Script는
Groovy
를 사용함 - Backend 분들은 Spring Boot 설정 파일에서 사용하는 경우도 있어서 익숙할지 모르겠으나..
- Spring Boot와 어색한 우리 Frontend 에겐 러닝 커브가 있음
- 그래도 한줄한줄 보다보면 어떤 느낌으로 흘러가는 지 정도는 파악할 수 있음
- 뭔가 파이썬스럽기도 하고..
- check parameter -> git checkout/pull -> docker build -> push to ECR -> GitLab k8s commit
Jenkins on IDC - 그냥 뭔가 불편하다
버전이 너무 낮음
- GitLab도.. Jenkins도 버전이 오래됨..
- 플러그인들 붙이기도 어려움
- 검색해서 뭔가 신박한걸 해보려고 하지만 할 수가 없음
- UI도 왠지 구림
IDC 서버에서 작동
- CPU 성능이 GitHub Action 서버의 40% 정도 수준임
- => 빌드 속도에서 차이가 날 수 밖에 없음
- 가끔 다른 프로젝트들에서 이미 여러개 실행 중인 경우, 대기 큐에 밀려서 끝날때까지 기다려야 함
- 어쩌다 한번씩 젠킨스 서버가 터져서 배포를 못하기도 함.. 디스크 용량 초과라든지.. 마스터 계정 비번을 못찾는다든지..
- CPU 성능이 GitHub Action 서버의 40% 정도 수준임
Jenkins - IDC | GitHub |
![]() | ![]() |
GitHub Actions를 활용한 ECR 배포 자동화
- 현재 ArgoCD의 업데이트 반영 로직은, AWS ECR을 직접 지켜보는 것이 아닌, IDC GitLab k8s 레포지토리를 지켜보도록 되어 있음
- 이것만 아니면 ECR 배포만 해서 자동으로 배포까지 이어질텐데, 이 부분 때문에 결국 사내망을 한번은 접속해서 commit을 해줘야 함
- 어차피 QA 서버 확인하려면 사내망 접속하긴 해야 되니깐 뭐..
- 언제될지 모르겠지만.. 방화벽 문제 해결 되면 이것도 해결 되긴 할 듯..
- 그래서 위 Jenkins Pipeline에서 Push to ECR까지만 GitHub Action으로 옮기고, 마지막 Tag Update하는 부분만 Jenkins에 남겨둔다
QA 배포 자동화 스크립트
name: AWS EKS Auto-Deploy (QA)
on:
pull_request:
branches:
- 'develop'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node: [14]
outputs:
version: ${{ steps.set-version.outputs.version }}
tag: ${{ steps.set-version.outputs.tag }}
steps:
- name: Git Clone, Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx for Docker Cache
uses: docker/setup-buildx-action@v2
- name: Cache Dependencies
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
cache: 'yarn'
- name: Check Build Environments
run: npx envinfo
- name: Install Dependencies
run: yarn install --no-progress --emoji=false
- name: Build App
run: |
rm -rf node_modules/.cache
yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_QA }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_QA }}
aws-region: ap-northeast-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Set ENVs
id: set-version
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: finance/finance-front/dev
version: ${{ steps.set-version.outputs.version }}
run: |
version=$(jq -r .version package.json)-$(date '+%Y%m%d-%H%M%S')
echo "::set-output name=version::$version"
echo "::set-output name=tag::$ECR_REGISTRY/$ECR_REPOSITORY:$version"
- name: Build, tag, and push image to Amazon ECR
uses: docker/build-push-action@v3
with:
context: .
push: true
tags: ${{ steps.set-version.outputs.tag }}
file: qa.github.Dockerfile
- name: Check Container Tag
env:
version: ${{ steps.set-version.outputs.version }}
run: echo version $version
- GitHub Action의 장점 중 하나는 이미 다른 사람들이 만들어놓은 Workflow를 플러그인처럼 갖다 붙일 수 있다는 것
- 직접 Git Checkout 하고, Node, Docker 환경설정하고 ECR login-push 하는 스크립트를 짤 필요 없이,
- 그냥 갖다 쓰기만 하고 parameters만 잘 넣어주면 된다
- 또한 의존성(
node_modules
) 설치한 것들을 캐싱해서 쓸 수 있다는 것- 물론 특정 디스크 용량 초과할 경우 비용 발생할 수 있음
actions/setup-node@v3
을 활용해node_modules
디렉토리를 캐싱할 수 있는데, 쌩으로yarn install
했을 때 1분~1분 30초 정도 소요된다면, 캐싱을 통해 30초 내외로 시간을 단축할 수 있다- yarn PnP Zero-installs 설정을 하게되면, 3초 내외로 단축할 수 있다
node_modules
디렉토리 전부를 git에 넣어버리는 셈이라..- zip 파일들이라 용량도 크게 줄어든다
변수 설정
- 나름 제일 까다로웠던 (?) 부분
jq
를 활용한 version tag 생성- container tag를 생성할 때, 기존처럼 버전을 직접 입력하는게 아니라 package.json에 있는 버전을 가져와서 자동으로 생성하도록 만들고 싶었음
- 처음엔 어떻게 해야 될지 몰라서, shell에서 package.json 파일 내용을 출력한 다음 정규식으로 version에 해당하는 값을 가져올 수 있는 방법을 찾아봤음
- 많은 개발 지식은 물론 쓰레기도 섞여있는 stackOverflow를 보면서 이런저런 삽질을 하다보니
jq
라는 라이브러리로 json parsing이 가능하다는 걸 알게 됨 version=$(jq -r .version package.json)-$(date '+%Y%m%d-%H%M%S')
- 이 스크립트로 프로젝트 최상단 package.json에 있는 version 값과 현재 datetime 값을 합쳐 tag 생성
outputs
을 활용한 전역변수 생성- 각 step마다 env를 설정할 수 있는데 이건 그 step에서만 사용할 수 있는 지역변수임
- 전역변수 env를 선언할 수도 있긴한데, 위 tag처럼 동적으로 생성하는 건 안됨. 상수만 가능한 듯
- 그래서 동적으로 전역변수를 선언하려면
outputs
를 활용해야 함 [전역변수명]: ${{ steps.[stepId].outputs.[변수명] }}
- jobs.outputs에서 전역변수명들을 선언하고, 어떤 step에서 어떤 output으로 나올 건지 알려준다
echo "::set-output name=[변수명]::$version"
- 해당 step에서 변수명에 해당하는 값을 대입해준다
Docker Build; Image 사이즈 최적화
GitHub Action에서 사용할 수 있는 OS는 Ubuntu, MacOS, Windows 3가지임
GitHub Action에서 빌드하고, 빌드 결과물, 최소한의 필요한 의존성만 Docker로 Copy해서 넘김
- Docker base OS가 alpine이긴한데, Ubuntu에서 빌드해도 문제 안됨
- 문제되는 경우는 Window - Unix 계열 end of line 문자가 달라서 빌드 파일에 영향을 미치거나,
- CPU architecture가
intel
-arm
달라서Esbuild
,Parcel (SWC)
,node-sass
등 일부 빌드 관련 패키지가 아예 달라지는 경우 등- Rust는 하루 빨리 M1을 지원하라..!!
- 그거 말고는 아직 못봤음, 암튼 동일한 intel CPU면 Ubuntu - Alpine 차이 정도는 문제 안됨
GitHub Action도 Container 환경(아마도 99% 확률로 Docker?)에서 실행되는 거라, 기존처럼
Docker-in-Docker
방식으로 빌드하면 속도가 더 느려질 듯이때 Docker Cache는 굳이 쓸 필요가 없음
- 이것도 결국은
node_modules
캐싱하는게 주목적인데, GitHub Action에서 디렉토리 전부 캐싱해버리기 때문 - 만약 Docker Cache가 꼭 필요한 상황이라면,
docker/build-push-action@v3
사용하는 부분에서cache-from
,cache-to
옵션을 설정해준다node-alpine
이미지 가져오는 몇초까지 아껴야하는 상황이라면..- github.com/docker/build-push-action/blob/ma..
- 카카오엔터테인먼트 FE 기술블로그 - GitHub Actions에서 도커 캐시를 적용해 이미지 빌드하기
- 이것도 결국은
Container Tag
- 여기서 만든 Docker Container Tag를 출력하고,
- 이 tag를 복사해서, 사내 Jenkins에서 tag만 업데이트하는 pipeline을 실행시킨다
조심해야 할 것
GitHub Action 월간 사용량
- Pro/Team Plan 월 3,000분까지 무료, 그 이후부터는 분당 과금됨
- ChartIQ 패키지 추가하면서 빌드 한번에 10분씩 걸리는데..
- 월 20일 출근 X 하루 15번 빌드 X 빌드 1회당 10분 => 3000분
- 모바일 파트쪽 빌드/테스트하는 것까지 포함하면 월간 사용량이 꽤 될 것 같아서 조금 걱정됨..
- 사실 걱정 보다는 나중에 시간 줄이라고(돈 아끼라고) 얘기 나올 거 같아서 귀찮아질 것 같음
- => PR 만들어놓고 1 commit - 1 push 보다는 commit 어느정도 쌓인 후 push 하는게 좋을듯..
AWS ECR 비용 문제
다행히도 ECR inbound 네트워크 비용은 발생하지 않는 듯
- 자동배포를 하면서 QA 서버 빌드는 PR / push 할 때마다 Docker 이미지가 GitHub -> AWS ECR로 날아감
- 이때 프로젝트에 따라 Docker image 크기는 적게는 300mb 많게는 500 mb 내외
- 당장은 데이터 수신 비용이 $0 여서 이건 문제가 안됨
만약 나중에 AWS에서 돈을 받겠다고 한다면?
- AWS CodeBuild, CodeDeploy 도입을 고려해볼 수 있을 듯
- AWS 동일 region 내 네트워크 비용은 발생하지 않으므로..
- 근데 CodeBuild는 월간 무료 사용량 100분 밖에 안되기 때문에, 비용 비교를 잘 해봐야 할 듯
- AWS CodeBuild, CodeDeploy 도입을 고려해볼 수 있을 듯
좀더 개선해 볼 것
Cron으로 정기 배포 (Xvezda
님 의견 👍)
- Jenkins에서 어쨌든 k8s 레포지토리 태깅 커밋은 한번 해줘야 함
- QA 서버 정도는 5분~10분 단위로 Cron 걸어서 자동 배포해줘도 크게 문제 없을 듯
- Cron은 Jenkins에서 해도 되고, GitLab CI에서 해도 됨
- 개인적으로는 이것도 GitLab CI가 좀더 편함.. (서버시간 엉망인것만 빼고..)
- Prod 서버는 그래도 QA 서버에서 충분히 확인하고 수동으로 배포하는게 좋지 않을까..
페이지 마다 모노레포 패키지로 나눠서 빌드 시간을 줄여보자 (somedaycode
님 의견 👍)
- turborepo 적용해 패키지 병렬 빌드 가능하도록 함
- domain / BE 패키지는 5~15초 내외 소요되고 있어서, 병렬 빌드하는 이점이 크게 없음
- 문제는 FE 빌드시간인데, Chart 빌드 => FE:CSR 빌드 => FE:SSR 빌드 순서가 반드시(;;) 지켜져야하는 상황
- ChartIQ 라이브러리 사이즈가 꽤 되다보니, Chart~FE 빌드만 7~8분 정도 소요됨
- Chart 패키지 쓰는 페이지(상세페이지) - 나머지 페이지 나눠서 병렬 빌드하면 이 문제가 좀 해결될 수도?
- 좀 큰 공사가 될수도 있어서 겁남..
- Next/Nuxt 쓰면 알아서 해결될 문제긴 한데.. 아무튼..
references
resources
- image