본문 바로가기

Backend/Study

[DevOps]Jenkins CI/CD 파이프라인 구축 방법

반응형

0. 개요

  1. Jenkins CI/CD 파이프라인 구축 방법
  2. 아키텍처 개요와 설치 선택지
    • 2-1. 컨트롤러/에이전트, Docker vs Kubernetes
    • 2-2. 플러그인·크리덴셜·RBAC 기본
  3. 소스 관리와 트리거
    • 3-1. 멀티브랜치 파이프라인
    • 3-2. GitHub/GitLab Webhook 연동
  4. Jenkinsfile 설계(Declarative 중심)
    • 4-1. stages/steps/when/agent
    • 4-2. 캐싱·병렬·매트릭스 빌드
  5. 빌드·테스트·품질 게이트
    • 5-1. Node/Java 예시
    • 5-2. JUnit·SonarQube·SAST
  6. 이미지 빌드·아티팩트 관리
    • 6-1. Docker/BuildKit/Kaniko
    • 6-2. 태깅 규칙·레지스트리 푸시
  7. 배포 자동화
    • 7-1. Kubernetes(Helm/Kustomize)
    • 7-2. VM/서버(Ansible/Systemd)
    • 7-3. Blue/Green·Canary·롤백
  8. 프로모션·승인·보안
    • 8-1. 입력 승인 단계
    • 8-2. 시크릿·권한·감사
  9. 관측성·알림·운영
    • 9-1. 로그·리포트·Slack
    • 9-2. 리소스 최적화·백업
  10. 레퍼런스 Jenkinsfile
    • 10-1. 단일 서비스(REST)
    • 10-2. 매트릭스(노드 버전)
  11. 트러블슈팅
    • Webhook 미동작, 권한, 워크스페이스
  12. 체크리스트 & 운영 플레이북
  13. 결론 요약
  14. FAQ

1. Jenkins CI/CD 파이프라인 구축 방법

이 글은 팀 규모와 배포 환경(온프레미스·클라우드·Kubernetes)에 상관없이 재사용 가능한 Jenkins 표준 파이프라인 설계법을 안내합니다. 설치 아키텍처부터 멀티브랜치·Webhook 트리거, Jenkinsfile 작성, 테스트/품질 게이트, 컨테이너 이미지 빌드, 배포/롤백, 승인·보안, 관측성까지 실전 중심으로 정리했습니다.

2. 아키텍처 개요와 설치 선택지

2-1. 컨트롤러/에이전트, Docker vs Kubernetes

  • 컨트롤러(마스터): UI·큐·크리덴셜·잡 메타를 관리합니다. 빌드는 에이전트에서 수행해 분리합니다.
  • Docker 설치: 단일 호스트에 빠르게 구축. jenkins/jenkins:lts 컨테이너 + 호스트의 Docker 소켓 마운트로 이미지 빌드 가능(보안 주의).
  • Kubernetes 설치: Kubernetes Plugin으로 에이전트 Pod를 요청 시점에 생성·파괴(탄력적). 컨트롤러는 StatefulSet, 영속 볼륨으로 운영합니다.

2-2. 플러그인·크리덴셜·RBAC 기본

  • 필수 플러그인 예: Pipeline, Git, Blue Ocean(선택), Credentials, Kubernetes, Docker, GitHub/GitLab, JUnit, Warnings NG, Slack, SonarQube(선택).
  • Credentials: Username/Password, SSH Key, Secret Text, Secret File 유형을 폴더 단위로 관리하고, 잡에서는 credentialsId만 사용합니다.
  • RBAC: 폴더/잡 단위 권한을 최소화합니다. 민감한 작업(크리덴셜/시스템 설정)은 관리자 전용으로 분리하세요.

3. 소스 관리와 트리거

