Jenkins 서비스 자체가 재시작되지 않는 상황과 특정 Pipeline만 실패하는 상황은 출발점이 다릅니다. 전자는 Jenkinsfile의 Groovy 문법보다 컨트롤러 프로세스가 실제로 사용하는 Java 경로·버전과 첫 종료 로그를 먼저 확인해야 합니다. 반대로 Jenkins 화면은 열리고 특정 작업만 실패한다면 그때 Pipeline, 플러그인, agent, 빌드 도구를 좁혀 갑니다.
2026년 9월 28일 최신 Jenkins LTS 버전 엔드포인트가 반환한 2.568.3 WAR와 공식 SHA-256을 내려받아 검증한 뒤, Windows의 빈 JENKINS_HOME에서 Temurin JRE 17.0.20.1과 21.0.12.1로 같은 파일을 각각 실행했습니다. 운영 계정·플러그인·작업 데이터는 사용하지 않았습니다.
같은 WAR를 Java 17과 21로 바꿔 실행했다
| 실행 조건 | 관찰 결과 | 판정 |
|---|---|---|
| Jenkins LTS 2.568.3 + Java 17.0.20.1 | 약 0.5초 뒤 exit 1, HTTP 응답 없음 | 컨트롤러 기동 전 거부 |
| 같은 WAR + Java 21.0.12.1 | Jenkins is fully up and running, /login 200 |
초기 설정 화면까지 기동 |
| Java 21 HTTP 응답 | X-Jenkins: 2.568.3 |
실행한 WAR 버전과 일치 |

