* 이 포스트는 학습 과정에서 그 내용을 기록한 글이기에 부정확한 정보가 포함될 수 있습니다.
따라서 해당 글은 참고용으로만 봐주시고 틀린 부분이 있다면 알려주시면 감사하겠습니다.
❗ 대상 독자 : CI/CD 파이프라인 구축에 입문하는 주니어 개발자
❗ 이 글은 기존 프로젝트에 github actions를 이용한 CI/CD를 구축하는 내용을 메인으로 합니다. 따라서 독자분이 기존 프로젝트에 사용했던 Git, Docker, Travis CI, AWS에 대해서 익숙하지 않으시다면 전체적인 프로세스를 개괄적으로 봐주시거나 아래 링크를 통해 모르는 부분을 질문해 보시길 추천드립니다.
* 잘 모르시는 기술은 로그인 필요 없이 이 곳에서 AI에게 물어보세요!
이번 포스트에선 Spring Boot, React.js, Docker, AWS를 사용했던 기존 프로젝트에 github actions를 활용하여 CI/CD 파이프라인을 구축하는 것을 다루겠습니다. 사실 현재 취직 전 막바지로 자바와 스프링 부트에 대한 복습을 하고 있었어서 따로 토이 프로젝트를 또 하거나 블로그 포스팅을 하려는 생각은 딱히 없었습니다만...
최근 이력서를 다듬다가 배포된 프로젝트가 잘 작동하는지 살펴보는데 질문 과정에서 아래와 같이 에러 메시지만 계속 날리고 있었습니다.

애초에 클라이언트에서 api 통신 에러 시 발생하는 모든 오류 메시지는 위로 통일했었기 때문에 브라우저상으론 알기 어렵고, 그래서 직접 배포된 서버에 가서 확인해 봤습니다.

한마디로 gpt api에게 요청할 때 기존에 사용했던 언어 모델인 text-davinci-003을 더 이상 사용할 수 없다는 거였죠. 애초에 현재 오픈된 gpt도 3에서 3.5로 업데이트되었기에 어쩌면 당연했었는데 좀 방치해 둔 감이 있었습니다. 그래도 공식 docs를 읽어보니 기존 엔진은 24년 1월 4일부로 더 이상 쓸 수 없다는 것 같았고 제가 며칠에 한 번은 체크하고 있었어서 바로 다음날 발견했기에 다행이긴 하네요.
여하튼 이 엔진만 바꿔주도록 서버에 코드 몇 줄만 수정해 주면 간단히 해결될 문제... 였겠지만 현재 제 배포 방식으론 그렇게 간단하게 수정할 수 있지 않더라고요.

'아니 이렇게 간단한 수정 사항도 서버에 적용하고 도커로 다시 빌드하고 서버 파일 교체하고 설정해 주고 도커 다시 켜주고.... 를 해야 한다고?'란 생각에 귀찮음이 몰려오던 그때, 더 귀찮아질 미래를 모르고 전 생각했습니다.
'아 그냥 자동 배포를 배워서 적용해 두면 저 귀찮은 짓을 할 필요 없겠지?'
CI/CD?
왜 CI/CD를 학습하려고 했는지 빌드업은 충분히 길게 쓴 것 같아서 이제 그것에 대해 설명해보려 합니다. 우선 현재 제가 적용한 방식을 간단히 설명하면 github에 commit만 push시 EC2의 라이브 서버에 자동 배포되도록 한 게 전부입니다. 간단하죠? 그런데 사실 이 과정은 실무에서 적용된 CI/CD 파이프라인의 프로세스를 엄청 압축한 것입니다.
이 글을 보신다면 CI/CD가 대충 무엇인지 아시겠지만 조금 설명해 보면 CI/CD는 지속적 통합(Continuous Integration)과 지속적 배포(Continuous Deployment)의 약자*입니다. 한마디로 CI/CD 는 소프트웨어 개발 및 배포 프로세스를 자동화하고 효율적으로 관리하기 위한 방법론과 도구들을 포함합니다. 더 간단히 서버 개발자용으로 요약하자면 '개발자가 코드만 수정하면 자동으로 테스트, 빌드, 배포, 환경 설정은 알아서 해주도록 구성해 놓는 것'을 뜻하죠.
* 바로 다음에서 추가 내용 서술
CD는 사실 지속적 배포뿐만 아니라 지속적 전달(Continuous Delivery)의 약자기도 합니다. 그래서 CD를 말하면 엄밀히 두 단어를 구분해야 맞겠지만 일반적으론 두 단어를 혼용하거나 두 단어가 가진 뜻을 합친 내용이 CD로 간주되기도 합니다. 그렇기에 보통 CI/CD를 구축한다고 하면 간단하게 다음과 같은 프로세스를 따라갑니다.

