0. 들어가며
CI/CD를 접하지 않은 상태의 개발자가 개발 산출물을 배포하려면 어떻게 해야 할까? 서버에 Putty로 접속 해서 변경된 파일의 위치를 잡고 그 위치에 FTP로 변경된 파일을 덮어써야 한다. 만약 변경된 것이 jsp나 static 파일이라면 그나마 괜찮지만 클래스 파일이라면? 서버를 껐다 켜야 하기까지 한다.
실제로 직전 회사에서는 작은 배포는 개발자가 알아서 FTP를 쏘고, 배포를 하지 않고 쌓인 개발 건은 정기 배포일을 따로 잡아서 한꺼번에 진행 했다. 사용자가 없는 시간을 이용해서 서버를 내리고, 파일을 덮어쓰며 배포하고, 다시 서버를 올려 테스트를 진행한다. 당연히 배포 날은 야근이다. 테스트에서 에러가 나면 퇴근은 기약이 없어진다. 또 그동안은 사용자들은 서비스를 이용할 수 없는 상황에 놓인다.
하지만 CI/CD 라는 개념은 이러한 개발 및 배포 단계들을 연결해서 자동화하여 빠르게 사용자에게 변경된 서비스를 제공할 수 있도록 만들어준다. 이번 사이드 프로젝트를 진행하면서 CI/CD를 직접 구현해볼 수 있었는데, 본 포스팅에서는 내가 진행했던 간단한 사이드 프로젝트의 예시를 통해 Spring 프로젝트에서는 흔히 어떤 식으로 CI/CD 환경이 적용되는지 정리하고자 한다. 나는 실제 프로덕션에 잘 적용된 레벨까지는 경험해보지 못했고, 구현할 수 있는 수준도 아니지만 간단하게 적용된 사례나 CI/CD에 필요한 각각의 요소들에 대해 설명하는 레퍼런스가 없어 삽질을 많이 했었기 때문에 아래의 글에서는 CI/CD에 대한 얕은 지식만을 챙기고, Best Practice는 잘 정리된 개별 글을 보는 것을 추천한다.
1. CI ? CD?
CI와 CD는 각각 Continuous Integration(지속적 통합), Continuous Delivery / Continuous Delpoyment(지속적 제공 / 지속적 배포)의 줄임말이다.
지속적인 통합(CI)은 개발자가 개발한 내용을 "정기 배포일"에 한 번에 합치는 것이 아니라,변경 사항을 조금씩 합치면서 테스트 실행을 통해 안정적으로 합치는 것이다. 지속적인 배포(CD)란 "정기 배포일에 서버를 끄는 것"이 아니라 개발자가 push한 변경 사항이 거의 즉시 적용될 수 있도록 하는 것이다.
CI는 개발의 변경사항을 정기적으로 공유하며 합치고(Version Control System) 각 변경사항이 잘 작동하는지 확인(테스팅과 빌드)하는 것이고 CD는 CI가 성공적으로 마무리된 시점부터 빠르게 배포하는 것이다.
대부분의 경우 CI와 CD는 분리되지 않고 합쳐서 파이프라인을 구성하기 때문에 보통 CI/CD라고 합쳐서 부른다. 둘은 각각의 개념이 아니라 CI/CD라는 devOps의 한 방법론으로 해석이 된다.
그리고 개발 패러다임이 Waterfall에서 Agile로 변경되면서(https://www.jetbrains.com/ko-kr/teamcity/ci-cd-guide/continuous-integration/) CI/CD는 현대적인 애플리케이션 환경에서는 필수 개념이 되었다.
2. CI /CD 환경이 적용된 구조
배포 구조는 아주 단순하게 위와 같다. 간단하게 흐름을 파악하고 CI/CD에 필요한 각 tool 들에 대해 설명하겠다.
Local에서 Github로 Push가 수행되면, 깃허브의 변경사항을 관리하고 있는 Webhook이 이를 감지하여 Jenkins에게 소식을 알린다. Jenkin는 Github의 Repository로부터 소스코드를 받아와서 설정된 일련의 Job을 수행한다.
이제 Jenkins는 AWS EC2로 접속한 뒤 내부에 있는 도커 컨테이너(WAS - tomcat)에 소스코드를 빌드하고, Webapps 폴더에 넣으면서 배포가 수행된다.
사용자 입장에서는 서버의 Public 주소로 들어오게 되면 웹서버, Nginx를 통해 각각의 WAS(Tomcat)에 접근한다. Tomcat은 과부하를 방지하기 위해 사용자를 8088 포트의 톰캣, 8089 포트의 톰캣으로 번갈아가며 나누어서 전송한다. 하지만 이때, 사용자의 접속 정보(Login Session 이라든가)는 서로 다른 WAS에서도 유지되어야 하기 때문에 세션 클러스터링을 설정한다.
테스트가 없는 CI는 브레이크 없는 자동차(https://www.nextree.co.kr/p10799/)라는 말을 인용해서, 사실 위의 프로세스는 반쪽짜리다. CI에서 자동화된 빌드만을 구현하고 있으니. 하지만 다시 말하자면, 이 포스팅의 목적은 아주 얕게 CI/CD를 알아보는 것이니 CI의 본질은 테스트라는 것을 알아두고, 우선 넘어가자!
3. CI /CD 환경에 필요한 도구들
1. Github
다수의 개발자들의 개발 변경사항을 관리할 수 있는 도구가 필요하다. 여기서는 Github라는 remote repository를 사용했다.
2. Webhook
VCS에 생긴 변경사항을 감지하고 전달할 도구로 Webhook을 사용했다. Webhook은 특정 이벤트가 발생했을 때 타 서비스로 알림을 보내는 기능이다. 여기서는 Github의 변경사항이 발생하면, Jenkins로 알람을 보낸다.
3. Jenkins
핵심은 젠킨스다. 젠킨스는 Job을 통해 자동화된 빌드, 테스팅 등을 실행할 수 있는데 직접 스크립트를 만들어서 커스텀하게 다양한 환경에 적용할 수 있다. 또한, 다양한 플러그인을 제공해주고 레퍼런스가 많기 때문에 사용하기 편리하다. 대안으로 Travis CI도 많이 사용한다.
4. AWS EC2
EC2(Elastic Compute Cloud)는 아마존에서 제공하는 클라우드 컴퓨팅 서비스다. 자세한 개념은 EC2나 IaaS(Infrastructure as a Service, https://cloud.google.com/learn/what-is-iaas?hl=ko)의 키워드로 검색해보자. 아마존이 구축해놓은 서버용 컴퓨터들의 자원을 원격으로 사용할 수 있는 개념인데 아주 간단하게 생성하고 삭제할 수 있고, 가입으로부터 1년간 무료이기 때문에 간단하게 CI/CD 환경을 구성할 인프라로 사용하기 좋다.
5. Docker
Docker는 가상 머신이 서버 하드웨어를 가상화하는 것과 비슷하다. 안드로이드 모바일 게임을 컴퓨터로 할 때, 안드로이드 가상환경을 우리 컴퓨터에 실행하고 그 위에 게임을 실행시키듯이, 혹은 리눅스 서버를 내 컴퓨터에 설치해서 운영할 때처럼 Docker는 이런 가상 머신을 "컨테이너"라는 개념으로 부르며 제공한다. 그리고 예를 든 가상 머신보다 훨씬 가볍고, 편리하다.
내가 만들어놓은 환경을 "이미지"로 만들어 공유할 수도 있고 다른 사람의 개발환경을 "이미지"로 받아와서 작업할 수 있다. 내 운영체제가 맥이든 윈도우든, 도커 컨테이너 내부에서는 모두 평등하다. 사실 개인적으로 Docker는 아무리 잘 정리된 글을 읽어도 잘 모르겠더라. 근데 찍먹이라도 대충 해보면 안다, Docker는 진심 혁신이다. CI/CD의 본질적인 목적이 애플리케이션을 신속하게 구축/ 테스트 및 배포하는 것이라면 Docker는 이러한 목표에서 본질적으로 매우 밀접하다. Docker를 이렇게 길게 쓰는 이유는 그만큼 너무 좋기 때문에.. 재밌고 귀에 쏙쏙 박히는 5분 짜리 도커 영상(https://www.youtube.com/watch?v=tPjpcsgxgWc)을 보자
6.Nginx
Nginx는 웹서버다. 사실 작은 사이드 프로젝트 정도야 tomcat 하나만 띄워도 충분하지만, 대부분의 애플리케이션은 Web Server와 Web Application Server을 분리하여 구성한다.
웹서버는 정적 컨텐츠를 제공, WAS는 동적 컨텐츠를 제공하는 서버라고 알고 있겠지만 사실 WAS도 정적 컨텐츠도 제공한다. 하지만 Web Server와 WAS를 분리함으로써 많은 이득을 얻을 수 있다. 기능을 분리하여 서버 부하를 방지하거나, 사용자의 요청을 여러 WAS에 나눠서 전달할 수 있도록 돕기(로드밸런싱)도 한다.
7. Tomcat
Nginx를 앞에 두고 Tomcat을 여러 개 운영한다면, 세션 클러스터링이라는 키워드를 꼭 검색해보자.
4. CI /CD 가 이루어지려면...
CI/CD는 앞서 말했듯이 devOps의 방법론이다. Agile을 devOps에 결합시킨 방법론이라고 해야 하나. 그렇기 때문에 단순히 CI/CD 툴을 끼워넣는다고 해서 CI/CD의 환경이 갖추어지는 것이 아니다. 지속적 통합과 배포를 도입한다는 것은 개발팀(혹은 개인)의 환경 자체가 달라져야 함을 의미한다.
필수적으로 구성되어야 하는 테스트 코드, 단위 별로 잘게 나누는 Commit, 올바른 협업, 구성된 인프라 자체의 안정성이 선행되어야 한다. 또한 CI/CD 파이프라인을 구축하고 손을 놓는 것이 아니라 지속적으로 모니터링 하며 프로세스를 개선해나가야 한다. 이러한 것들이 CI/CD의 장점은 누구나 알고 있지만, 누구나 쉽게 도입할 수는 없는 이유가 된다.
나도 CI/CD 파이프라인을 올바르게 구성하기 위해 부단히 노력해야겠다. 테스트 코드를 중요시 하고, 인프라 환경을 이해하고, docker에 대한 학습이 필요할 것 같다.
Github Acitons + Docker Compose + Elastic Beanstalk으로 구성한 CI/CD 파이프라인이 궁금하다면?
'프로젝트' 카테고리의 다른 글
AWS RDS Lock 해결하기 (0) | 2022.08.17 |
---|---|
Github Actions + Docker Compose + Elastic Beanstalk (0) | 2022.07.21 |
SpringBoot 전략패턴 + IF 분기 없애기 (0) | 2022.06.08 |
*.do 없애고 깔끔한 HTTP API 만들기 (2) | 2022.05.09 |
댓글