8개 기대 조건이 모두 통과했습니다. 두 JRE 압축 파일과 Jenkins WAR의 체크섬을 먼저 대조했고, Java 17 실행 로그에는 “현재 Java 17은 최소 요구 버전 Java 21보다 낮다”와 지원 버전 [21, 25]가 기록됐습니다. Java 21에서는 약 11.1초 뒤 완전 기동 로그를 확인했고 로컬 /login 요청이 200을 반환했습니다.
# 같은 WAR에 런타임만 바꾼 최소 재현 명령
java -jar jenkins.war --httpPort=12981 --httpListenAddress=127.0.0.1
# Java 17 핵심 관찰
Running with Java 17 ... older than the minimum required version (Java 21).
Supported Java versions are: [21, 25]
# Java 21 핵심 관찰
Jenkins is fully up and running
GET /login → 200
X-Jenkins: 2.568.3
포트 번호는 실행 때 비어 있는 loopback 포트를 동적으로 골랐기 때문에 운영 설정값이 아닙니다. 초기 관리자 비밀번호는 결과 파일과 이미지에 저장하지 않았고, 실행 후 프로세스와 격리 홈을 운영 환경과 분리했습니다.
서비스 실패인지 Pipeline 실패인지 먼저 가른다
| 첫 관찰 | 먼저 볼 위치 | 아직 손대지 않을 것 |
|---|---|---|
systemctl status jenkins가 failed |
서비스의 Java 경로·버전, 첫 종료 로그, 포트·권한 | Jenkinsfile 문법 수정 |
| 웹 화면 자체가 열리지 않음 | controller 프로세스와 reverse proxy를 분리해 확인 | 특정 stage 재작성 |
| 화면은 열리고 한 Job만 실패 | 해당 build console, Jenkinsfile, 사용 플러그인, agent | controller JDK를 무조건 교체 |
| controller는 정상, agent가 offline | agent JVM과 연결 로그 | 빌드 도구 JDK만 변경 |
java/javac build step만 실패 |
도구 설정과 그 step의 PATH·JAVA_HOME | 서비스 unit을 먼저 변경 |
Pipeline은 Jenkins 플러그인이 제공하는 DSL이며 Scripted Pipeline은 제한된 Groovy 계열 문법을 사용합니다. 그렇다고 Jenkins controller 프로세스가 별도 Groovy 실행 파일로 기동되는 것은 아닙니다. 서비스가 뜨기 전 Java 요구 버전에서 종료됐다면 groovy 패키지를 추가로 설치해도 이번 재현의 실패 조건은 바뀌지 않습니다.
Linux systemd에서는 실제 서비스 환경을 읽는다
이번 실험은 Windows WAR 직접 실행이므로 아래 systemd 명령을 이 컴퓨터에서 실행했다고 주장하지 않습니다. Linux 패키지 설치 환경에서는 Jenkins 공식 운영 문서가 안내하는 위치를 따라 다음 순서로 증거를 모읍니다.
sudo systemctl status jenkins --no-pager
sudo journalctl -u jenkins -b --no-pager -n 120
sudo systemctl cat jenkins
sudo systemctl show jenkins -p ExecStart -p Environment --no-pager
# 실행 중일 때 실제 바이너리 경로 확인 예시
pid=$(systemctl show -p MainPID --value jenkins)
sudo readlink -f "/proc/$pid/exe"
- status에서 exit code와 반복 재시작 여부를 확인합니다.
- journal에서 가장 마지막 stack trace보다 먼저 나온 원인 메시지를 찾습니다.
- systemctl cat으로 배포판 기본 unit과 drop-in override를 함께 봅니다.
- 셸의
java -version과 서비스가 선택한 Java가 같다고 추정하지 말고ExecStart, 환경 변수, 실제 프로세스 경로를 연결합니다.
공식 systemd 문서에 따르면 패키지 서비스의 수정은 기본 unit을 직접 편집하기보다 systemctl edit jenkins로 drop-in을 두는 방식이 기본입니다. 파일을 직접 바꿨다면 systemctl daemon-reload 후 재시작하고, 변경 전 systemctl cat jenkins 출력을 함께 보관해야 되돌릴 수 있습니다.
controller·agent·빌드 JDK를 세 칸으로 기록한다
| Java가 필요한 위치 | 영향 범위 | 확인 증거 |
|---|---|---|
| controller JVM | Jenkins 웹·스케줄링·플러그인 로딩 | controller 시작 로그, 프로세스 경로, 관리 화면 |
| agent JVM | 노드 연결과 Pipeline step 실행 기반 | agent 시작 명령·연결 로그·노드 정보 |
| build tool JDK | Gradle·Maven·javac가 만드는 산출물 | 해당 build step 안의 java -version·javac -version |
Jenkins Java 지원 정책도 컨트롤러·agent를 구동하는 런타임과 Java 프로젝트를 빌드하는 JDK를 구분합니다. 따라서 컨트롤러를 Java 21로 올렸다고 앱의 target Java가 자동으로 21이 되는 것은 아닙니다. 일부 플러그인은 더 엄격한 조건을 둘 수 있으므로 실제 설치 플러그인의 호환 조건도 함께 확인합니다. Flutter Android 첫 빌드 환경을 따로 확인해야 한다면 Flutter 설치부터 첫 Android 빌드까지의 점검 순서에서 SDK·기기·빌드 도구 경계를 이어서 볼 수 있습니다.
업그레이드는 교체보다 복구 조건을 먼저 만든다
운영 Jenkins라면 새 JDK 설치 직후 기존 버전을 지우는 순서로 진행하지 않습니다. Jenkins 버전, 플러그인 목록, JENKINS_HOME 백업·복구 방법, 기존 Java 경로를 먼저 기록합니다. 그 다음 테스트 환경에서 새 JDK로 controller와 agent 연결, 대표 Job, credential 사용, artifact 보관을 확인하고 되돌릴 Java 경로를 남긴 상태로 운영 변경을 진행합니다.
| 변경 전 기준 | 합격 증거 | 실패 시 복구점 |
|---|---|---|
| 현재 Jenkins·Java·플러그인 버전 기록 | 버전 조합표가 한 문서에 남음 | 기존 패키지와 JDK 경로 |
| 백업 복원 시험 | 격리 환경에서 Job·credential 참조 확인 | 변경 전 JENKINS_HOME 스냅샷 |
| 새 controller JVM | 완전 기동 로그와 로그인·상태 확인 | drop-in의 이전 Java 경로 |
| 대표 Pipeline | checkout·test·artifact·배포 전 단계 통과 | 이전 controller/agent 조합 |
출시 자동화에서 단순 성공 화면보다 실패·재시도·중복 실행을 확인하는 방법은 앱 출시 전 상태·동시성·오류 흐름 점검과 연결됩니다. 기술 스택을 고르기 전 빌드·배포 제약을 표로 만드는 방법은 Flutter·React Native·Kotlin·Swift 선택 검증에서 확인할 수 있습니다.
이번 재현에서 확인하지 않은 범위
- Windows에서 WAR 직접 실행만 비교했으며 Linux systemd 서비스를 실제로 기동하지 않았습니다.
- 빈
JENKINS_HOME의 초기 화면까지 확인했고 운영 플러그인·Job·credential 이관은 실행하지 않았습니다. - Java 25, controller-agent 연결, Maven·Gradle·Android 빌드 JDK는 실행하지 않았습니다.
- loopback HTTP만 사용했으며 reverse proxy, TLS, 방화벽과 8080 포트 충돌은 재현하지 않았습니다.
- Java 21에서 초기 화면이 열렸다는 결과는 개별 플러그인과 운영 Job의 호환성을 보장하지 않습니다.