아키텍처

톰캣의 주요 설정 파일인 server.xml 을 설명하기 전에 먼저 톰캣의 대략적인 아키텍처에 대해서 알아보자. 설정 파일 항목에서 아키텍처를 설명하는게 의아한 독자들도 있겠지만 server.xml 의 구조는 톰캣의 아키텍처와 모듈을 그대로 반영하였으므로  아키텍처를 이해한다면 설정 파일의 구성과 의미도 쉽게 이해할 수 있다.

톰캣은 HTTP 서버이며 서블릿/JSP 의 컨테이너이다. 위 그림처럼 계층적으로 개별 기능이 구현되어 있으며 모듈화되어 있다. 

커넥터는 클라이언트와 통신하는 모듈로 톰캣은 여러 가지 커넥터를 구현하고 있다. 기본 설정된 커넥터는 HTTP(8080 포트), AJP(8009 포트) 이며 HTTPS는 기본적으로는 꺼져 있다.

보통 HTTP/HTTPS 는 아파치 웹서버등 별도의 웹서버를 많이 쓰고 톰캣은 서블릿/JSP 처리용으로 사용하므로 HTTPS 커넥터가 꺼져 있어도 별 문제는 없다. 톰캣의 서버 모듈이 인스턴스 기동/종료용으로 또 하나의 포트(8005)를 사용하므로 기본적으로 톰캣이 사용하는 포트는 총 3개가 된다.

 

설정

구성 요소

아키텍처내 구성 요소별 용도는 다음 표와 같다. 

설정 파일

톰캣을 사용할때 주로 변경하는 파일은 server.xml 과 tomcat-users.xml 이다. 먼저 server.xml 파일의 구성을 살펴 보고 설정 파일을 확인해 보자.

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">

<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>

<Listener className="org.apache.catalina.core.JasperListener"/>

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>

<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

<GlobalNamingResources>

<Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" />

</GlobalNamingResources>

<Service name="Catalina">

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>

<Engine defaultHost="localhost" name="Catalina">

<Host name="localhost" appBase="webapps" autoDeploy="true" unpackWARs="true">

</Host>

</Engine>

</Service>

</Server>

 

이제 톰캣에 기본 포함된 server.xml 에서 주로 변경하게 되는 부분을 살펴 보자.


Server

Server 항목은 설정할 수 있는 속성 자체가 많지 않으므로 변경할 일이 거의 없다. 가끔 변경하게 되는 것은 톰캣의 인스턴스를 여러 개 사용할 경우 서버 포트 중복을 방지하기 위해  사용하는 포트 번호를 수정하는 경우가 있다. 기본적으로 8005이지만 9005등 다른 포트를 사용하면 된다. 

서버 속성중 shutdown="SHUTDOWN" 으로 설정되어 있는데 이럴 경우 TCP 소켓으로 톰캣의 서버 포트를 열고 SHUTDOWN 이라는 문자를 보내면 톰캣을 종료시킬 수 있다. 

편리하지만 보안상 취약할 수 있으므로 서버의 포트를 끄고 사용하는 경우가 있다. port="-1" 로 설정하면 서버 포트를 끌수 있다. 포트를 끌 경우 shutdown.sh 명령은 동작하지 않으므로 프로세스 정보를 보는 명령어인 ps 명령어로 톰캣의 프로세스 ID 를 얻어낸 후에 kill -TERM PID 와 같이 kill 명령어로 종료시켜야 한다.

또는 shutdown="MyShutdownCmd" 와 같이 종료 명령어 자체를 변경하면 종료 명령어를 알아야 종료 시킬수 있게 하는 방법도 있다.

 

Service

서비스 항목은 Connector 설정을 추가/변경할 경우 외에는 크게 수정할 일이 많지 않다. 커넥터 설정은 톰캣의 버전에 따라 약간 다른데 특정 버전은 AJP 커넥터 항목이 주석 처리된 경우도 있다.

아파치 웹서버와 AJP 방식으로 연결할 경우 반드시 AJP 커넥터를 설정해 주어야 한다.

커넥터 설정시 주의할 점은 HTTP 의 GET 요청 처리시 Encoding 방식이 지정되어 있지 않으면 톰캣은 ISO-8859-1 로 처리한다.

최근에는 URL 에 한글을 UTF-8 로 인코딩해서 전송하는등 GET 파라미터에  UTF8을 쓰는 경우가 많으므로 ISO-8859-1로 인코딩이 설정되면 한글이 깨져서 제대로 처리하지 못하는 경우가 발생할 수 있다.

