⸻
1. 서론: 왜 ‘동적’ 파이프라인인가
• 규모의 경제: 수십 개 프로젝트를 개별 Jenkinsfile로 관리하면 유지보수와 표준화가 불가능
• 유연한 로직 주입: 빌드·테스트·배포 단계를 코드로 모듈화하고, 메타데이터에 따라 런타임에 조합
• 확장성 확보: 새로운 팀·서비스가 생겨도 Shared Library에만 템플릿을 추가하면 자동 반영
실리콘밸리·심천 톱티어 엔지니어들은 공통 로직을 Shared Library에 담고, Groovy 메타프로그래밍으로 파이프라인을 ‘동적으로’ 생성하여 수백 개 파이프라인을 일원화합니다. 이제 그 비법을 파헤쳐 보겠습니다.
⸻
2. 전체 아키텍처 개관
Jenkins Master
└── Shared Library Repo (vars/, src/, resources/)
├── vars/
│ ├── pipeline.groovy ← 메인 엔트리 포인트
│ └── stepRegistry.groovy ← 스텝 정의 저장소
├── src/
│ └── org/company/
│ ├── StageFactory.groovy
│ └── Utils.groovy
└── resources/
└── templates/
└── stageTemplate.gtpl ← GString 기반 템플릿
1. vars/
• pipeline.groovy: call(Map config) 로 파이프라인 생성
• stepRegistry.groovy: 서비스별·언어별 스텝 콜렉션
2. src/
• StageFactory: createStages(config) 로 동적 스테이지 리스트 반환
• Utils: 공통 유틸 함수 (GitTag 파싱, Slack 알림 등)
3. resources/
• GString 템플릿으로 복잡한 스크립트·YAML을 동적으로 생성
⸻
3. Jenkins Shared Library 심화
3.1 구조화된 Entry Point
// vars/pipeline.groovy
def call(Map config) {
node(config.nodeLabel) {
checkout scm
config = Utils.mergeDefaultConfig(config)
List<Stage> stages = StageFactory.createStages(config)
for (stage in stages) {
stage.run()
}
Utils.notifyBuild(config)
}
}
• config.nodeLabel, config.stages, config.notifications 등만 지정하면
• 나머지 로직(테스트, 패키징, 배포)은 모두 라이브러리 내부에서 처리
3.2 stepRegistry로 완전 분리
// vars/stepRegistry.groovy
def get(buildType) {
switch(buildType) {
case 'java': return ['compile', 'unitTest', 'codeCoverage', 'package']
case 'node': return ['npmInstall', 'lint', 'unitTest', 'bundle']
default: return ['shell']
}
}
• 서비스 언어·프레임워크별 기본 파이프라인 정의
• 신규 빌드 타입 추가 시 이 파일만 수정
⸻
4. Groovy 스크립팅 테크닉
4.1 CPS(Continuable Passing Style)와 non-CPS 조합
• @NonCPS: Groovy 컬렉션·메일 로직 같이 Jenkins CPS 변환이 필요 없는 함수에 적용
@NonCPS
def parseGitTag(String tag) {
// 복잡한 문자열 처리, CPS 변환 비허용 로직
return tag.tokenize('-')[1]
}
4.2 메타프로그래밍: AST 트랜스폼 활용
@groovy.transform.ASTTest(value={
assert node instanceof org.codehaus.groovy.ast.stmt.BlockStatement
})
def call(Map config) { ... }
• ASTTest로 컴파일 타임 검증
• 커스텀 AST 변환기로 @WithRetry 어노테이션 삽입
4.3 GString 템플릿으로 스크립트 생성
// resources/templates/deploy.gtpl
#!/bin/bash
kubectl set image deployment/${deployment} ${container}=${image}:${version}
def renderTemplate(name, binding) {
def tpl = libraryResource("templates/${name}.gtpl")
return tpl.toString().replace(/\$\{(\w+)\}/) { _, key -> binding[key] }
}
• 복잡한 배포 스크립트도 코드 변경 없이 템플릿만 수정
⸻
5. 동적 파이프라인 생성 패턴
5.1 파라미터 주도 단계 주입
// StageFactory.groovy
class StageFactory {
static List createStages(Map cfg) {
def steps = stepRegistry.get(cfg.buildType)
return steps.collect { stepName ->
return new Stage(name: stepName, action: { Utils.invokeStep(stepName, cfg) })
}
}
}
• cfg.buildType = 'java' 면 java 빌드 스텝 리스트를 동적으로 로드
• 신규 스텝 추가 시 registry만 갱신
5.2 Parallel & Conditional 스테이지
if (cfg.parallelTests) {
parallel cfg.testSuites.collectEntries { suite ->
["test-${suite}" : { Utils.runTestSuite(suite) }]
}
}
• parallel 키워드로 테스트 스위트를 동시 실행
• 프로파일 환경변수에 따라 분기
⸻
6. 실전 예제: End-to-End Jenkinsfile
@Library('company-shared-lib') _
pipeline {
agent none
parameters {
string(name: 'BUILD_TYPE', defaultValue: 'java', description: 'build type')
booleanParam(name: 'PARALLEL_TEST', defaultValue: true)
}
stages {
stage('Initialize') {
agent { label 'master' }
steps {
script {
pipeline([
nodeLabel: 'docker',
buildType: params.BUILD_TYPE,
parallelTests: params.PARALLEL_TEST,
notifications: [slack: '#builds']
])
}
}
}
}
}
• 한 줄 pipeline([...]) 호출로 전체 파이프라인 완성
• Shared Library 내부에서 복잡한 유효성 검사·Retry·캐시·알림 모두 처리
⸻
7. “아, 이런 방법도 있었구나” 팁
• Dynamic Agent Allocation
def agentLabel = Utils.chooseAgent(cfg.buildType)
node(agentLabel) { ... }
• Caching with Lock
lock(resource: "cache-${cfg.buildType}") {
Utils.restoreCache(...)
Utils.saveCache(...)
}
• 스크립트 승인 최소화
• @NonCPS 메서드로 CPS 변환 최소화 → Jenkins sandbox 예외 줄이기
• Library 내 버전 관리
• Semantic Versioning으로 @Library('company-shared-lib@v1.2.3') 사용
• Self-Healing DSL
retry(3) { pipeline(config) }
⸻
결론: 끝판왕 동적 파이프라인
• 모듈화 & 재사용: Shared Library에 모든 공통 로직 통합
• 메타프로그래밍: CPS vs non-CPS, AST 변환으로 초경량 코드
• 템플릿화: GString 템플릿으로 복잡 스크립트 생성
• 파라미터 주도: 실행 시점 config로 런타임 파이프라인 조립
“이제 수백 개 Jenkinsfile을 한 곳에서 관리하며, 새로운 서비스가 생길 때마다 5줄 config만 추가하면 동작하는 지구 최강 파이프라인”을 직접 경험해 보세요! 여러분의 CI/CD가 한 단계 더 진화합니다.
'IT & Tech 정보' 카테고리의 다른 글
통합 보안 스캔: SonarQube · OWASP ZAP · Snyk CI 파이프라인 연동 끝판왕 가이드 (0) | 2025.05.26 |
---|---|
모노레포 의존성 자동화: Nx & Lerna를 활용한 빌드 그래프 관리 끝판왕 가이드 (0) | 2025.05.26 |
정책 as Code 자동화: Open Policy Agent(OPA) & Gatekeeper 연동 끝판왕 가이드 (0) | 2025.05.26 |
GitOps 멀티클라우드 배포 자동화: FluxCD & ArgoCD 연동 (0) | 2025.05.26 |
AI가 인간의 ‘종료’ 지시를 거부하다: 역사상 첫 사례 심층 분석 (0) | 2025.05.26 |