본문 바로가기
CI.CD/Jenkins

[Jenkins] 입문: CI/CD의 중심

반응형

현대 소프트웨어 개발 생태계에서 가장 중요한 화두를 하나 꼽으라면 단연코 '어떻게 하면 더 빠르고 안전하게 배포할 것인가'일 것입니다. 과거에는 코드를 작성하는 개발 시간 자체가 중요했다면, 이제는 작성된 코드를 사용자에게 전달하기까지의 병목을 줄이는 딜리버리(Delivery) 과정의 혁신이 기업의 경쟁력을 좌우하고 있습니다. 이번 포스팅에서는 [Jenkins 실무 완벽 가이드] 시리즈의 첫 번째 핵심 주제인 Jenkins 입문: CI/CD의 중심에 대하여 상세한 개념, 아키텍처, 실무 도입 배경, 그리고 다른 도구들과의 비교까지 매우 깊이 있게 파헤쳐보겠습니다. 이 글을 끝까지 읽으신다면, 단순한 툴 사용법을 넘어 왜 Jenkins가 업계 표준으로 자리 잡았는지 완벽하게 이해하실 수 있을 것입니다.

📌 1. CI/CD(지속적 통합/지속적 배포)의 진정한 의미와 필요성

IT 업계에 종사하다 보면 CI/CD라는 용어를 수도 없이 듣게 됩니다. 하지만 이 개념을 실무에 완벽하게 녹여내어 '진정한 의미의 자동화'를 이룬 조직은 생각보다 많지 않습니다. CI와 CD는 서로 연결되어 있지만, 목적과 수행하는 역할이 명확히 다릅니다.

CI (Continuous Integration, 지속적 통합): 다수의 개발자가 작성한 코드를 중앙 코드 저장소(예: Github, Gitlab, Bitbucket)에 하루에도 여러 번, 지속적으로 병합(Merge)하는 과정입니다. 이 과정의 핵심은 단순한 코드의 병합이 아니라, '자동화된 빌드와 테스트'가 수반된다는 점입니다. 개발자 A와 개발자 B가 각자 완벽하게 작동하는 코드를 짰더라도, 두 코드가 합쳐졌을 때 예기치 못한 사이드 이펙트나 충돌(Conflict)이 발생할 수 있습니다. CI 파이프라인이 구축되어 있다면, 코드가 Push 될 때마다 자동으로 단위 테스트(Unit Test)와 통합 테스트(Integration Test)가 실행되어 이러한 문제를 조기에 발견할 수 있습니다. 즉, 버그가 운영 환경으로 넘어가는 것을 원천 차단하는 방어막 역할을 합니다.

CD (Continuous Deployment / Continuous Delivery, 지속적 배포 / 지속적 제공): CI 과정을 무사히 통과하여 검증된 코드를 실제 사용자가 접근할 수 있는 환경(Staging, Production 등)에 자동으로 릴리즈하는 과정을 의미합니다. 여기서 Delivery와 Deployment는 약간의 차이가 있습니다. Continuous Delivery는 배포 준비 상태까지만 자동화하고 실제 Production 반영은 관리자의 수동 승인(Manual Approval)을 거치는 것을 말하며, Continuous Deployment는 이 수동 승인 과정조차 없애고 테스트를 통과하면 즉각적으로 Production에 반영되는 궁극적인 자동화를 뜻합니다. CD가 도입되면 "배포하는 날"이라는 개념이 사라지며, 개발팀은 하루에도 수십 번씩 무중단으로 서비스를 업데이트할 수 있게 됩니다.


⚙️ 2. 수많은 CI/CD 도구 중 왜 아직도 Jenkins인가?