URIEncoding="UTF-8" 설정을 넣어서 명시적으로 커넥터에서 데이타의 인코딩 방식을 알려주도록 하자.

 

Host

Host는 appBase 가 중요한 속성으로 기본 설정으로 웹 어플리케이션이 존재하는 경로를 나타낸다. 절대 경로나 상대 경로를 사용할 수 있으며 상대 경로일 경우 ${CATALINA_HOME} 변수를 참고하게 된다.

${CATALINA_HOME} 변수는 톰캣이 설치된 경로로 설정되며 톰캣이 /home/user/tomcat-7.0.50 에 설치되었을 경우 ${CATALINA_HOME} 는 /home/user/tomcat-7.0.50 가 된다.

autoDeploy 속성이 true 이면 웹 어플리케이션의 Java 소스나 JSP, .XML 설정이 변경되었을 경우 자동으로 배포를 수행한다. 편리하지만 성능 이슈가 있을수 있으므로 개발이나 테스트외에는 설정하지 않는게 좋다.


 

Context 

개별 컨텍스트는 웹 어플리케이션을 의미한다. 컨텍스트는 웹 어플리케이션을 webapps 폴더에 넣어주면 자동으로 설정된다.

특별히 Context 의 속성등을 커스텀 설정해야 할게 없다면 위와 같이 하는 방법을 권장한다.

만약 Context 설정을 직접 해야 한다면 server.xml 에 하는것 보다는 $CATALINA_BASE/conf/[enginename]/[hostname]/ 에 지정하는 것을 권장하고 있다.

웹 어플리케이션이 my-webapp.war 라면 conf/Catalina/localhost/my-webapp.xml 을 만들고 다음 내용을 넣어주면 autoDeploy 속성이 true 일 경우 자동으로 배포된다.

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/my-webapp" docBase="my-webapp"/>


 

배포하기(deploy)

일반적으로 많이 사용하는 웹 어플리케이션 배포 방식은 호스트 에 등록된 기본 appBase 디렉터리인 webapps 에 war 를 넣어주는 방식이다. 톰캣을 재시작하면 자동으로 배포가 이뤄지며 컨텍스트가 생성된다. URL이 / 인 어플리케이션을 ROOT 어플리케이션이라고 하며 파일 이름이 ROOT.war 이거나 디렉터리 이름이 ROOT 디렉터리가 있으면 자동으로 루트 어플리케이션으로 처리한다. 

 

톰캣은 동시에 여러 버전의 어플리케이션을 배포할 수 있다. 다음 표에 있는 규칙대로 war 파일을 배포하게 되며 Host 항목에 undeployOldVersions 가 true로 설정되지 않은 이상 기본적으로 예전 버전도 갖고 있으므로 잘못된 버전의 어플리케이션을 변경했어도 톰캣을 재구동하지 않고도 예전 버전으로 복구할 수 있다.

 

톰캣은  컨텍스트 경로가 지정되지 않으면 ROOT 컨텍스트로 처리를 하게 된다. 

지속적인 통합 서버로 많이 사용되는 jenkins 의 경우 홈페이지에서 jenkins.war 파일을 배포하고 있다.

이 파일을 webapps 에 넣으면 host-name/jenkins 의 URL 경로로 브라우저에서 접근할 수 있다. 호스트 이름이 ci.example.com 일 경우 http://ci.example.com/jenkins 가 된다.

jenkins.war 를 ROOT.war 로 이름을 변경하고 webapps 에 넣어주면 ROOT 컨텍스트가 되므로 http://ci.example.com 으로 연결할 수 있다.


이제 어플리케이션을 배포할 경우 톰캣의 관리자 기능을 이용하는 방법을 알아 보자. 

tomcat manager

톰캣은 웹 기반으로 톰캣의 호스트와 컨텍스트를 관리할 수 있는 편리한 관리자 도구를 제공한다. 관리자 기능을 사용하면 다음과 같은 일을 할 수 있다.

  • 원격으로 app 배포
  • 사용하지 않는 세션 정리
  • 컨테이너 재시작없이 app 배포 취소
  • 메모리 누수 분석
  • JVM 상태 확인 및 서버 상태 확인(커넥터, 클라이언트 연결 갯수등)

관리자 기능은 톰캣에 웹 어플리케이션으로 기본 내장되어 있으며 webapps 폴더밑에 host-manager 와 manager 라는 2 개의 어플리케이션을 통해서 사용할 수 있다.

두 어플리케이션 간 차이점은 host-manager 는 이름 그대로 톰캣의 호스트를 등록/삭제 관리할 수 있으며 manager 는 호스트내 컨텍스트(어플리케이션)을 관리할 수 있는 기능을 제공한다.