3-1. 멀티브랜치 파이프라인

  • 리포지토리 각 브랜치/PR에 있는 Jenkinsfile을 자동 탐지·빌드합니다. 브랜치 수명주기를 Jenkins가 추적하므로 운영이 단순합니다.
  • 브랜치 전략: main(배포), develop(통합), feature/*를 권장. 태그(semver)는 릴리스 파이프라인을 트리거하도록 규칙화합니다.

3-2. GitHub/GitLab Webhook 연동

  • GitHub: Repository → Webhooks에 Jenkins 엔드포인트(예: /github-webhook/) 등록. 토큰/SSL를 설정해 무결성을 보장합니다.
  • GitLab: Push events/Merge Request events를 Jenkins의 GitLab Plugin과 연계합니다.
  • Webhook 이벤트가 없다면 폴링이 필요해 빌드 지연·낭비가 발생하니, 가능하면 Webhook을 표준으로 채택합니다.

4. Jenkinsfile 설계(Declarative 중심)

4-1. stages/steps/when/agent

  • Declarative Pipeline은 표준화·가독성에 유리합니다. agent로 실행 환경(노드 라벨, Docker 이미지, K8s Pod 템플릿)을 정의합니다.
  • when 조건으로 브랜치/변수/태그에 따라 빌드 흐름을 분기합니다. 예: 태그일 때만 배포.
  • post 블록에서 항상/성공/실패/불안정 상황별 알림과 아티팩트 보존을 정의합니다.

4-2. 캐싱·병렬·매트릭스 빌드

  • 언어(예: Maven/NPM)의 캐시 디렉터리를 호스트 마운트 또는 Pod emptyDir에 연결해 속도를 높입니다.
  • parallel로 유닛/리눅스·윈도우·다중 런타임 테스트를 병렬화합니다.
  • matrix로 Node 18/20, JDK 17/21 등 조합을 한번에 검증합니다.

5. 빌드·테스트·품질 게이트

5-1. Node/Java 예시

  • Node: npm ci로 깨끗한 설치, npm test·커버리지 출력, npm run build로 번들 생성.
  • Java: mvn -B -DskipTests=false test package, Surefire 리포트와 JaCoCo 커버리지 게시.

5-2. JUnit·SonarQube·SAST

  • JUnit: junit '**/target/surefire-reports/*.xml' 등으로 테스트 결과를 수집, 트렌드와 실패 내역을 대시보드에서 확인합니다.
  • SonarQube: 분석 토큰을 크리덴셜로 저장하고 품질 게이트 상태에 따라 파이프라인을 중단해 코드 품질을 강제합니다.
  • SAST: 상용/오픈소스 도구 실행 후 취약점 임계치 기준으로 실패 처리(예: High 0개 미만 통과).

6. 이미지 빌드·아티팩트 관리

6-1. Docker/BuildKit/Kaniko

  • Docker-in-Docker(DinD): 간편하지만 권한 이슈가 큽니다. 빌드 전용 노드/Pod로 격리하세요.
  • BuildKit: DOCKER_BUILDKIT=1로 캐시·속도·보안 강화. --secret로 민감 정보 주입.
  • Kaniko(K8s): Docker 데몬 없이 컨테이너 이미지 빌드. Jenkins K8s 에이전트와 궁합이 좋습니다.

6-2. 태깅 규칙·레지스트리 푸시

  • 태그 전략: app:1.4.2, app:1.4, app:latest, app:git-<shortSHA>를 함께 푸시하면 추적·롤백에 유리합니다.
  • 레지스트리: ECR/GCR/Docker Hub/Harbor 등. 크리덴셜은 Jenkins에 저장 후 withCredentials 블록으로 사용합니다.

7. 배포 자동화

7-1. Kubernetes(Helm/Kustomize)

  • 릴리스 네임·네임스페이스·값 파일을 스테이지별(dev/stg/prod)로 분리하고, helm upgrade --install로 선언형 배포를 수행합니다.
  • 프로브(라이브네스/레디니스), 리소스 요청/제한, HPA를 차트 값으로 표준화합니다.

7-2. VM/서버(Ansible/Systemd)

  • 아티팩트를 배포 서버로 전송 → systemd 서비스 재시작 → 헬스체크. 무중단이 필요하면 Nginx 업스트림 스위치 또는 Blue/Green을 적용합니다.

7-3. Blue/Green·Canary·롤백

  • Blue/Green: 두 환경을 병행 구성하고 트래픽 스위치 후 검증. 실패 시 즉시 롤백.
  • Canary: 10%→30%→100%와 같이 점진 전개. Jenkins에서 단계별 승인·자동화 테스트를 끼워 넣습니다.
  • 롤백: 이전 이미지 태그·Helm 리비전·이전 아티팩트를 메타데이터로 기록해 원클릭 롤백을 준비하세요.

8. 프로모션·승인·보안

8-1. 입력 승인 단계

  • 프로덕션 배포 전 input 스텝으로 휴먼 게이트를 두고, 승인자 그룹을 RBAC로 제한합니다.

8-2. 시크릿·권한·감사

  • 시크릿은 Credentials·클라우드 시크릿 매니저로 관리하고, 파이프라인에는 환경 변수로만 주입합니다.
  • 컨트롤러는 인터넷 노출을 피하고 리버스 프록시/SSL/TLS를 강제합니다. 감사 로그를 외부 스토리지로 보관하세요.

9. 관측성·알림·운영

9-1. 로그·리포트·Slack

  • JUnit/코버리지/정적분석 리포트를 게시하고, 실패 시 Slack/Email로 즉시 알립니다.
  • 배포 후 헬스체크 API·e2e 스모크 테스트를 자동 실행해 배포 검증을 표준화합니다.

9-2. 리소스 최적화·백업

  • 에이전트는 에페메럴이 기본. 오래된 워크스페이스/아티팩트는 만료 정책으로 정리합니다.
  • 컨트롤러 구성/잡 정의/크리덴셜을 정기 백업하고, 복구 연습을 분기마다 수행합니다.

10. 레퍼런스 Jenkinsfile

10-1. 단일 서비스(REST) Declarative 파이프라인

pipeline { agent { label 'docker' } environment { REGISTRY = 'registry.example.com' IMAGE = "${REGISTRY}/app" COMMIT = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim() } options { timestamps() buildDiscarder(logRotator(numToKeepStr: '50')) disableConcurrentBuilds() } triggers { pollSCM('@daily') } // Webhook이 기본, 폴백으로 폴링 stages { stage('Checkout') { steps { checkout scm } } stage('Setup Node') { agent { docker { image 'node:20-alpine' } } steps { sh 'npm ci' sh 'npm run lint' } } stage('Test (parallel)') { parallel { stage('Unit') { steps { sh 'npm test -- --ci --reporters=junit' } } stage('E2E (smoke)') { steps { sh './scripts/e2e-smoke.sh' } } } post { always { junit 'reports/junit/**/*.xml' } } } stage('Build Image') { when { branch 'main' } steps { sh 'export DOCKER_BUILDKIT=1; docker build -t $IMAGE:git-$COMMIT -t $IMAGE:latest .' } } stage('Security Gate') { when { branch 'main' } steps { sh './scripts/sast.sh --fail-on-high' } } stage('Push Image') { when { branch 'main' } steps { withCredentials([usernamePassword(credentialsId: 'REGISTRY_CREDS', usernameVariable: 'U', passwordVariable: 'P')]) { sh 'echo $P | docker login $REGISTRY -u $U --password-stdin' } sh 'docker push $IMAGE:git-$COMMIT && docker push $IMAGE:latest' } } stage('Deploy to Staging') { when { branch 'main' } steps { sh 'helm upgrade --install app charts/app -n staging --set image.tag=git-$COMMIT' } } stage('Approval for Prod') { when { branch 'main' } steps { input message: '프로덕션 배포 승인?', ok: '배포' } } stage('Deploy to Prod') { when { branch 'main' } steps { sh 'helm upgrade --install app charts/app -n prod --set image.tag=git-$COMMIT' } } } post { success { slackSend channel: '#ci', message: "✅ ${env.JOB_NAME} #${env.BUILD_NUMBER} 성공" } failure { slackSend channel: '#ci', message: "❌ ${env.JOB_NAME} #${env.BUILD_NUMBER} 실패" } } }

