Tomcat & nginx 운영 · Tomcat 구조와 server.xml · 이론
Tomcat 을 열어 보면 무엇이 있는가
한 줄 요약
Tomcat 은 디렉터리 일곱 개의 역할만 알면 대부분의 운영 상황이 설명되고, 그중 실제로 사고를 내는 곳은 bin/setenv.sh·work/·logs/catalina.out 셋이다.
왜 아직도 Tomcat 인가
스프링부트를 쓰면 내장 톰캣이 들어 있으니 java -jar 로 끝난다.
그런데 국내 SI 현장에 나가면 여전히 독립 실행 Tomcat 에 WAR 를 올리는 시스템이
훨씬 많다. 이유는 기술적 선호가 아니다.
- 운영 조직이 WAS 단위로 관리한다. 서버 한 대에 여러 업무 WAR 를 올리고,
- 표준 프레임워크(전자정부 표준프레임워크 포함)와 배포 절차서가 WAR 기준으로 쓰여 있다.
- WebLogic/JEUS 를 쓰던 조직이 비용 절감으로 Tomcat 으로 내려온 경우, 운영 방식은 그대로다.
기동/정지/모니터링 절차가 WAS 기준으로 표준화돼 있다.
그래서 신입에게 첫 주에 떨어지는 일이 "톰캣 좀 띄워 보세요"인 것이다.
그리고 그 순간 systemctl start tomcat 이 안 되는 서버를 만난다.
디렉터리 지도
/opt/tomcat├── bin/ 기동·정지 스크립트. catalina.sh, startup.sh, shutdown.sh, setenv.sh├── conf/ 설정. server.xml, web.xml, context.xml, tomcat-users.xml, logging.properties├── lib/ 톰캣 자신과 모든 웹앱이 공유하는 JAR (JDBC 드라이버를 여기 두는 관행)├── logs/ catalina.out, localhost_access_log.*.txt, 각종 *.log├── webapps/ 배포 대상. WAR 를 두면 자동으로 같은 이름 디렉터리로 전개된다├── work/ JSP 를 컴파일한 .java/.class 캐시└── temp/ java.io.tmpdir현장에서 실제로 문제가 되는 지점만 짚자.
bin/setenv.sh— 톰캣이 기본 제공하지 않는 파일인데, 있으면catalina.sh가work/— 배포 후 화면이 옛날 그대로면 십중팔구 여기 캐시다. 배포 절차서에logs/catalina.out— 로테이션이 안 된다. 방치하면 수십 GB 가 된다.lib/vsWEB-INF/lib/— 같은 라이브러리가 양쪽에 다른 버전으로 있으면
자동으로 읽는다. JVM 옵션(CATALINA_OPTS)을 여기에 넣는다.catalina.sh 를 직접 고치면 톰캣 버전 올릴 때 사라진다. 반드시 setenv.sh 에 넣어라.
"work 디렉터리 삭제"가 들어가는 이유다.
디스크 풀로 인한 장애 원인 1위가 이 파일이다.
클래스로더 지옥이 열린다. NoSuchMethodError 가 나면 여기부터 본다.
server.xml 의 계층
server.xml 은 러시아 인형이다. 바깥에서 안으로 읽으면 이해가 빠르다.
<Server port="8005" shutdown="SHUTDOWN"> <!-- JVM 하나 --> <Service name="Catalina"> <!-- 커넥터들 + 엔진 하나 --> <Connector port="8080" protocol="HTTP/1.1" ... /> <!-- 바깥과 만나는 문 --> <Engine name="Catalina" defaultHost="localhost"> <!-- 요청 처리 엔진 --> <Host name="localhost" appBase="webapps" <!-- 가상 호스트 --> unpackWARs="true" autoDeploy="true"> <Valve className="...AccessLogValve" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service></Server>- Server 의
port="8005"는 서비스 포트가 아니라 종료 명령 수신 포트다. - Connector 는 뒤 모듈에서 통째로 다룬다. 여기서는 하나만 기억하자 —
- Host 의
appBase가webapps이고autoDeploy="true"라서 WAR 를 복사하면 - AccessLogValve 의
pattern에%D(처리 시간 ms) 를 넣지 않은 시스템이 아직도 많다.
shutdown.sh 는 여기에 TCP 로 접속해 SHUTDOWN 이라는 문자열을 보낸다.
즉, 이 포트가 열려 있고 문자열이 기본값이면 누구나 텔넷으로 WAS 를 내릴 수 있다.
보안 점검에서 항상 지적되는 항목이고, 조치는 두 가지다:shutdown 문자열을 길게 바꾸거나 port="-1" 로 아예 비활성화한다.-1 로 하면 shutdown.sh 가 안 되니 kill 로 내려야 한다는 점을 절차서에 적어 둔다.
커넥터는 여러 개 둘 수 있고, 각각 다른 포트/프로토콜/스레드풀을 갖는다.
전개된다. 운영에서는 autoDeploy="false" 로 두고 배포 스크립트가 명시적으로
전개하게 하는 조직도 많다. 실수로 파일이 들어가는 사고를 막기 위해서다.
응답시간이 액세스 로그에 없으면 "느리다"는 신고를 받았을 때 근거가 하나도 없다.
이건 오픈 전에 반드시 넣어라.
context.xml — 웹앱 단위 설정
conf/context.xml 은 전역, conf/Catalina/localhost/<앱이름>.xml 은 앱별 설정이다.
후자를 쓰면 webapps 바깥에 있는 디렉터리를 서비스할 수 있다(docBase).
배포 산출물을 /app/deploy/order 에 두고 톰캣은 건드리지 않는 운영 방식이 여기서 나온다.
DB 커넥션 풀(<Resource>)도 보통 여기 있다. 그래서 "DB 접속 정보 어디 있어요"의
답은 대개 context.xml 이거나 애플리케이션의 프로퍼티 파일 둘 중 하나다.
기동과 정지 — systemd 가 없을 때
# 기동 (백그라운드, catalina.out 으로 로그)/opt/tomcat/bin/catalina.sh start# 포그라운드 (컨테이너에서 쓰는 방식. 로그가 터미널로)/opt/tomcat/bin/catalina.sh run# 정지 (8005 포트로 SHUTDOWN 전송, 종료 대기)/opt/tomcat/bin/catalina.sh stop 30 -forcestop 뒤의 30 -force 는 "30초 기다리고 안 죽으면 kill" 이다.
운영 스크립트에는 이걸 넣는 것이 좋다. 세션 처리 중인 스레드가 있으면
톰캣은 얌전히 안 죽는 경우가 있다.
기동이 됐는지 확인하는 가장 확실한 방법은 프로세스가 아니라 로그와 포트다.
grep 'Server startup in' /opt/tomcat/logs/catalina.out | tail -1ss -ltn | grep 8080"프로세스는 떠 있는데 포트가 안 열린 상태"가 실제로 존재한다.
포트 충돌이나 초기화 실패로 커넥터만 죽은 경우다. 프로세스만 보고
"올라왔습니다"라고 보고하면 5분 뒤에 다시 전화를 받는다.
현장에서 만나는 모습
SI 현장에서 톰캣을 만지는 첫 주에 겪는 일은 대개 이 셋 중 하나다.
- "JVM 옵션을 넣었는데 안 먹어요."
catalina.sh를 직접 고쳤거나,setenv.sh를 만들고 재기동을 안 했다. 반영 여부는 파일이 아니라 프로세스에 물어야 한다 —/proc/<pid>/cmdline으로 실제 실행 인자를 본다. - "배포했는데 화면이 그대로예요."
work/에 남은 JSP 컴파일 캐시다. 배포 절차서에 "work 디렉터리 삭제" 가 들어가는 이유가 이것이고, 이 한 줄이 빠진 절차서로 몇 시간을 태우는 일이 실제로 생긴다. - "디스크가 꽉 찼어요."
catalina.out은 로테이션이 없다. 톰캣이 아니라 logrotate 쪽에서 잘라 줘야 하고, 방치하면 수십 GB 가 된다.
세 가지 모두 톰캣을 몰라서 생기는 문제가 아니라 어느 파일이 무엇을 하는지 몰라서 생기는 문제다. 그래서 디렉터리 지도가 먼저다.