DevOps/Deploy

프론트엔드 CI/CD 효율적으로 활용하기 (feat. Github Actions)

닝닝깅 2024. 1. 30. 17:23

CI/CD 말은 많이 들어봤는데, 큰 규모의 프로젝트는 개발해본 적 없는 나로서는 한번 배포하면 다시 배포할 일이 그렇게 많지는 않았기 때문에 접할 기회가 마땅히 없었다.

꼭 써보고 싶었는데 이왕 쓸 거 제대로 알고 쓰자는 의미에서 CICD에 대해 찾아보게 되었다.

 

 

➰ 개발부터 배포까지

배포가 되기까지는 어떤 과정을 거칠까?

개발 > 빌드 > 테스트 > 릴리즈 > 배포 

개발

개발자가 소스코드를 원격저장소에 push한다.

빌드

소스코드 파일이 실행 가능한 형태로 변환되는 것이다.

 

작성한 소스 코드 파일을 컴파일하여 바이너리코드로 변환하고, 링크를 거쳐 실행 파일이나 라이브러리 파일 등을 생성하는 과정으로 이루어진다.

테스트 

실행가능한 결과물이 의도한대로 동작하는지를 테스트한다.

릴리즈

테스트를 마친 후 결과물이 다운로드가 가능하거나, 앱 스토어 또는 기타 배포 채널을 통해 배포하거나, 사용자 시스템에 설치할 수 있는 상태가 되면 이 버전을 릴리즈라고 한다.

배포

완성된 결과물을 서버와 같은 기기에 설치하여 사용자들에게 서비스를 제공할 수 있게 된다.

 

 

서비스의 규모가 커질 경우 하나의 조직이 관리하기 때문에 코드를 통합하고 저 과정을 모두 거치기까지는 시간이 오래 걸리게 된다. 이렇게 되면 배포 주기가 길어질 수밖에 없고 사용자의 피드백을 빠르게 반영할 수 없기 때문에 서비스 품질과 효율성이 떨어지게 된다.

 

CI/CD로 이 번거로운 과정을 압축시켜줄 수 있다.!

 

 

✨ 작업 효율을 위한 CI/CD 

CI/CD는 코드 병합부터 테스트, 배포까지의 라이프사이클 전체에 걸쳐 자동화를 이루는 것이다.

 

 

CI/CD를 통하여 개발자는 더울 개발에만 집중할 수 있기 때문에 작업의 효율성을 높여준다.

그리고 좀 더 짧은 주기로 사용자들에게 서비스를 제공할 수 있다.

 

 

📌 CI : 빌드 및 테스트 자동화

CI는 지속적 통합( Continuous Integration )으로, 정기적으로 코드에 대한 변화를 실행하고 테스트한다.

 

이는 앞선 단계에서 테스트까지의 단계를 의미한다.

빌드 결과를 통해 유닛테스트와 빌드의 성공여부를 확인하고, 테스트 결과를 통해 코드의 개선방안을 찾을 수 있다.

 

이 과정을 통하여 개발자는 신속하게 버그를 찾아내고 테스트가 완료된 코드에 대하여 빠른 전달이 이루어지며 지속적인 배포가 가능해진다.

 

 

📌 CD : 배포 자동화

CD는 지속적 제공과 지속적 배포 두가지 의미를 갖는다.

 

일단, 두 경우 모두 CI가 끝난 결과물을 하나의 중앙 레포지토리로 통합하여 릴리즈 상태로 준비하는 과정까지 자동화가 되어있다.

 

두 경우의 차이점은 다음 단계인 배포의 자동화 여부이다.

지속적 제공의 CD

개발팀은 레포지토리에 업로드된 준비된 릴리즈가 정상적인지 문제가 없는지 이 검증을 한 후, 애플리케이션을 실시간으로 프로덕션 환경에 수동으로 배포한다.