10-2. 매트릭스 빌드(노드 18/20)

pipeline { agent none stages { stage('Matrix Test') { matrix { axes { axis { name 'NODE_VERSION'; values '18', '20' } axis { name 'OS'; values 'alpine', 'slim' } } agent { docker { image "node:${NODE_VERSION}-${OS}" } } stages { stage('Install & Test') { steps { sh 'node -v && npm ci && npm test' } } } } } } }

11. 트러블슈팅

  • Webhook가 동작하지 않음: 방화벽/리버스 프록시 경로, GitHub Secret 검증, Jenkins 로그(/github-webhook/) 확인.
  • 권한 오류: 크리덴셜 스코프(시스템/도메인) 확인, 폴더 상속 권한 충돌 점검.
  • 워크스페이스 충돌: disableConcurrentBuilds() 사용, 브랜치별 별도 워크스페이스 지정.
  • Docker 권한: 소켓 마운트 시 루트 권한 이슈 → 전용 빌드 노드 또는 Kaniko로 대체.
  • K8s 에이전트 실패: Pod 템플릿 이미지 풀 권한, 네임스페이스/리소스 쿼터, serviceAccount 권한 확인.

12. 체크리스트 & 운영 플레이북

  • 아키텍처: 컨트롤러 고가용성(백업/복구), 에이전트는 에페메럴, 플러그인 버전 고정.
  • 보안: HTTPS 강제, RBAC 최소 권한, 시크릿은 Credentials/SM, 감사 로그 외부 보관.
  • 품질: JUnit/커버리지/정적분석 필수, 품질 게이트 실패 시 배포 차단.
  • 배포: 태그 기반 릴리스, Helm/Kustomize 선언형, 롤백 스크립트 상시 준비.
  • 속도: 캐시(의존성/도커 레이어), 병렬/매트릭스, 무거운 단계는 전용 에이전트.
  • 가시성: Slack/이메일 알림, 대시보드(성공률/리드타임/주기 시간), 포스트 배포 스모크 테스트.