CI/CD 방법론을 더 풀어서 보자면 이거보다 훨씬 더 길지만 서버 개발자가 숙지할 사항으론 이 정도면 충분합니다.
개발에 입문하시고 작은 프로젝트만 하셨다면 굳이 복잡한 파이프라인을 타고 CI/CD를 왜 도입해야 하나?라고 생각하실 수도 있습니다. 하지만 프로젝트 규모가 커지고 투입되는 개발자가 많아진다면 이는 필수로 도입해야 합니다. CI 도입 필요성의 단적인 예로 과거 회사들에서 배포 전에는 모여서 코드를 통합하는 날을 따로 가졌었다고 합니다. 그 정도로 코드 통합과 테스트는 매우 중요한 일인데 이걸 자동화하면 아낄 수 있는 비용이 엄청나겠죠, 또 한 번이라도 내 프로젝트를 웹으로 배포해 본 경험이 있으시다면 CD의 중요성을 설명할 필요가 없을 정도로 체감하시리라 생각합니다.
프로젝트에 적용
제가 기존에 알고 있었고 보통 입문자라면 이렇게 알법한, 제가 이전 프로젝트에 사용했었던 CI/CD 파이프라인은 다음과 같습니다,

이 프로세스의 가장 큰 장점은 빌드와 배포가 분리된 점입니다. 원래라면 AWS CodeDeploy의 경우 git의 코드를 직접 받아서 빌드와 배포를 한 번에 진행할 수도 있습니다. 한마디로 위 과정에서 Travis CI와 S3를 사용하지 않을 수 있죠. 하지만 실무에서 CI/CD를 도입할 때 그렇게 빌드와 배포를 묶어버리면 확장성이 많이 떨어집니다. 단적인 예로 빌드를 하지 않고 배포를 해야 하는 경우에도 쓸데없이 빌드를 해야만 하므로 보통 실무에선 위처럼 둘을 분리해서 프로세스를 짜는 걸 추천합니다.
하지만 이 프로세스의 가장 큰 단점도 빌드와 배포가 분리됐다는 것입니다. 실무에선 여러 커스텀 설정에 용이하도록 프로세스를 세밀하게 분리하는 것이 당연합니다. 하지만 개인이 프로젝트에 CI/CD 구축을 경험하기엔 위의 프로세스는 대단히 번거롭습니다. AWS안에서 S3, CodeDeploy, EC2, RDS가 통합되어 있으니 조금 접근성은 있을지 몰라도 일단 하나하나 공부해야 하는 것은 달라지지 않습니다. 그런데 여기에 Travis CI, jupyter notebook까지 알아야 하죠. 뭐 사실 다른 프로세스도 각 툴들을 공부해야 하니 사실 학습할 게 많다는 것은 크게 와닿지 않을 수 있습니다. 하지만 제일 중요한 것은 너무 도구들을 많이 사용하다 보니 도구들 간의 설정 또한 그만큼 일일이 해줘야 한다는 겁니다.
우리가 스프링 부트로 코드를 짤 땐 build.gradle에 사용할 라이브러리명만 추가해 줘도 자동으로 버전을 설정해 주니 참 편합니다만 CI/CD에선 다릅니다. EC2에 관련 툴들을 깔 때도 모두 버전을 체크해줘야 하는 것부터 Travis CI와 AWS 간 IAM 등의 설정까지... 말하기도 너무 긴 과정을 직접 해줘야 합니다. 이렇게 설정을 많이 건드리고 리눅스에서 개발자가 해야 할 일이 많기에 접근성이 좋을래야 좋을 수가 없습니다.
그렇기에 앞서 얘기한 것처럼 S3와 Travis CI를 쓰지 않고 CodeDeploy로 빌드와 배포를 한 곳에 묶어 버릴 수도 있습니다만 이 역시 git과 CodeDeploy를 연동해야 하기에 설정할 게 좀 많습니다.(실제로 설정하다가 며칠 날려봤기도 하고...)
그렇기에 제가 처음 새로운 토이 프로젝트를 시작했을 때 너무 많은 시간이 뺏길 거 같아서 간단하게 스크립트 배포로 끝냈던 것 같네요. 그런데 이번에 새로 학습한 프로세스는 보다 간단했고 시간도 그렇게 크게 뺏기지 않았습니다.

이 수정된 프로세스의 가장 큰 장점은 CI/CD에 사용되는 플랫폼이 Git과 AWS으로 단 둘만 존재한다는 것입니다. 아무리 서비스 간 통합이 잘 되어 있어도 사용하는 플랫폼이 다르다면 무조건 설정에 학습 시간을 써야만 합니다. 또한 사용해야 하는 툴을 처음 접한다면 더더욱이요.

