Tomcat·nginx 배포·재기동
3. 코드 예제
예제 1: Tomcat 정지·시작 함수 — tomcat_deploy.sh 발췌
have_systemd() { systemctl list-unit-files "$TOMCAT_SERVICE.service" 2>/dev/null | grep -q "$TOMCAT_SERVICE"; }
tomcat_stop() {
if have_systemd; then systemctl stop "$TOMCAT_SERVICE"; return; fi
"$CATALINA_HOME/bin/shutdown.sh"
for _ in $(seq 1 "$STOP_WAIT"); do
pgrep -f "catalina.base=$CATALINA_BASE" >/dev/null || return 0
sleep 1
done
pkill -9 -f "catalina.base=$CATALINA_BASE"
}
tomcat_start() {
if have_systemd; then systemctl start "$TOMCAT_SERVICE"; else "$CATALINA_HOME/bin/startup.sh"; fi
}유닛이 있으면 systemctl, 없으면 catalina 스크립트를 쓰도록 한 함수에 묶었습니다. 호출하는 쪽은 서버가 어느 방식인지 몰라도 됩니다.
예제 2: 배포 본문 — tomcat_deploy.sh 발췌
WAR=${1:?사용: $0 <war> [컨텍스트]}
CTX=${2:-$(basename "$WAR" .war)}
STAMP=$(date +%Y%m%d_%H%M%S)
[ -f "$WEBAPPS/$CTX.war" ] && cp "$WEBAPPS/$CTX.war" "$BACKUP_DIR/$CTX.war.$STAMP"
tomcat_stop
rm -rf "$WEBAPPS/$CTX" "$WEBAPPS/$CTX.war"
rm -rf "$CATALINA_BASE/work/Catalina/localhost/$CTX"
cp "$WAR" "$WEBAPPS/$CTX.war"
tomcat_start
wait_health || { echo "롤백: $BACKUP_DIR/$CTX.war.$STAMP"; exit 1; }== deploy build/shop.war -> /opt/tomcat/webapps/ROOT.war
[dry] cp /opt/tomcat/webapps/ROOT.war /opt/tomcat/backup/ROOT.war.20260910_164211
== stop tomcat
[dry] /opt/tomcat/bin/shutdown.sh
[dry] rm -rf /opt/tomcat/webapps/ROOT /opt/tomcat/webapps/ROOT.war
[dry] rm -rf /opt/tomcat/work/Catalina/localhost/ROOT
[dry] cp build/shop.war /opt/tomcat/webapps/ROOT.war
== start tomcat
[dry] /opt/tomcat/bin/startup.sh
== health check http://localhost:8080/
== done (ROOT, backup=20260910_164211)DRY_RUN=1 이면 run 함수가 명령을 실행하지 않고 출력만 합니다. 배포 전 이 출력으로 경로가 맞는지 확인하고, 서버에서는 DRY_RUN 없이 실행합니다.
예제 3: nginx 설정 교체 — nginx_reload.sh 발췌
NEW=${1:-}
if [ -n "$NEW" ]; then
[ -f "$TARGET" ] && cp "$TARGET" "$TARGET.bak"
cp "$NEW" "$TARGET"
fi
if ! nginx -t; then
echo "문법 오류, 이전 설정으로 되돌립니다"
[ -f "$TARGET.bak" ] && cp "$TARGET.bak" "$TARGET"
exit 1
fi
systemctl reload nginx
sleep 1
systemctl is-active --quiet nginx || { systemctl restart nginx; exit 1; }== 설정 교체 bad.conf -> /etc/nginx/conf.d/myapp.conf
[dry] cp /etc/nginx/conf.d/myapp.conf /etc/nginx/conf.d/myapp.conf.bak
[dry] cp bad.conf /etc/nginx/conf.d/myapp.conf
== nginx -t (문법 검사)
문법 오류, 이전 설정으로 되돌립니다
종료 코드=1잘못된 설정을 넣으면 검사 단계에서 멈추고 .bak 으로 되돌립니다. reload 뒤 1초 후 is-active 로 살아 있는지 한 번 더 확인합니다.
예제 4: 리버스 프록시 설정 — myapp.conf
upstream myapp {
server 127.0.0.1:8080 max_fails=3 fail_timeout=10s;
}
server {
listen 80;
server_name myapp.example.com;
access_log /var/log/nginx/myapp.access.log;
location /static/ { root /opt/myapp/public; expires 7d; }
location / {
proxy_pass http://myapp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
}
}proxy_read_timeout 은 자바 앱의 가장 긴 요청보다 길어야 504 가 안 납니다. 엑셀 다운로드처럼 오래 걸리는 경로는 별도 location 으로 빼서 값을 따로 줍니다.