수동 배포의 경우 개발자는 애플리케이션을 최종 배포하기 전에 계속해서 조정할 수 있다.

 

지속적 배포의 CD

개발팀이 준비된 릴리즈를 확인하지 않고 배포까지 자동화 해두는 것이다. 자동화 흐름이 중단되지 않으므로 코드 자체가 프로덕션 환경에 진입하기 전에 충분히 테스트되어야 한다.

 

 

👍🏻 CI/CD의 장점

CI/CD로 배포 주기를 단축시킬 수 있기 때문에 많은 수정을 한 번에 배포하지 않고, 자주 여러번 수정 배포하면서 개발의 효율성과 릴리즈 기간을 단축시킬 수 있다!

 

 

👁‍🗨 CI/CD 구성요소와 효율적인 활용방법

CICD 파이프라인을 자세히 들여다보면 아래와 같은 세부과정들을 거친다. 우선 각 과정이 어떤 효과를 내는 지부터 살펴보자.

Linting, Formatting와 유닛테스트

이 과정은 일관된 코드 스타일링으로 팀 내 개발속도를 높일 수 있고, 빠른 테스트를 통해 버그를 찾아낼 수 있도록 도와준다. 해당 과정을 통해 팀은 더 안정적이고 빠른 개발 환경을 가질 수 있다.

 

Linting, Formatting

린팅(Linting)과 포맷팅(Formatting) 은 코드 일관성을 위한 도구이다. 

코드 스타일을 통일시켜주고, 테스트 전 테스트 코드에서 실행 될 수 없는 코드를 찾아주는데 도움을 준다.

 

Unit 테스트

유닛 테스트는 실행 가능한 가장 작은 단위의 소프트웨어를 테스트 하는 것이다. 프론트엔드에서 유닛테스트의 단위는 단일 컴포넌트나 단일 서비스라고 할 수 있다.

테스트는 매우 간단하고 명확하게 작성이 되기 때문에 개발단계에서의 버그를 빠르고 쉽게 잡아줄 수 있다.

 

ex ) Jest

 

 통합테스트와 E2E테스트

같은 조직내에서의 협업과정에서 테스트를 통하여 프로젝트가 의도한대로 작동하는 지 테스트를 해야한다.

테스트 과정은 통합 테스트와 e2e 테스트로 과정을 나눌 수 있다.

 

통합테스트

통합테스트는 통합된 기능을 테스트하는 것이다. 앞서 테스트한 유닛들의 상호작용에 대하여 테스트을 하고 유닛을 넘어 외부 라이브러리, db 등 다른 시스템과 잘 연동이 되는 지 테스트하기도 한다.

 

E2E 테스트

e2e는 end to end의 약자로, 소프트웨어의 가장 끝단인 사용자로 부터 가장 끝단인 백엔드 인프라까지 테스트하는 것을 의미한다. 즉 사용자가 실제 서비스를 사용하는 상황을 테스트하는 것이다.

 

팀과 조직이 미처 파악하지 못한 긴 로딩시간이나 경쟁상황을 드러낼 수 있다는 것이 장점이다.

하지만 cicd에서 가장 오랜 시간을 잡아먹을 만큼 느리다는 단점이 있다. 그리고 api로 데이터를 전송하는 기능에 대하여 테스트를 진행한다고 할 경우 외부 api에 대하여 백엔드와 잘 연결이 되어있는 지에 대해서만 테스트가 가능하다.

 

ex) cypress, playwright

 

접근성 테스트와 접근성 감사

이 과정은 장애인을 포함한 모든 사용자가 차별없이 서비스에 접근할 수 있게 접근성을 확인하도록 하는 것이다.

 

ex) Lighthouse CI , CypressAxe

 자동화 구성

CI/CD 파이프라인의 구체적인 구성요소와 효율적인 활용방법에 대해 알아보기 위해 열심히 자료를 찾아보던 중 한 개발자 분이 쓰신 글이 마음에 들어 그 글을 참고하여 작성하였다.

 