하지만 우리가 개발할 때 VCS로 git을 안 써본 사람이 있을까요? 게다가 이 프로세스는 빌드와 배포를 github actions에서 워크플로우 파일 하나만 작성한다면 ok므로 정말 간단합니다.
여기서 질문이 있을 수도 있습니다. 'actions를 사용해도 aws와 통합해야 하니 설정이 필요한데 기존처럼 CodeDeploy를 사용해도 어차피 git과 설정하는 거나 다른 게 없지 않냐?'라고요. 맞습니다. 그래서 우리는 이 프로세스에서 Docker를 추가로 사용하는 겁니다!
기존 프로젝트에선 CodeDeploy를 통해 스크립트로 배포했었습니다. 하지만 그 과정에선 EC2에 직접 java와 node.js를 설치해야 하고 버전을 충돌하지 않게 맞춰줘야 하고 VPC와 서브넷도 직접 관리해줘야 하는 등 배포 과정 중 직접 해야 할 설정이 너무 많았습니다. 하지만 도커를 사용하면 이런 쓸데없는 설정들 필요 없이 EC2에 도커만 설치해 주면 간단히 끝납니다. 게다가 위 그림을 보시면 포워드 프록시로 nginX가 추가된 것을 보실 수 있는데 도커를 사용한다면 EC2에 특별히 다른 작업을 해줄 필요가 없습니다.
혹시 도커를 모르는 분들이 있을 수 있는데 간단히 말하면 개발 환경에 구애받지 않고 서비스할 수 있는 가상화된 컨테이너 기술입니다. 우리가 개발해서 로컬로 테스트하려면 프로젝트에 맞는 언어도 설치해야 하고, 라이브러리도 받아와야 하고, 버전도 서로 맞춰줘야 합니다. 그런데 도커를 사용한다면 그냥 도커만 깔면 컨테이너 안에서 테스트를 진행할 수 있는 거죠. 쉽게 맥을 사용하는데 윈도우를 켜기 위해 사용하는 VM머신과 비슷하다고 생각하면 됩니다. 자바를 사용하신다면 JVM을 떠올리시면 되겠죠?
마지막으로 기존에 배포된 EC2 서버를 관리하기 위해 jupyter notebook을 사용했었습니다. 제가 사용하는 노트북의 OS가 윈도우기 때문에 EC2를 관리하려고 SSH연결을 하려면 Putty가 필수적이고 pem키를 등록해 뒀다고 하더라도 매번 putty를 통해 EC2를 관리하고 모니터링하는 건 매우 매우 귀찮은 일이었습니다. 그래서 웹으로 EC2에 접근하기 위해 jupyter notebook을 설치하긴 했지만 이것도 초기 설정이 매우 매우 많습니다. 또한 이후 연결도 인증서 갱신이나 이런 게 필요해서 번거로운 점이 많았죠. 이것을 대체하기 위해 AWS에서 제공하는 SSM을 사용해 애초에 세션에 접근할 때 SSH연결 자체를 아예 할 필요 없게되어서 매우 편해졌습니다.
이번 포스트에선 일단 CI/CD를 프로젝트에 적용한 개괄적인 프로세스에 대해 간단히 적어봤습니다. 물론 CI/CD를 사용할 때 GitLab, Jenkins, CircleCI, AWS CodePipeline 등 본인에게 더 적합한 툴들이 많고 당연히 익숙하다면 그것들을 사용하면 됩니다. 하지만 기본적으로 github를 다들 사용하는 현재 github actions를 사용하는 건 매우 접근성도 좋고 합리적이라고 생각하기에 프로젝트에 적용해 봤고 이렇게 포스팅합니다. 다음 포스트에선 어떻게 제 프로젝트에 이 프로세스를 적용했는지 다루도록 하겠습니다.
refer
CI/CD 기본개념과 가장 많이 쓰이는 도구 5가지 | 하늘네트
CI/CD란? CI = 지속적인 통합(Continuous Integration); 한마디로 “빌드와 테스트 자동화” CD = 지속적인 전달(Continuous Delivery) 또는 지속적인 배포(Continuous Deployment); 한마디로 “배포 자동화” 덧붙이
www.hanl.tech
'Project' 카테고리의 다른 글
P4_기존 프로젝트에 CI/CD 파이프라인 구축하기(github actions)_2 (0) | 2024.02.02 |
---|---|
P3_GPT API로 프로그래밍 AI 웹서비스 만들어보기(spring Boot+React)_5 기능 명세 정의 (0) | 2023.02.26 |
P3_GPT API로 프로그래밍 AI 웹서비스 만들어보기(spring Boot+React)_4 CORS로 인한 기능 수정 (0) | 2023.02.09 |
P3_GPT API로 프로그래밍 AI 웹서비스 만들어보기(spring Boot+React)_3 리액트+스프링 부트 연동2 (0) | 2023.02.06 |
P3_GPT API로 프로그래밍 AI 웹서비스 만들어보기(spring Boot+React)_2 리액트+스프링 부트 연동1 (0) | 2023.02.05 |