[DevOps] CI/CD는 왜 필요하며, 언제 쓰여야 하는가?
📕 목차
1. Introduction
2. 레거시 환경
3. 개발 프로세스
4. 지속적 통합(CI) 파이프라인 적용해보기
5. 지속적 배포(CD) 파이프라인 적용해보기
1. Introduction
📌 개요
약 2년 전쯤, 지인에게서 CI/CD 라는 단어의 존재를 처음 알게 되었을 때 궁금해서 온갖 블로그를 찾아본 적이 있었다.
그런데 하나같이 모르는 개념을 모르는 개념으로 설명해주고 있어, 이해가 매우 어려웠던 경험이 있었다.
그나마 얻은 키워드라고 해봐야 "자동화" 하나 뿐이었는데, 대체 뭘 자동화한다는 건지 당췌 알 수가 없었다.
그래서 Spring Boot에 적용할 수 있는 Continuous Deployment부터 직접 부딪히면서 공부했었다.
이번 포스팅은 CI/CD를 설명하기 위해 그 어떤 전문 용어도 사용하지 않을 것이며(물론 간단한 CS 용어가 나오긴 한다),
설령 이 개념을 처음 보는 사람이라도 CI/CD의 개념와 필요성을 알 수 있도록 작성하는 것이 목표다.
2. 레거시 환경
📌 가장 단순한 배포 흐름
1인 서버 개발을 하고 있는 상황을 가정하자.
열심히 코드를 작성하고 github에 게시한 후, 터미널에서 서버에 접근하여 코드를 내려받고 실행을 하는 게 가장 단순한 형태일 것이다.
이 과정이 좀 귀찮다고 느낀 적이 있는가?
아니면, 이 정도는 할만하다고 느끼는가?
그렇다면, 도커를 사용해서 컨테이너로 애플리케이션을 실행한다고 가정해보자.
위 상황은 어떠한가?
도커 엔진의 강력함을 얻었지만, 단순히 git push & pull로 해결하던 때보다 확실히 느려진다.
이미지를 생성하고, DockerHub에 올리고, 그걸 서버에서 다시 받고 실행하기 위해 개발자는 개발이 아닌 배포 과정에서 많은 시간을 빼앗기게 된다.
애플리케이션이 커질 수록 속도는 느려지고, 만약 애플리케이션이 예상처럼 동작하지 않으면 계속 위 과정을 반복해야 한다.
아직도 공감이 되지 않는다면, 협업 환경을 살펴보자.
📌 협업 환경
혼자 개발할 때와는 달리 다음 조건이 추가되었다.
- 형상 관리를 위해 반드시 원격 저장소에 작업물을 게시해야 한다.
- 게시한 작업물은 반드시 다른 팀원에게 리뷰를 받고 병합되어야 한다.
- 보안 문제나 기타 복잡한 상황을 회피하기 위해 서버에 접근할 수 있는 팀원은 A만 가능하다고 가정한다.
혼자 개발할 때는 코드가 실패해도 그나마 빠르게 수정과 배포를 수동으로 하기 용이했다.
하지만 지금은 B의 코드가 실패하면, 그 동안 계속 A의 발목이 붙잡힌다.
심지어 코드 리뷰가 끝나고 브랜치에 작업물이 병합이 되어도, 서버에는 A가 작업이 가능한 상태가 되어야지만 배포 서버에 반영이 된다.
위와 같은 프로세스를 가지면, A는 사실상 개발이 불가능한 상황에 다다를 것이다.
📌 배포 관리자
팀원에 여력이 있어서, 배포 관리자라는 직책을 따로 배정했다고 가정하자.
개발팀은 개발에만 몰두할 수 있고, 배포 관리자는 배포에만 관리하면 되므로 R&R(책임과 역할)이 잘 나누어져 있다고 볼 수도 있을 것이다.
그런데 이전 상황이랑 동일하게 심각한 문제가 하나 있는데, 관리자가 일을 할 수 있는 환경이 아니면 여전히 서버에 즉각적으로 반영이 되지 않는다는 것이다.
그럼 관리자를 여러 명 두어야 할까? 하지만 그렇게 되면 다른 문제들이 발생한다.
바로 책임 문제와 의사 소통 문제가 발생한다.
그리고 더 현실적인 문제로 인력을 투입하기 위한 자본이 그만큼 많이 들어간다. (기업은 바보가 아니다.)
서버 접근과 배포의 권한을 갖는 것은 상당히 큰 책임을 갖는다.
그렇다면 배포 관리자를 누가 맡아야 할까. PM이 맡아야 할까? 하지만 PM은 바쁜 사람이다.
그럼 사실상 개발자 중 한 명이 빠져야 할 가능성이 크다. 심지어 제법 노련한 개발자가 맡아야 한다.
물론 문제는 훨씬 더 많다.
대충 생각나는 것만이라도 열거해봤다.
- 드물지만 정말 빠르게 배포가 진행되는 곳에선 하루에 병합이 백 건도 넘게 발생하기도 한다고 한다. 관리자의 곡소리가 여기까지 들린다
- 무중단 배포: 8080 포트에 애플리케이션이 실행 중이고, 병합 코드를 반영하기 위해 애플리케이션을 내렸다가 다시 올리면 그동안 서비스는 중단된다. 따라서 8081 포트로 새로 애플리케이션을 띄우고, 트래픽을 8081 포트로 옮겨주어야 하는 작업을 해야하는데, 배포 관리자가 직접 다 할 것인가?
뭐가 더 있지만 너무 깊어지는 것 같아서 그냥 관두기로 했다.
📌 소통의 문제
이번에는 배포 외에도 다른 관점에서 살펴보자.
A가 작업물의 PR을 게시하고, B에게 리뷰를 요청해야 하는 상황도 어찌보면 비효율적이다.
만약 팀원이 더 많다면, A는 매번 모든 팀원에게 리뷰를 요청해야 한다.
그런데 시간이 아무리 지나도 아무도 확인해주지 않는다면, A는 그때마다 팀원들에게 리뷰 요청 메시지를 직접 전송해야 한다.
테스트 코드의 경우엔 어떠한가?
A가 테스트 코드를 작성해서 게시를 하면, 코드를 확인할 수는 있겠지만 정상적으로 동작한다는 보장은 없다.
즉, 리뷰어는 해당 코드를 로컬 환경으로 pull하고 매번 직접 테스트의 통과 여부를 확인해야만 한다.
이 또한 비효율적이다.
3. 개발 프로세스
📌 레거시 환경의 문제점
위의 문제들은 모두 필수적인 과정이지만, 모두 휴먼 리소스를 낭비시킨다.
하지만 곰곰이 생각해보면, 위 작업은 언제나 반복적이다. 어떤 변칙적인 작업이 아니다.
그 말은 즉슨, 언제나 일관된 프로세스를 갖는 반복적인 일련의 작업들이며, 이는 자동화의 대상이 될 수 있다.
📌 프로덕트를 만드는 과정
처음 CI/CD 키워드에 호기심을 가지고 접근하는 사람들이 가장 많이 놓치는 점은 프로덕트를 생산하기 위한 과정은 단순히 개발만이 다가 아니라는 점이라고 생각한다. (내가 사람들을 가르치던 경험 상)
디자인 팀과의 소통도 중요하고, 계획, 태스크 관리, 형상 관리, 테스트 등등.
프로세스에 참여하는 인원이 많아질 수록 소통은 더욱 복잡해지고, 그만큼 혼자 개발할 때에 비해 낭비되는 부분 또한 필연적으로 많아지게 된다.
CI&CD 파이프라인을 구성한다는 것은 이러한 부분들을 모두 자동화한다.
개발자는 개발에만 집중하고, 기획자는 기획에, 디자이너는 디자인에만 집중할 수 있도록 돕는다.
그 외의 모든 비효율적인 곳은 자동적으로 이루어진다.
이것이 CI&CD 파이프라인의 본질이라 생각한다.
4. 지속적 통합(CI) 파이프라인 적용해보기
📌 규칙 파악하기
코드 통합을 위해서 대표적인 두 가지 경우를 살펴보자.
리뷰 요청의 경우엔 다음과 같은 순서를 따른다.
- 개발자가 작업 내역을 PR로 상세히 기술하여 게시한다.
- 개발자는 다른 팀원에게 리뷰를 요청한다.
- 팀원이 리뷰를 한 후에 작업자에게 다시 확인을 요청한다. (혹은 팀원이 리뷰를 안 해줘서 다시 요청할 수도 있다.)
- 승인이 될 때까지 2~3번을 반복한다.
그리고 테스트의 경우엔 다음과 같을 것이다.
- 개발자는 테스트 코드를 함께 PR로 게시한다.
- 팀원은 PR이 올라온 브랜치를 로컬 환경으로 pull한다.
- 테스트가 정상적으로 수행됨을 확인한다.
물론 순서는 팀마다 회사마다 다를 수 있지만, 가장 일반적이고 단순한 사례를 생각해보았다.
📌 리뷰 요청 자동화
협업을 하면 당연히 소통을 위한 도구를 사용하고 있을 것이다.
가장 많이 사용하는 것이 Slack이고, 학생이면 보통 Discord를 사용하고 있을 것이다.
이런 도구들은 대부분 webhook이라는 걸 아주 쉽게 사용할 수 있도록 지원한다.
Github에 webhook을 등록해두고, 특정 이벤트(push, comment, review 등)가 발생하면 팀원 전체에게 알림이 전송되도록 구성할 수 있다.
팀원이 리뷰를 하면 이 또한 알림이 전송될 것이므로 더 이상 일일히 찾아다니며 리뷰를 요청하고, 리뷰 확인을 요청해도 되는 인적 리소스 낭비를 없앨 수 있다.
물론 webhook을 지원하지 않는 앱을 사용하는 경우도 있을 수 있다.
예전에 디자이너, 프론트, 나 포함 3명밖에 안 될 때는 카카오톡으로 메시지를 전송했었는데, 나는 이것도 귀찮아서 카카오톡으로 알림이 가도록 만드는 장치를 만들었었다.
📌 테스트 실행 자동화
테스트를 필요한 건 무엇인가?
우선 소스 코드를 빌드하기 위한 환경이 마련된 서버가 필요하고, PR이 작성되거나 수정될 때마다 이벤트를 감지해 소스 코드를 내려받아 테스트를 실행해보면 된다.
테스트 서버를 하나 두거나, Github actions를 활용하면 가상 서버를 사용할 수 있다.
테스트 실행이 끝나면 실행 결과를 Github에 반환하고, 방금 전의 CI 파이프라인과 결합하면 테스트 결과 또한 팀원 전체에 쉽게 전달할 수 있다.
이전의 수동으로 모든 걸 처리하던 때와 차이점이 느껴지는가?
개발자는 그저 코드를 작성하고 PR만 작성했을 뿐인데, 통합을 위한 나머지 작업들은 모두 자동적으로 처리되고 있다.
📌 그 외
지속적 통합(Continuous Integration)은 개발자가 작성 혹은 수정한 코드를 중앙 레포지토리에 합치는 모든 과정에 대해 이야기한다.
그 말은 단순히 테스트나 PR 리뷰 뿐만 아니라, 통합을 위해 의사소통이 필요한 모든 과정에 걸쳐 자동화의 대상이 될 수 있음을 의미한다.
- Github Project나 Jira를 사용해 이슈의 상태(작업 전, 작업 중, 리뷰 중, 완료)를 관리한다면, 개발자가 수동으로 상태를 변경하지 않고 자동으로 변경되게끔 만들 수도 있다.
- 컨벤션에 맞게 코드를 강제하거나 자동으로 리포맷 되도록 만든다면, 리뷰의 속도가 더 향상될 수 있을 것이다.
- 코드 상 보안 취약점을 확인하고 싶다면 git guardian이나 자체적인 시스템을 사용할 수도 있다.
- 요샌 ChatGPT랑 연결해서 PR을 올리면 자동으로 코드 리뷰 해주는 기능도 있다.
- 그 외에도 다양한 종류의 테스트를 상황에 맞게 적용하고, 코드 커버리지 등을 검사할 수도 있다.
이 외에도 PM이나 디자이너와 같은 다른 부서의 사람들과의 소통 또한 자동화를 해볼 수 있을 것이다.
예를 들어, 빌드/테스트/성능 일일, 주간 평가 보고서를 자동으로 생성하게 한다던가...ㅎ
5. 지속적 배포(CD) 파이프라인 적용해보기
📌 규칙 파악하기
위에서 봤던 배포 과정을 다시 살펴보자.
우선 "코드는 검증이 되었음"을 전제로 두고, 중앙 저장소의 코드를 서버에 배포만 하면 되는 상황이다.
순서는 다음과 같다.
- 통합된 중앙 저장소의 코드를 내려받는다.
- 코드를 빌드한다.
- 빌드한 파일을 image로 만들어 DockerHub 올린다.
- 서버에 접근하여 DockerHub에 올린 image를 내려받는다.
- 컨테이너를 재실행한다.
📌 배포 자동화
이번에도 개발자는 PR을 브랜치에 병합만 하면 모든 일이 자동으로 처리되도록 구성해보자.
우선 중앙 저장소의 코드를 내려받고, 빌드한 후, DockerHub에 이미지를 만들어 올릴 장소가 필요하다.
이를 위해 빌드 서버를 마련할 수도 있고, Github actions의 가상 서버를 활용해도 충분하다.
(예전에는 Jenkins가 워낙 강력해서 필수 사항이었지만, 요샌 간단한 파이프라인은 Github actions를 사용하는 게 훨씬 쉽고 빠르게 구축할 수 있다.)
그 후, 배포 서버에서 DockerHub의 이미지를 내려받고 실행할 수 있도록 ssh이 됐건, ssm이 됐건 서버에 접속하여 나머지 스크립트를 실행하면 된다.
만약 실행해야 할 스크립트가 양이 좀 많다면, 별도의 쉘 스크립트 파일같은 걸 만들면 편할 것이다.
📌 그 외
지속적 배포(Continuous Deployment)는 배포 준비가 된 코드를 자동으로 배포하기 위해 필요한 모든 과정에 대해 이야기한다.
위의 상황에서 보다 개선해볼 수 있는 여지는 몇 가지 더 있다.
- 버전 관리를 위해 태깅을 하는 작업이 현재는 포함되어 있지 않지만, 이 또한 자동화할 수 있다.
- 배포 과정 중 문제가 발생했을 때, 롤백이나 재시도를 위한 프로세스를 도입하면 보다 안정적인 CD 파이프라인을 구축할 수 있다.
- 배포가 성공했을 때, 혹은 실패했을 때 알림을 전달하면 보다 신속하게 대응할 수 있다.
- 배포를 할 때마다 서비스가 중단되어선 안 되므로 무중단 배포 환경을 구성할 필요가 있는데, 여기엔 여러가지 전략들이 존재한다.
처음 CI/CD를 독학할 때 너무 힘들었던 기억이 있어서 정리해봤습니다.
그런데 요샌 잘 정리해놓은 블로그들이 예전보단 잘 보이는 거 같아서 의미 없었을지도 ㅎ