최근에는 Github Actions, Gitlab CI, CircleCI, Travis CI 등 YAML 기반의 직관적이고 모던한 SaaS(Software as a Service)형 CI/CD 도구들이 폭발적으로 성장하고 있습니다. 이들은 별도의 서버 구축 없이도 즉시 사용할 수 있다는 엄청난 장점이 있습니다. 그럼에도 불구하고, 대규모 엔터프라이즈 환경, 금융권, 그리고 보안이 중요한 온프레미스(On-premise) 및 폐쇄망 실무 환경에서는 여전히 Jenkins가 압도적인 점유율 1위를 굳건히 지키고 있습니다. 그 이유는 크게 다음과 같습니다.

  • 무한한 확장성과 방대한 플러그인 생태계: Jenkins 자체는 사실 아무런 기능이 없는 '껍데기'나 다름없습니다. Jenkins의 진정한 힘은 1,800개가 넘는 방대한 오픈소스 플러그인 생태계에서 나옵니다. AWS, GCP, Azure 배포 연동은 기본이고, Slack, MS Teams, Discord 알림, Jira 티켓 자동 생성 및 상태 변경, SonarQube를 통한 정적 코드 분석, Docker 및 Kubernetes 연동 등 상상할 수 있는 거의 모든 작업이 플러그인 설치 몇 번만으로 가능해집니다. 반면 다른 도구들은 기능 확장에 제한이 있거나 직접 스크립트를 짜야 하는 경우가 많습니다.
  • 비용 효율성과 무제한 에이전트 확장: SaaS형 툴들은 기본적으로 무료 플랜을 제공하지만, 빌드 시간(Build Minutes)이 늘어나거나 동시 빌드(Concurrent Builds) 개수를 늘리려면 엔터프라이즈 플랜을 구독해야 하며, 이 비용이 매달 수백에서 수천만 원에 달할 수 있습니다. 반면 Jenkins는 완전한 무료 오픈소스입니다. 회사의 유휴 서버 자원이나 저렴한 클라우드 인스턴스만 있다면, 비용 걱정 없이 수십, 수백 개의 빌드 에이전트(Agent/Node)를 연결하여 방대한 규모의 병렬 처리를 무료로 구성할 수 있습니다.
  • Pipeline as Code (Groovy)의 유연성: 모던 CI 툴들이 YAML 문법을 사용하여 직관성을 높인 반면, 복잡한 로직을 처리하는 데에는 한계가 있습니다. Jenkins는 Groovy 언어 기반의 파이프라인을 지원합니다. 이 덕분에 단순한 선언적(Declarative) 파이프라인뿐만 아니라, 복잡한 if-else 분기문, for 반복문, try-catch 예외 처리, 동적 노드 할당 등 프로그래밍 언어가 할 수 있는 모든 수준의 세밀한 제어가 가능합니다. "YAML로 안 되면 스크립트를 짜야 하지만, Jenkins 파이프라인(Groovy)으로는 안 되는 것이 없다"는 말이 실무에서 통용되는 이유입니다.
  • 보안 및 폐쇄망 환경의 필수 요건: 금융권이나 공공기관처럼 외부 인터넷망과 단절된 망분리(폐쇄망) 환경에서는 SaaS 툴을 아예 사용할 수 없습니다. 소스 코드가 외부 클라우드로 넘어가는 것 자체를 보안 규정상 금지하기 때문입니다. Jenkins는 사내망에 직접 설치하여 모든 빌드 프로세스와 소스 코드를 내부망 안에 완벽히 격리시킬 수 있는 최적의 솔루션입니다.

🏗️ 3. Jenkins의 아키텍처: Master와 Node(Agent)의 완벽한 분업

Jenkins를 실무에 도입하기 위해 반드시 이해해야 하는 핵심 구조가 바로 Master-Agent(Node) 분산 아키텍처입니다. Jenkins를 개인 PC나 작은 서버 한 대에 설치해서 빌드까지 다 돌려보면 잘 되는 것처럼 보이지만, 실무 환경에서 여러 팀이 동시에 파이프라인을 실행하면 서버가 OOM(Out of Memory)으로 쉽게 다운됩니다. 이를 방지하기 위해 역할을 철저히 분리합니다.