관리자는 tomcat-users.xml 에 설정할 수 있으며 역할 기반으로 설정할 수 있다. 기본 관리자 기능은 보안 문제때문에 막혀 있으니 관리가 기능을 사용할 수 있게 설정해 보자.

 

tomcat-users.xml 설정

이제 tomcat-users.xml 을 설정해 보자. 역할을 정의하고 사용자에게 허용할 역할을 설정하는 형식으로 설정되며 사전에 정의된 역할은 다음과 같다.

admin 으로 시작되는 역할은 host-manager 에 적용되며 manager 로 시작되는 역할은 manager 에 대응된다.


admin
  • admin-gui  - 웹 기반의 관리 콘솔로 로그인할 수 있는 역할이다.
  • admin-script - 텍스트 기반으로 어드민 기능을 사용할 수 있는 역할이다. 스크립트나 기타 자동화 기능을 사용하려면 필요하다.
manager
  • manager-gui — 브라우저로 로그인하기 위해 필요한 역할이다.
  • manager-status — 관리자로 로그인시 "Server Status" 페이지만 볼 수 있다.
  • manager-script — 플레인 텍스트 방식으로 관리자 기능을 사용할 수 있는 역할이다. 지속적인 통합서버에서 빌드가 끝나면 자동으로 배포를 하는등 자동화된 도구에서 연결할 경우 필요하다.
  • manager-jmx — JMX 프락시 인터페이스에 접근할 수 있는 권한이다. jmx 프락시는 http://yourhost/manager/jmxproxy URL 로 접근 가능하며 텍스트 기반으로 결과가 출력되므로 별도의 모니터링 프로그램을 작성하는 등의 경우에 유용하다.


이제 tomcat-users.xml 을 열고 다음과 같이 설정해 보자. 

<?xml version='1.0' encoding='utf-8'?>

<tomcat-users>

<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<role rolename="manager-gui"/>
<role rolename="manager-jmx"/>
<role rolename="manager-script"/>
<role rolename="manager-status"/>

<user username="HostAdmin" password="$trongPasswd" roles="admin-gui,admin-script"/>
<user username="ManaGer" password="$trongPasswd" roles="manager-gui,manager-script,manager-status"/>

</tomcat-users>

 

 먼저 role 구문을 살펴 보자. rolename 에 사전 정의된 역할을 기술한다. 주의할 점은 사용할 역할만 기술하고 사용하지 않는 롤은 삭제하는게 좋다.

그리고 user 구문에 로그인에 사용할 사용자 이름(username), 암호, 역할을 정의해 주면 된다. 웹 기반의 관리자는 manager-gui 권한만 있어도 되며 manage-script 권한을 줄 필요가 없다.

설정을 마쳤으면 톰캣을 종료후 재시작하면 관리자 기능을 사용할 수 있다.

username 은 id 와 동일한 용도이므로 manager, admin, tomcat 같이 유추하기 쉬운 것으로 설정하면 안 된다. 암호도 잘 알려진 암호인 s3cret를 사용하지 말고 안전한 암호를 사용하자.

 

관리자로 연결

톰캣의 기본 어플리케이션에는 관리자 링크가 있으므로 이것을 클릭해서 들어가도 되며 또는 URL 에 http://yourhost/manager 같이 manager를 기술하면 된다.

인증창이 뜨면 위에서 설정한 사용자 이름과 암호를 입력하고 로그인을 하자.

 

위와 같이 전첵 어플리케이션 목록이 보이고 우측에 시작, 정지, 재시작, 재배포할 수 있는 버튼이 표시되므로 개별 어플리케이션 별로 관리할 수 있다.


관리자로 어플리케이션 배포

관리자 화면에서 바로 어플리케이션을 배포할 수 있다. 관리자 메뉴중 Deploy 에서 기능을 수행할 수 있다.

먼저 Deploy directory or WAR file located on server 메뉴는 톰캣 서버에 있는 WAR 나 디렉터리를 배포할 수 있는 기능이다. 경로를 입력하고 Deploy 를 누르면 된다.

아래의 WAR file to deploy 는 PC 에 있는 war 를 배포할 수 있는 기능이다.

다음 순서로 배포해 보자.

  1. 파일 선택을 눌러서 PC 에 있는 war 파일을 선택한다. (예로 PC 에 있는 war 가 simple-webapp.war 라 가정하자)
  2. 선택이 완료되면 선택된 파일명이 표시된다. 이제 Deploy 버튼을 누르면 배포된다.
     
  3. 정상적으로 배포되었다면 전체 어플리케이션 목록에 표시가 된다. 그림에서 화살표 표시한 어플리케이션 이름을 클릭하면 브라우저로 컨텍스트로 연결하므로 사용이 가능하다.
     



