32장 WAR를 유지할 것과 현대화할 것을 증거로 나눈다
컨테이너나 Kubernetes로 옮긴다고 레거시가 자동으로 현대화되지는 않는다. WAR 안팎의 상태와 연계를 모른 채 포장만 바꾸면 장애 위치만 이동한다. 먼저 현재 운영을 재현 가능하게 만든 뒤 변경 가치가 큰 경계부터 분리한다.
유지: 안정된 WAR 패키징, 검증된 Servlet 기능
외부화: 비밀, 환경 설정, session, 업로드 파일
분리: 중복 위험 배치, 독립 확장 가능한 읽기 API
교체: 지원 종료 JDK/Tomcat, 취약·무소유 라이브러리
폐기: 사용되지 않는 context, 계정, cron, 인증서
현대화 후보는 장애 빈도, 변경 빈도, 확장 병목, 규제 위험, 담당자 부재로 순위를 매긴다. strangler 방식으로 일부 경로를 새 서비스로 보내더라도 데이터 정본, 인증, transaction, rollback 경계를 먼저 정한다. dual write는 조용한 불일치를 만들 수 있으므로 reconciliation과 중단 기준이 필요하다.
실습 32 레거시 금요일 확장 캡스톤
다음 조건을 한 번에 받는다.
- Tomcat 9의
javaxWAR와 JDK 11 - 지원 patch upgrade 요청
- node 두 대와 sticky session
- JNDI pool 합계가 DB 한도에 근접
- 새벽 정산 cron이 두 노드에 존재
- Nginx에서 TLS 종료
변경을 patch upgrade, pool 조정, batch 단일화, session 시험 네 묶음으로 분리한다. 각 묶음에 증거, 승인, smoke, 보호 지표, rollback을 적는다. Jakarta 전환은 별도 프로젝트로 격리한다. 마지막으로 한 노드를 drain해 배포하고 외부 경로·로그인·DB·정산 fixture를 확인한 뒤 다음 노드로 진행한다.
레거시 확장 졸업 기준
- WAR 밖 의존성을 소유자와 함께 한 장에 그릴 수 있다.
- JDK·Tomcat·Servlet namespace·framework 호환을 행렬로 설명할 수 있다.
- JNDI pool의 전체 connection 예산과 classloader 위치를 계산할 수 있다.
- session·cache·파일·batch 상태가 롤링 배포에서 어떻게 움직이는지 말할 수 있다.
- 외부 proxy 경로와 내부 health의 차이를 실제 smoke로 검증할 수 있다.
- 노드·zone 장애에서 RTO/RPO와 데이터 일관성을 확인할 수 있다.
- WAR 유지와 현대화 대상을 유행이 아니라 운영 증거로 나눌 수 있다.
레거시 인프라 20개 미션 워크북
각 미션은 관찰, 위험, 변경, 검증, rollback, 소유자 여섯 칸으로 기록한다. 운영 서버에 쓰기 명령을 실행하지 않고 fixture와 스테이징에서 먼저 수행한다.
- 외부 URL에서 DNS·TLS·proxy·context·WAR까지 요청 경로를 그린다.
- JDK·Tomcat·Servlet/JSP·framework·JDBC driver 버전을 고정한다.
- WAR SHA-256과
WEB-INF/lib,web.xml, build info를 기록한다. CATALINA_HOME과 인스턴스별CATALINA_BASE를 구분한다.- systemd unit·EnvironmentFile·실행 계정·파일 권한을 검수한다.
- JNDI 이름·DB·pool·driver classloader와 전체 connection 예산을 계산한다.
- HTTP session attribute와 직렬화·sticky·failover 경로를 시험한다.
- 로컬 cache·임시 파일·업로드·공유 디렉터리를 찾는다.
- cron·WAS timer·DB job·외부 scheduler의 중복을 제거한다.
- SFTP/파일 연계에
.part, 원자 이동, 멱등 key를 적용한다. - Nginx host·proto·forwarded header와 신뢰 프록시를 확인한다.
- 내부 health, 기능 smoke, 외부 SNI 경로를 서로 다른 검사로 만든다.
- 한 노드를 drain하고 active request·session·batch가 빠지는지 본다.
- 새 WAR와 구 WAR가 같은 DB schema를 함께 사용할 수 있는지 시험한다.
- Manager·JMX·배포 계정의 역할과 접근망을 최소화한다.
- 인증서 SAN·키·체인·reload·외부 serial 확인을 반복한다.
- 노드 장애와 zone 장애의 capacity·RTO·RPO를 계산한다.
- 깨끗한 DR 환경에 아티팩트와 설정 정본으로 복구한다.
- 지원 종료·무소유·고장 빈도가 높은 의존성을 현대화 후보로 정렬한다.
- 금요일 캡스톤을 실행하고 타임라인·판정·남은 위험을 인계한다.
워크북 출간 판정표
| 항목 | 0점 | 1점 | 2점 |
|---|---|---|---|
| 인벤토리 | WAR 파일만 | 일부 설정 | proxy·JNDI·상태·배치·소유자까지 연결 |
| 호환성 | 버전 추정 | 버전 목록 | JDK·namespace·framework 통합 시험 |
| 상태 | sticky만 사용 | session 확인 | failover·직렬화·파일·batch 검증 |
| 배포 | 파일 복사 | health 확인 | immutable artifact·외부 smoke·rollback |
| 보안 | 관리자 공유 | 계정 분리 | 최소 권한·신뢰망·비밀·감사 증거 |
| 복구 | 재시작 | 이전 WAR | DB·session·DR·RTO/RPO 훈련 |
총점 10점 이상이고 인벤토리·상태·복구가 각각 2점이어야 현장 배포 후보로 본다. 이 표는 조직의 변경 승인과 보안 검토를 대신하지 않는다.
부록 A 30분 로컬 실습
cd war-deployment-operations
npm run qa
정상 결과는 테스트 5개, WAR 생성, 로컬 CA와 인증서 두 벌 생성, 1.0.0 sandbox 승격, 24장 웹북 생성이다. build/cert-fixture의 private key는 운영용이 아니며 npm run cert:fixture 때마다 다시 만들어진다.
실습 화면은 책에 포함된 Node.js HTTP server로 연다. 별도 Python 설치가 필요 없다.
npm start
# 브라우저: http://127.0.0.1:4182/dist/lab/index.html
Python 3가 이미 설치된 환경이라면 python3 -m http.server 4182 --directory .도 같은 용도로 쓸 수 있다. 두 서버 모두 로컬 실습용이며 외부 인터페이스에 공개하지 않는다.
파일을 file://로 열면 ES module import가 막힐 수 있다. 종료는 터미널에서 Ctrl+C다.
부록 B 운영 체크리스트
WAR
- [ ] source commit과 승인 PR이 고정됐다.
- [ ] build JDK, target bytecode, Tomcat/Servlet 호환성을 확인했다.
- [ ] 테스트·취약점·secret 검사가 통과했다.
- [ ] WAR 구조, checksum, SBOM을 보관했다.
- [ ] 환경 설정과 비밀이 WAR 밖에 있다.
- [ ] migration이 rollback window와 호환된다.
- [ ] health·smoke·지표 기준과 이전 버전이 준비됐다.
인증서
- [ ] TLS 종료 지점을 확인했다.
- [ ] SAN, notBefore/notAfter, key, chain을 검증했다.
- [ ] private key의 소유자와 권한이 최소화됐다.
- [ ] 설정 테스트 뒤 reload한다.
- [ ] SNI를 포함한 외부 handshake에서 serial을 확인한다.
- [ ] 갱신 실패와 만료 임박 경보가 있다.
- [ ] rollback 인증서가 유효하고 안전하다.
부록 C 공식 자료
- Apache Tomcat Migration Guide
- Tomcat 9에서 10으로 이관
- Tomcat 10.1 Manager App How-To
- Tomcat 10.1 Class Loader How-To
- Tomcat 10.1 Cluster 구성
- Tomcat 10.1 Session Manager 구성
- Tomcat 10.1 SSL/TLS Configuration How-To
- Apache Maven WAR Plugin, 3.5.1 기준
- Spring Boot Traditional Deployment
- Nginx HTTPS Server Configuration
- Certbot User Guide
위 링크는 2026년 8월 9일에 다시 확인했다. 당시 Apache Tomcat의 migration 페이지는 9.0.x, 10.1.x, 11.0.x를 지원 branch로 안내했고 세 branch 모두 Java 17에서 실행할 수 있다고 설명했다. 다만 애플리케이션이 실제로 요구하는 JDK·Servlet API·라이브러리 조합은 별도 검증 대상이다. major version을 올릴 때는 이전 conf를 통째로 복사하지 않고 새 버전의 기본 설정에서 필요한 차이만 이식한다.
Spring Boot의 traditional deployment 문서는 WAR 배포에서 SpringBootServletInitializer, war packaging과 embedded servlet container의 provided 범위를 요구한다. reactive WebFlux 애플리케이션은 WAR 배포 대상이 아니라는 경계도 확인한다. Tomcat 9에서 10으로 옮길 때 javax.*에서 jakarta.*로 바뀌는 것은 바이너리 호환 변경이 아니므로 소스·의존성·descriptor와 session persistence까지 staging에서 함께 검증한다.
공식 문서는 제품 버전과 운영체제에 따라 달라진다. 실제 서버의 정확한 version 문서를 변경 승인 시점에 다시 확인한다. 이 책은 공식 문장을 복제하지 않고 운영 판단과 실습을 독자적으로 구성했다.
부록 D 저작권·상표·보안
본문, 코드, fixture, SVG와 실습 화면은 이 책을 위해 새로 작성했다. Apache Tomcat, Maven, Spring, Gradle, Nginx, Certbot은 각 권리자의 명칭 또는 상표이며 제품 식별을 위해 사용했다. 제휴나 보증을 뜻하지 않는다. 외부 제품 화면과 로고, 타 도서의 표와 문장을 배포물에 포함하지 않는다.
실습 도메인은 예약된 .invalid 영역을 사용한다. 생성된 인증서와 private key는 로컬 교육용이다. 실제 조직의 인증서, 키, host, 계정, 로그를 출판 예제나 외부 AI 서비스에 입력하지 않는다.