1. Jenkins Master (Controller):
Master는 오케스트레이터(Orchestrator) 역할을 합니다. 웹 UI를 사용자에게 제공하고, 파이프라인의 설정 정보와 플러그인들을 관리하며, 빌드 스케줄링을 담당합니다. Master는 직접 무거운 빌드를 돌리지 않고, "이 코드를 빌드해!"라는 명령을 Agent들에게 하달하는 역할만 수행합니다. 실무에서는 Master 노드 자체의 Executor 개수를 0으로 설정하여, Master가 실수로라도 무거운 빌드 작업을 직접 처리하지 못하도록 강제하는 것이 아주 중요한 Best Practice입니다.

2. Jenkins Agent (Node / Slave):
Master로부터 명령을 전달받아 실제 노동(소스코드 Clone, 의존성 패키지 다운로드, 컴파일, Docker 빌드 등)을 수행하는 워커(Worker) 노드입니다. Agent는 리눅스, 윈도우, macOS 등 다양한 운영체제로 구성할 수 있습니다. 예를 들어, iOS 앱을 빌드하려면 Xcode가 필요하므로 Mac 머신을 Agent로 연결하고, .NET 애플리케이션 빌드를 위해 Windows 머신을 연결하며, 일반적인 백엔드 서버는 Linux Agent에 할당하는 식으로 크로스 플랫폼 빌드 환경을 완벽하게 통제할 수 있습니다.


💡 4. 실무 도입 시나리오 및 파이프라인 자동화 흐름

이론을 넘어, 실제 대기업 및 유니콘 스타트업에서 구성하는 전형적인 마이크로서비스(MSA) 기반의 파이프라인 자동화 흐름을 살펴보겠습니다. 아래의 일련의 과정은 단 한 번의 클릭이나 명령 없이, 오직 개발자의 '코드 푸시' 하나만으로 3~5분 안에 전자동으로 이루어집니다.

  1. 이벤트 발생 (Trigger): 개발자가 로컬에서 기능 개발을 완료하고, Github의 feature/login-api 브랜치를 main 브랜치로 병합(Merge/Pull Request)합니다.
  2. Webhook 통신: Github에 등록된 Webhook이 사내 Jenkins 서버로 HTTP POST 요청을 보내어 "새로운 코드가 푸시되었음"을 알립니다.
  3. 작업 할당 및 Clone: Jenkins Master가 큐(Queue)를 확인하고, 쉬고 있는 Linux Agent(Node)에 작업을 할당합니다. Agent는 Github에서 최신 소스 코드를 git clone 합니다.
  4. 빌드 및 의존성 설치: Node.js 환경이라면 npm ci, Java Spring 환경이라면 ./gradlew clean build 명령어를 실행하여 코드를 컴파일하고 의존성 패키지를 묶습니다.
  5. 정적 코드 분석 (선택): SonarQube 서버로 소스 코드를 전송하여 보안 취약점, 코드 스멜(Code Smell), 중복 코드 등을 검사합니다. 품질 기준(Quality Gate)을 통과하지 못하면 파이프라인을 즉시 중단(Fail)시킵니다.
  6. 단위 테스트 (Unit Test): 미리 작성된 테스트 코드를 실행하여 로직의 결함을 검증합니다.
  7. 컨테이너화 (Dockerizing): Dockerfile을 기반으로 애플리케이션을 Docker 이미지로 빌드합니다. 버전 관리를 위해 태그(Tag)에는 Git Commit Hash 값이나 빌드 번호를 부여합니다.
  8. 이미지 푸시 (Push): 빌드된 Docker 이미지를 사내 프라이빗 레지스트리(Harbor)나 클라우드 저장소(AWS ECR, Docker Hub)에 업로드합니다.
  9. 배포 (Deployment): 배포 타겟인 Kubernetes 클러스터에 kubectl apply 혹은 Helm Chart를 통해 롤링 업데이트(Rolling Update) 명령을 내립니다. 기존 버전의 컨테이너가 서서히 내려가고 새 버전이 올라가며 무중단 배포가 완료됩니다.
  10. 결과 알림 (Notification): 성공 혹은 실패 여부와 상세 빌드 로그 링크를 사내 Slack 팀 채널로 자동 전송합니다. 실패했다면 즉시 개발팀이 인지하고 핫픽스(Hotfix)를 준비할 수 있습니다.

