서론
배치 스케줄링을 담당하는 Pipeline 프로젝트에서 FreeStyle프로젝트를 호출하는 과정에서,
FreeStyle 프로젝트 빌드넘버가 갱신되는 에러가 발생했다.
조사결과 딱 Pipeline Proj -> Freestyle Proj 하는 과정에서 reload-configuration 을 실행했더니
이 사단이 났다.
요약하자면 build.xml 에 대해 알아야한다.
정확히 어떤 것이 문제가 됐는지 하나하나 배워보자.
1. Jenkins 내부 파헤치기
젠킨스는 오픈소스다.
내부 jar 를 뜯어서 그의 뽀얀 속살을 보자.
- Jenkins 빌드 번호 관리 메커니즘
// jenkins.model.Jenkins.java
public class Jenkins {
private transient RunMap<Run> builds;
// 빌드 정보는 builds.xml에 저장됨
private void saveBuildNumbers() {
// 빌드 번호와 타임스탬프 저장
}
}
// hudson.model.Job.java
public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, RunT>> {
protected transient RunMap<RunT> builds;
// 다음 빌드 번호 결정
private synchronized int assignBuildNumber() {
int nextBuildNumber = getNextBuildNumber();
builds.put(nextBuildNumber, build);
return nextBuildNumber;
}
}
- reload-configuration 발생 시 동작
// Jenkins reload-configuration 처리
public void reload() {
// 모든 설정 리로드
this.servletContext.setAttribute("app", new Jenkins(root, servletContext));
// 빌드 정보 다시 로드
builds = new RunMap<>();
builds.load(); // builds.xml에서 정보 로드
}
- 빌드 번호가 달라지는 과정
상황:
1. 원래 빌드: myproj #4094 실행 중
2. reload-configuration 발생
3. 새 빌드: myproj #4095 시작
발생 순서:
1. Pipeline Job이 하위 프로젝트 호출
2. reload-configuration으로 Jenkins 재로드
3. builds.xml 재로드
4. 새로운 빌드 번호 할당
2. 대안 : reload-job 으로 reload-configuration 대체
젠킨스 조작에 사용된 jenkins-cli.jar 도 오픈소스다.
너도 예외는 없다. 낱낱히 발가벗겨 보자.
reload-job
명령의 Jenkins 내부 동작 분석:
- Jenkins CLI ReloadJobCommand
// jenkins.cli.ReloadJobCommand.java
public class ReloadJobCommand extends CLICommand {
@Override
protected int run() throws Exception {
// 단일 Job만 찾아서 처리
AbstractItem job = JobResolver.findSingleJob(jenkins, jobName);
job.doReload(); // AbstractItem의 doReload 호출
return 0;
}
}
- AbstractItem의 doReload 구현
// hudson.model.AbstractItem.java
public abstract class AbstractItem extends Actionable implements Item {
public synchronized void doReload() throws IOException {
checkPermission(CONFIGURE);
// 현재 설정 파일
XmlFile cfg = getConfigFile();
// 현재 트리거 상태 보존
Map<TriggerDescriptor,Trigger<?>> oldTriggers = getTriggers();
// 설정 다시 로드
load(cfg);
// 빌드 번호는 변경되지 않음
// nextBuildNumber는 유지
}
protected void load(XmlFile file) throws IOException {
// 설정만 다시 로드
// 빌드 정보나 번호는 건드리지 않음
}
}
- Job의 빌드 번호 관리
// hudson.model.Job.java
public abstract class Job<JobT extends Job<JobT, RunT>,
RunT extends Run<JobT, RunT>>
extends AbstractItem {
/** 다음 빌드 번호 */
private transient int nextBuildNumber = 1;
/** builds.xml에서 관리되는 빌드 정보 */
protected transient RunMap<RunT> builds;
/** doReload()에서 이 부분은 건드리지 않음 */
public synchronized int assignBuildNumber() throws IOException {
int number = nextBuildNumber++;
save(); // 빌드 번호 저장
return number;
}
}
- 실제 동작 분석
// 내부 동작 시퀀스
public class BuildSequence {
void sequence() {
// 1. reload-job 호출
job.doReload();
// 2. 설정 파일만 리로드
// - builds.xml은 건드리지 않음
// - nextBuildNumber 유지
// - 실행 중인 빌드 정보 유지
// 3. 트리거 상태 유지
// - 기존 타이머 유지
// - 스케줄링된 작업 유지
}
}
결론: reload-job
은 안전함
이유:
- 단일 Job의 설정만 리로드
- 빌드 번호 체계 유지
- 진행 중인 빌드에 영향 없음
- 트리거(타이머 등) 상태 보존
reload-job
은 reload-configuration
보다 안전하며, 단일 Job의 설정만 리로드하므로 빌드 번호나 진행 중인 작업에 영향을 주지 않는다.
3. build.xml 상세 보기
Jenkins의 builds.xml
파일에 대해 상세히 설명:
- 위치
JENKINS_HOME/jobs/[JOB_NAME]/builds/builds.xml
# 예: /var/lib/jenkins/jobs/my-pipeline/builds/builds.xml
- 파일 구조
<?xml version='1.0' encoding='UTF-8'?>
<builds>
<build>
<number>123</number>
<timestamp>1634567890123</timestamp>
</build>
<build>
<number>124</number>
<timestamp>1634567990123</timestamp>
</build>
<!-- 각 빌드별 정보 -->
</builds>
- 관련 Jenkins 코드
// hudson.model.RunMap.java
public class RunMap<R extends Run<?,R>> {
private final File buildsDir;
// builds.xml 로드
public synchronized void load() throws IOException {
XmlFile file = new XmlFile(new File(buildsDir, "builds.xml"));
if(file.exists()) {
builds.clear();
builds.putAll(((Map) file.read()));
}
}
// builds.xml 저장
public synchronized void save() throws IOException {
XmlFile file = new File(buildsDir, "builds.xml");
file.write(builds);
}
}
이러한 builds.xml
은 Jenkins의 빌드 이력을 관리하는 핵심 파일로, 빌드 번호 관리, 이력 조회, 롤백 등 다양한 용도로 사용된다.
반응형
'개발 > Linux & DevOps' 카테고리의 다른 글
Actuator 의 DB 헬스체크 (1) | 2024.12.18 |
---|---|
nginx, logrotate 운영 환경 세팅 (kill USR1, 파일디스크립터) (4) | 2024.07.22 |
Java Green Thread, Native Thread, Kernel Thread, User Thread + Jenkins Executor 최적화 (0) | 2024.07.11 |
aws 초청강의 - msa가 필요한 이유 (0) | 2023.03.24 |
도커 정보 초기화 (0) | 2023.02.28 |