13. 결론 요약

Jenkins 파이프라인의 핵심은 표준화입니다. 멀티브랜치 + Declarative Jenkinsfile + 품질 게이트 + 컨테이너 이미지 빌드 + 선언형 배포(Helm) + 승인/롤백 규칙을 일관되게 적용하면, 팀 규모가 커져도 안정적으로 확장됩니다. 설치 환경은 Docker로 시작해 Kubernetes 에이전트로 확장하고, 시크릿/권한/감사와 같은 운영 가드레일까지 함께 자동화할 때 CI/CD는 비로소 개발 생산성 가속기가 됩니다.

14. FAQ

Q1. Jenkins와 GitOps(Argo CD 등)를 같이 써도 될까요?

A1. 네. Jenkins는 빌드/테스트/이미지 푸시에 집중하고, 배포는 Git 리포지토리의 선언적 매니페스트(Helm/Kustomize)를 업데이트해 Argo CD가 싱크하도록 분리하면 책임이 명확해집니다.

Q2. 파이프라인이 느립니다. 어디부터 최적화할까요?

A2. 의존성 캐시(예: ~/.m2, ~/.npm), Docker 레이어 캐시/BuildKit, 병렬 테스트, 매트릭스 축소, 에이전트 스펙 조정 순서로 진행하세요. 병목은 스테이지별 시간 분포로 파악합니다.

Q3. 보안상 Docker 소켓 마운트가 불가합니다. 대안은?

A3. Kubernetes 환경이면 Kaniko/Buildah를, VM 환경이면 Rootless BuildKit을 고려하세요. 레지스트리 크리덴셜은 Jenkins Credentials로 주입합니다.

반응형