⚠️ 5. 실무 적용 시 주의할 점 및 트러블슈팅 (Troubleshooting)

Jenkins가 아무리 강력하더라도, 운영하다 보면 반드시 벽에 부딪히는 순간들이 옵니다. 초기 세팅 시 아래 사항들을 간과하면 큰 시스템 장애로 이어질 수 있습니다.

1. 무분별한 플러그인 설치 지양:
초보 관리자들이 가장 많이 하는 실수입니다. 좋아 보이는 플러그인을 무작정 설치하다 보면, 플러그인 간의 버전 의존성이 꼬여서(Dependency Hell) 젠킨스가 아예 부팅되지 않는 대형 사고가 발생합니다. 반드시 필요한 플러그인만 최소한으로 설치하고, 메이저 업데이트를 할 때는 플러그인 백업을 먼저 진행해야 합니다.

2. 디스크 용량 가득 참 (Disk Full) 현상 방지:
파이프라인이 하루에도 수십 번씩 돌다 보면, 각 빌드의 로그와 Workspace(소스코드 및 빌드 잔여물)가 서버 디스크에 그대로 남게 됩니다. 한 달만 방치해도 수백 GB의 용량을 갉아먹고 결국 디스크 100% 오류로 젠킨스가 멈춰버립니다. 이를 방지하기 위해 Job 설정에서 '오래된 빌드 버리기(Discard old builds)' 옵션을 켜서 최근 10~20개의 빌드 이력만 남기도록 설정하고, 파이프라인 post 구문에 cleanWs() 명령어를 넣어 빌드가 끝날 때마다 Workspace를 깨끗하게 비워주어야 합니다.

3. 백업 및 복구 (Disaster Recovery) 전략:
Jenkins의 모든 설정, 파이프라인 정보, 유저 계정은 JENKINS_HOME 디렉토리(주로 /var/jenkins_home) 안에 파일 형태로 저장됩니다. 만약 서버 스토리지가 물리적으로 파손되면 복구가 불가능합니다. 따라서 해당 디렉토리를 주기적으로 AWS S3나 별도의 외부 스토리지로 백업하는 스크립트를 크론(Cron)에 등록하여 운영해야 안정적인 인프라 관리가 가능합니다.


🎯 6. 마무리 및 요약

지금까지 Jenkins 입문과 CI/CD의 핵심 개념, 그리고 아키텍처 및 실무 도입 시나리오에 대해 3,000자에 가까운 방대한 분량으로 매우 상세하게 알아보았습니다. 단순한 개념 정리를 넘어, 현업에서 왜 Jenkins를 이토록 고집하는지, 그리고 인프라 관리자(DevOps)로서 어떤 부분을 신경 써서 구축해야 하는지 큰 그림을 그리실 수 있게 되셨을 것입니다.

CI/CD 파이프라인 구축은 단기간에 완성되는 것이 아니라, 팀의 개발 문화와 배포 프로세스에 맞춰 끊임없이 개선하고 다듬어 나가는 지속적인 여정입니다. 첫 단추를 어떻게 꿰느냐가 전체 아키텍처의 안정성을 좌우합니다. 이번 포스팅에서 다룬 Master-Agent 구조와 주의사항들을 잘 숙지하신다면, 추후 어떠한 장애 상황에서도 유연하게 대처할 수 있는 탄탄한 기본기를 갖추게 된 것입니다.

이론을 단단하게 다졌으니, 이제 본격적으로 실습에 돌입할 차례입니다. 이어지는 다음 포스팅에서는 이러한 개념을 바탕으로 호스트 리눅스 환경과 완전히 격리되어 부작용을 원천 차단하는 'Docker Compose 기반의 Jenkins 초고속 설치 및 설정 방법'에 대해 아주 구체적인 코드와 함께 실습을 진행해 보겠습니다. 기대해 주세요!

반응형