用 WAR 部署与并行部署做不停机切换
한국어 원문으로 표시합니다.
목표
WAR 배포의 실제 동작을 확인하고, 병행 배포(Parallel Deployment) 로 세션을 끊지 않고 버전을 올린 뒤, 검증까지 하는 배포 스크립트를 작성할 수 있게 됩니다.
왜 중요한가
단일 WAS 환경에서 무중단 배포를 하려면 L4 앞단에서 서버를 빼고 넣어야 한다고
생각하기 쉽습니다. 그런데 톰캣에는 원래 병행 배포 기능이 있습니다.
파일명에 ##버전 을 붙이면 같은 컨텍스트에 여러 버전이 공존하고,
기존 세션은 구버전으로, 신규 요청은 신버전으로 갑니다.
많은 SI 현장이 이 기능을 모른 채 새벽 정지 배포를 반복합니다.
또 하나 — 배포 스크립트가 전개 완료를 기다리지 않으면 실패한 배포를
성공으로 보고합니다. 그게 정지 배포보다 훨씬 나쁩니다.
단계
- Tomcat 을 기동하고
/opt/lab/samples/labhub-1.0.0.war를/opt/tomcat/webapps/labhub##001.war로 배포합니다.http://127.0.0.1:8080/labhub/version이1.0.0을 반환해야 하고,catalina.out에labhub##001배포 기록이 남아야 합니다. (이 배포 기록이 이후 단계의 증거로 쓰입니다.) - 전개된 디렉터리를 확인해
/root/tc/explode.csv를 만듭니다. 첫 줄은path,exists. 아래 네 경로에 대해Y/N을 적습니다.WEB-INF/web.xml,WEB-INF/classes,WEB-INF/lib,META-INF /opt/lab/samples/labhub-2.0.0.war를/opt/tomcat/webapps/labhub##002.war로 배포합니다. 이때##001을 먼저 지우지 말고 두 버전이 공존하게 두세요.http://127.0.0.1:8080/labhub/version이 이제2.0.0을 반환해야 하고,catalina.out에labhub##001과labhub##002배포 기록이 모두 있어야 합니다./root/tc/parallel.md를 작성합니다. 아래 세 가지가 본문에 들어가야 합니다.- 기존 세션을 가진 요청이 어느 버전으로 가는지
- 신규 요청이 어느 버전으로 가는지
- 버전 문자열이 문자열 비교로 정렬되므로
##1/##10같은 표기가 위험한 이유001과002두 문자열이 모두 등장해야 합니다.
##001버전을 완전히 제거합니다(WAR 와 전개 디렉터리 모두). 제거 후에도http://127.0.0.1:8080/labhub/version이2.0.0이어야 합니다./opt/lab/samples/labhub-boot.jar를 8082 포트로 백그라운드 기동하고 로그를/root/tc/boot.log로 남깁니다.http://127.0.0.1:8082/version이 200 이어야 합니다./root/tc/war-vs-jar.csv를 만듭니다. 첫 줄은항목,WAR,JAR.배포단위,톰캣버전관리,포트지정,롤백,무중단다섯 항목이 있어야 하고 각 칸은 비어 있으면 안 됩니다./root/tc/deploy-war.sh를 만듭니다. 인자 두 개(WAR파일 컨텍스트명)를 받아- WAR 파일이 없거나 크기가 0 이면 즉시 0 이 아닌 종료코드로 끝냅니다.
- 있으면
webapps로 배치하고 최대 30초 동안 폴링하며 전개를 기다립니다. http://127.0.0.1:8080/<컨텍스트명>/version이 200 이면 종료코드 0, 30초 안에 안 되면 0 이 아닌 종료코드로 끝냅니다.
참고
curl -s -o /dev/null -w '%{http_code}' <URL>로 상태코드만 얻습니다.- WAR 는 zip 입니다:
unzip -l 파일.war로 내용을 볼 수 있습니다. - 실행 가능 JAR 포트 지정:
java -jar app.jar --server.port=8082 - 흔한 실수 1: 복사 직후 바로 검증해서 404 를 실패로 판정하는 것. 폴링이 필요합니다.
- 흔한 실수 2:
##002를 배포하며##001WAR 를 먼저 지우는 것. 그러면 병행 배포가 아니라 그냥 교체 배포입니다. - 흔한 실수 3: 배포 스크립트가 검증 없이 항상 0 으로 끝나는 것. 실패한 배포를 성공으로 보고하는 스크립트가 가장 위험합니다.
첫 버전 배포
Tomcat 을 기동하고 /opt/lab/samples/labhub-1.0.0.war 를
/opt/tomcat/webapps/labhub##001.war 로 배포합니다.
http://127.0.0.1:8080/labhub/version 이 1.0.0 을 반환해야 하고,
catalina.out 에 labhub##001 배포 기록이 남아야 합니다.
(이 배포 기록이 이후 단계의 증거로 쓰입니다.)
파일명에 ##버전 을 붙이면 컨텍스트 경로는 ## 앞부분이 됩니다. 전개는 비동기라 복사 직후 바로 요청하면 404 가 날 수 있습니다.
전개 결과 확인
전개된 디렉터리를 확인해 /root/tc/explode.csv 를 만듭니다.
첫 줄은 path,exists. 아래 네 경로에 대해 Y/N 을 적습니다.
WEB-INF/web.xml, WEB-INF/classes, WEB-INF/lib, META-INF
WAR 는 zip 입니다. 전개된 디렉터리에서 표준 웹 애플리케이션 구조를 찾아보세요. 어떤 것이 필수이고 어떤 것이 선택인지가 이 단계의 학습 포인트입니다.
두 번째 버전 병행 배포
/opt/lab/samples/labhub-2.0.0.war 를
/opt/tomcat/webapps/labhub##002.war 로 배포합니다.
이때 ##001 을 먼저 지우지 말고 두 버전이 공존하게 두세요.
http://127.0.0.1:8080/labhub/version 이 이제 2.0.0 을 반환해야 하고,
catalina.out 에 labhub##001 과 labhub##002 배포 기록이 모두 있어야 합니다.
같은 컨텍스트 이름에 더 높은 버전 문자열을 붙여 배포합니다. 두 WAR 가 동시에 전개된 상태여야 하고, 새 요청은 높은 버전으로 가야 합니다.
세션 드레이닝 이해 정리
/root/tc/parallel.md 를 작성합니다. 아래 세 가지가 본문에 들어가야 합니다.
- 기존 세션을 가진 요청이 어느 버전으로 가는지
- 신규 요청이 어느 버전으로 가는지
- 버전 문자열이 문자열 비교로 정렬되므로
##1/##10같은 표기가 위험한 이유001과002두 문자열이 모두 등장해야 합니다.
병행 배포에서 기존 세션과 신규 세션이 각각 어디로 가는지를 문장으로 정리합니다. 버전 문자열이 문자열 비교로 정렬된다는 점도 함께 적어 두세요.
구버전 내리기
##001 버전을 완전히 제거합니다(WAR 와 전개 디렉터리 모두).
제거 후에도 http://127.0.0.1:8080/labhub/version 이 2.0.0 이어야 합니다.
구버전 WAR 와 전개 디렉터리를 함께 제거해야 합니다. 제거 후에도 서비스가 끊기지 않아야 하고, 버전 응답은 그대로 새 버전이어야 합니다.
실행 가능 JAR 기동
/opt/lab/samples/labhub-boot.jar 를 8082 포트로 백그라운드 기동하고
로그를 /root/tc/boot.log 로 남깁니다.
http://127.0.0.1:8082/version 이 200 이어야 합니다.
내장 톰캣 방식은 포트를 실행 인자로 줍니다. 백그라운드로 띄우고 로그는 파일로 남기세요.
WAR 와 JAR 비교표
/root/tc/war-vs-jar.csv 를 만듭니다. 첫 줄은 항목,WAR,JAR.
배포단위, 톰캣버전관리, 포트지정, 롤백, 무중단 다섯 항목이 있어야 하고
각 칸은 비어 있으면 안 됩니다.
기술적 우열이 아니라 '운영 절차가 어느 쪽으로 표준화돼 있는가'가 실제 선택을 좌우한다는 관점으로 정리해 보세요.
배포 스크립트 작성
/root/tc/deploy-war.sh 를 만듭니다. 인자 두 개(WAR파일 컨텍스트명)를 받아
- WAR 파일이 없거나 크기가 0 이면 즉시 0 이 아닌 종료코드로 끝냅니다.
- 있으면
webapps로 배치하고 최대 30초 동안 폴링하며 전개를 기다립니다. http://127.0.0.1:8080/<컨텍스트명>/version이 200 이면 종료코드 0, 30초 안에 안 되면 0 이 아닌 종료코드로 끝냅니다.
실패한 배포를 성공으로 보고하는 스크립트가 가장 위험합니다. 전개를 기다리는 폴링 루프와, 검증 실패 시 0 이 아닌 종료코드가 핵심입니다.