이제 cicd의 파이프라인 구성요소는 살펴보았고 효율적인 자동화 구성을 위해 고민해볼 차례이다.

 

나는 cicd 파이프라인에 대한 경험이 부족하여 경험이 많은 다른 개발자 분들의 글을 많이 접했는데 그 중 한 글을 참고하여 정리해보았다

 

해당 개발자분은 cicd의 최종적인 목표는 테스트 실행부터 프로덕션 배포에 이르기까지 코드리뷰를 제외한 가능한 많은 부분을 자동화하는 것이라고 한다.

자동화를 통하여 작업의 효율성을 최대로 끌어올리겠다는 의미로 비춰진다.

 

그 과정을 위한 과정은 아래와 같다.

 

1. PR단위의 모든 코드 변경 사항 유효성 검사

주로 협업에서는 작성한 소스코드에 대하여 Pull Request을 보내고 코드리뷰를 거친 후 머지된다.

 

PR을 보내기 전 로컬에서 ESLint나 Prettier 등의 도구를 활용하여 유효성 검사를 거치게 되는 경우가 많다. 하지만 이를 로컬에서만 실행되게 하면 '설치하지 않는다', '무시한다' 등의 옵션이 존재하기도 하고, 설치가 제대로 되지 않았으나 설치가 된 줄 알고 작업하는 불상사가 벌어질 수도 있다.

 

이를 방지하고 더불어 테스트 케이스 수준에서 걸러지는 오류를 처리하기 위해 PR 단위의 코드 변경사항을 검사하는 자동화 과정을 거치는 것이 좋다.

 

2. PR단위의 프리뷰 배포

또 PR을 보낼 때마다 독립적으로 실행되는 배포를 각 PR에 제공하는 것을 추천한다.

여기서 해당 배포는 특정 변경 사항이 있는 프론트엔드 프로젝트의 버전이다.

 

이렇게 하면 팀의 검토 속도를 높일 수 있고 디자인이나 제품 팀에서 쉽게 검증할 수 있다. 변경 사항을 보기 위해 로컬에서 실행할 필요가 없으므로 검토 과정을 줄일 수 있기 때문에 효율적이다.

 

프론트엔드만 배포하는 것이기 때문에 배포도구로는 Netlify, Vercel와 같이 비교적 쉬운 호스팅을 제공하는 서비스를 추천한다.

 

3. 릴리스 프로세스

메인 브랜치에서 배포를 위한 프로덕션으로 보내지기 위해서는 검토를 위한 스크립트를 실행해야 하는데 이걸 수동으로 실행하는 것은 효율성이 떨어지는 일이다. 릴리즈 브랜치를 하나 생성해두고 메인 브랜치가 릴리즈 브랜치에 머지될 때마다 자동화된 스크립트를 실행하는 것을 추천한다. 

 

그리고 릴리즈를 자동화한 후에는 가능한 자주 릴리즈 프로세스를 수행해주는 것이 좋다. 배포의 주기가 길어질 수록 대규모 변경사항이 발생해 배포의 위험이 증가하기 때문이다.

 

이때 기능플래그( Feature Flag )를 추가하는 것을 추천한다.

기능 플래그란 코드 수정 없이 서비스 동작을 변경할 수 있는 기능이다. 배포한 기능을 바로 사용자에 보여주지 않고 특정한 인원만 접근할 수 있는 운영 환경에서 테스트를 할 수 있기 때문에 대규모 변경사항이 프로덕션에 배포하였을 때 발생할 수 있는 문제들을 효과적으로 제어할 수 있다.

 

 


참고

https://blog.logrocket.com/best-practices-ci-cd-pipeline-frontend/

https://engineering.linecorp.com/ko/blog/build-a-continuous-cicd-environment-based-on-data

https://blog.maximeheckel.com/posts/guide-to-cicd-for-frontend-developers/