IP 로 접근 제한 걸기

manager 와 host-manager 는 중요한 어플리케이션이므로 아이디/암호 기반으로 인증을 거쳐야 하지만 관리자로 접근할 IP 를 등록하고 다른 곳은 접근 자체를 막아 버리는 것이 좋다.

톰캣의 밸브 기능을 사용하면 파이프 라인 사이에 별도의 처리 기능을 반영할 수 있으므로 IP 기반 접근 제어가 가능하다.

 

밸브는 엔진, 호스트, 컨텍스트 기반으로 설정이 가능하지만 manager와 host-manager 컨텍스트에 IP 기반 접근 제어를 설정해 보자.

컨텍스트에 밸브 설정은 conf/server.xml 보다는 conf/Catalina/localhost/ 에 컨텍스트.xml 이름으로 설정하는 방법이 권장된다.

다음은 manager 컨텍스트용 설정으로 conf/Catalina/localhost/manager.xml 이름으로 저장하면 된다.

 

<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true">

<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1|192\.168\.1\.\d+"/>

</Context>

 

사용할 밸브는 RemoteAddrValve 이며 allow 속성에 허용할 IP를 적어주면 된다.  톰캣은 IP 패턴 처리시 java.util.regex 클래스를 사용하므로 정규식을 사용할 수 있다.

여러 개의 IP 를 적을 경우 | 를 구분자로 사용하며 IP의 대역을 지정할 경우 하나 이상의 숫자를 의미하는 정규식인 \d+ 를 사용하면 된다.

 


이제 톰캣을 재시작하면 허용되지 않은 IP 에서 manager 컨텍스트에 연결할 경우 HTTP 403 Forbidden 에러가 발생하는 것을 확인할 수 있다.

host-manager 에도 IP 기반 인증을 적용하려면 위 manager.xml  파일을 host-manager.xml 로 복사하면 된다.


다중 톰캣 인스턴스 사용

웹 어플리케이션의 크기와 복잡도는 나날이 증가한 반면 하드웨어는 가격이 낮아지고 고성능화 되고 있다. 복잡하고 중요한 어플리케이션이 한 서버에 여러 개 있을 경우 성능과 안정성을 위해 어플리케이션별로 별도의 톰캣을 구성하여 서비스 하는 것도 좋은 선택이다.

톰캣은 가볍고 설정이 간단하므로 여러 개의 인스턴스를 띄우는 것은 매우 쉽다. 다중 톰캣 인스턴스를 사용하기 위한 절차를 알아 보자.

  1. 신규 인스턴스용 톰캣을 별도의 디렉터리에 복사한다. 기존에 사용중이던 톰캣을 복사해도 되고 톰캣 홈페이지에서 새로 받아서 압축을 해제해도 된다. 기존에 사용하던 톰캣과 경로와 디렉터리 이름이 중복되지 않게 주의하자. 예로 기존에 사용하던 apache-tomcat-7.0.54 디렉터리를 apache-tomcat-7.0.54-new-app 로 복사해 보자.

    $ cp -a apache-tomcat-7.0.54 apache-tomcat-7.0.54-new-app

     

  2. 복사한 디렉터리로 이동한다.
  3. 에디터로 server.xml 을 열어서 커넥터의 포트와 서버의 포트(8005)를 중복되지 않게 수정하자.

    <?xml version="1.0" encoding="UTF-8"?>

    <Server port="9005" shutdown="SHUTDOWN">

    <!-- 중략 -->

    <Service name="Catalina">

    <Connector connectionTimeout="20000" port="9080" protocol="HTTP/1.1" redirectPort="9443" URIEncoding="UTF-8"/>

    <Connector port="9009" protocol="AJP/1.3" redirectPort="9443" URIEncoding="UTF-8"/>

    <Engine defaultHost="localhost" name="Catalina">

    <Host name="localhost" appBase="webapps" autoDeploy="true" unpackWARs="true">

    </Host>

    </Engine>

    </Service>

    </Server>

     

  4. 기존 배포된 어플리케이션이 필요없다면 삭제한다.

    $ rm -rf work/*

    $ rm -rf webapps/*

     

  5. 배포 하려는 어플리케이션을 webapps 에 복사한다.
  6. 톰캣을 시작하여 새로운 인스턴스의 정상 동작 여부를 확인한다.
  7. 아파치 웹서버와 연계가 필요하다면 포트가 변경되었으므로 아파치의 연계 설정을 새로 정의한다.