'tomcat'에 해당하는 글 18건

 

우와... 난 처음 글을 쓰는 거라고 생각했는데, 약 15년 전에 tomcat5 를 가지고 연동했던 글이 있네. 그 동안 아파치는 10년이 지나도록 apache3 도 내지 않고 있고...ㅋ

 

이렇게 사용하는 이유?는 성능을 위해서 일 수도 있겠고, 리소스 중복 줄이기나, 아파치의 특정 기능을 반드시 사용해야 하거나... 하겠지만, WAS 에서 인스턴스를 1개 정도만 사용한다면 글쎄... jmeter 등으로 테스트 해보고 결정하라. 인스턴스가 여러 개이고 동일한 정적 리소스를 사용한다면, 또 그 양이 방대하다면 리소스 중복을 줄일 수 있다는 이유로 apache 를 사용해 볼 만하다. 아니면 .htaccess? 아니면 php 랑 같이 쓴다던가. 아무튼... 이런저런 이유로 이 둘을 연동해야 한다면 해 봐야지.

 

테스트 환경 : CentOS 7 / Apache 2.4 / Tomcat 8.5 (instance1~3)
테스트 목표 : http://serverIP 80포트로 각 인스턴스에 AJP 통신 확인.(로드밸런싱 용도 아님)

 

 

1. Tomcat server.xml 설정 

 

(Apache / Tomcat 이 설치되어 있다고 가정)

$ vi /app/tomcat/instance1/conf/server.xml
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector protocol="AJP/1.3"
           address="::1"
           port="8009"
           secretRequired="false"
           redirectPort="8443" />

 

server.xml 에 AJP 관련 요소를 수정해야 한다. AJP(Apache JServ Protocol)은 웹서버와 WAS 간에 통신이 가능한 프로토콜이다. 우선 주석을 해제하고 인스턴스 별로 ajp port 와 https redirectPort 를 지정한다. secretRequired="false" 를 지정하지 않으면 아래의 에러를 만나게 된다.

 

Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.

 

 

2. Tomcat Connectors (mod_jk) 설치

의존 라이브러리 설치

 

# yum install gcc gcc-c++ httpd-devel


Download : https://tomcat.apache.org/download-connectors.cgi

 

$ cd /usr/local/src
$ wget https://mirror.navercorp.com/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.48-src.tar.gz
$ tar zxvf tomcat-connectors-1.2.48-src.tar.gz
$ cd tomcat-connectors-1.2.48-src/native/
$ ./configure --with-apxs=/usr/bin/apxs
$ make
$ make install


서버의 apxs 경로 확인 후 올바르게 입력

 

 

3. mod_jk 설정

 

apache 버전마다 설정은 조금씩 다르니 httpd.conf 파일 참고.

 

$ vi /etc/httpd/conf.modules.d/00-jk.conf
LoadModule jk_module modules/mod_jk.so

 

$ vi /etc/httpd/conf.d/mod_jk.conf
<IfModule jk_module>
  JkWorkersFile conf.d/workers.properties
  JkLogFile logs/mod_jk.log
  JkLogLevel debug
  JkShmFile run/mod_jk.shm
  JkMountFile conf.d/uriworkermap.properties
</IfModule>

 

 

4. workers.properties 추가

3개의 Tomcat 인스턴스가 있다고 가정하고 각 인스턴스의 이름과 포트 설정.

 

$ vi /etc/httpd/conf.d/workers.properties
worker.list=tomcat1, tomcat2, tomcat3

worker.tomcat1.type=ajp13
worker.tomcat1.port=8109
worker.tomcat1.host=localhost

worker.tomcat2.type=ajp13
worker.tomcat2.port=8209
worker.tomcat2.host=localhost

worker.tomcat3.type=ajp13
worker.tomcat3.port=8309
worker.tomcat3.host=localhost



5. uriworkermap.properties

 

uri 에 매칭되는 workers.properties 의 worker 인스턴스로 ajp 통신. 해당하지 않는 uri 는 apache 디렉토리에서 매칭.

/=tomcat1
/instance2/*=tomcat2
/instance3/*=tomcat3



6. 톰캣 웹사이트 고양이 복사

 

$ mkdir -p /app/tomcat/instance2/webapps/ROOT/instance2
$ mkdir -p /app/tomcat/instance3/webapps/ROOT/instance3
$ cp /app/tomcat/instance1/webapps/ROOT/*.* /app/tomcat/instance2/webapps/ROOT/instance2
$ cp /app/tomcat/instance1/webapps/ROOT/*.* /app/tomcat/instance2/webapps/ROOT/instance3

 

 

7. SELinux 에 AJP 포트 추가

 

SELinux 정책에 의해 AJP 연결이 추가로 필요할 경우, 해당 IP 를 추가한다.
(/etc/selinux/config 파일에 SELINUX 설정을 변경하는 것은 추천하지 않는다.)

 

# semanage port -a -t http_port_t -p tcp 8109
# semanage port -a -t http_port_t -p tcp 8209
# semanage port -a -t http_port_t -p tcp 8309
# semanage port -l | grep http_port_t
http_port_t        tcp      8309, 8209, 8109, 80, 81, 443, 488, 8008, 8009, 8443, 9000

 

semanage 명령어가 없을 경우, policycoreutils-python 설치

 

# yum install policycoreutils-python

 

 

8. Web Server / WAS 재구동 후 연동 확인

 

http://serverIP
http://serverIP/instance2/
http://serverIP/instance3/

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

 

Tomcat 에서 인스턴스를 여러개 만들어 서비스에는 성공하였지만, 각 인스턴스간에 세션을 공유해야 할 상황이라면 몇가지 설정을 추가해야 한다.

 

테스트 환경 : CentOS 7 / Tomcat 8.5
테스트 목표 : 구성된 인스턴스 간에 이동을 하더라도 session 유지

 

 

1. 현재 인스턴스 세션 확인

 

톰캣의 기본 고양이 화면 파일을 수정하여 세션ID 를 노출시켰다.

 

$ vi /app/tomcat/instance1/webapps/ROOT/index.jsp
<!-- 세션 사용하도록 항목 삭제나 변경. (기본값 session="true") -->
<%@ page session="false" %>

<!-- body 태그 안에 추가 -->
<%=session.getId()%>


http://serverIP:port1
http://serverIP:port2
http://serverIP:port3

 

EF5B9FCA054DBCEC5E3201DBA42C927A 처럼 보여지는 세션ID 는 세 인스턴스 간에 모든 다른 값을 출력할 것이다.

 

 

2. server.xml 파일 수정

server.xml 파일에 클러스터 설정의 주석을 해제한다.

상세 설정은 tomcat 웹사이트 참고 : https://tomcat.apache.org/tomcat-8.5-doc/cluster-howto.html 

 

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

 


3. 방화벽 port 추가

<Membership className="org.apache.catalina.tribes.membership.McastService"
            address="228.0.0.4"
            port="45564"
            frequency="500"
            dropTime="3000"/>


클러스터 멤버를 구성하는데 필요한 Multicast 기본 포트(45564)를 추가한다.
멀티캐스트(multicast)는 한 번의 송신으로 메시지나 정보를 여러 컴퓨터에 동시에 전송하는 역할을 한다.

 

# firewall-cmd --permanent --zone=public --add-port=45564/tcp
# firewall-cmd --permanent --zone=public --add-port=45564/udp
# firewall-cmd --reload

 

 

4. web.xml 파일 수정

각 인스턴스의 webapps/ROOT/WEB-INF/web.xml 파일 아래에 distribuable 요소를 추가하면, 해당 컨텍스트에 대한 클러스터링이 진행되며 세션 공유가 가능해 진다.

<web-app ...>
  <distributable/>
</web-app>



5. Apache / Tomcat 재부팅

http://serverIP:port1
http://serverIP:port2
http://serverIP:port3

재부팅 하면 포트간에 이동하여도 동일한 세션ID 가 유지됨을 확인할 수 있다.

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

 

부제: Tomcat multiple instances 자동 실행

 

작성해 놓은 스크립트를 부팅시 실행시키려면 rc.local 파일을 이용하면 된다. 하지만 rc.local 의 기본값은 부팅시 실행되지 않는다. rc.local 파일이 부팅시 실행되도록 먼저 설정하고, 원래 부팅시 실행하려던 스크립트들을 rc.lcoal 파일에 추가하도록 한다.

 

 

1. rc.local 파일 실행 권한 설정

 

 

# chmod +x /etc/rc.d/rc.local

 

 

2. runlevel3 환경이 셋업될 때 rc.local 이 실행되도록 스크립트 추가

 

# vi /usr/lib/systemd/system/rc-local.service

[Install]
WantedBy=multi-user.target

 

 

3. 부팅시 서비스 자동 실행 설정

 

# systemctl enable rc-local.service

 

 

4. rc.local 파일로 실행할 스크립트 추가

 

su - tomcat /app/tomcat/instance1/start.sh
su - tomcat /app/tomcat/instance2/start.sh
su - tomcat /app/tomcat/instance3/start.sh

 

 

5. 재부팅 후 자동 실행된 데몬들 확인

 

# shutdown -r now

 

$ ps -ef | grep tomcat

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

 

Tomcat 에서 여러 인스턴스를 관리하는 방법이 있다. CATALINA_HOME 디렉토리에서 필요한 부분만 복제하고 약간의 설정을 수정하여 인스턴스들을 구성할 수 있다. server.xml 파일 하나에 여러 호스트 정보를 등록하여 관리할 수도 있지만 이 경우 Tomcat 을 재구동하면 모든 서비스들이 재구동되는 단점이 있으므로 그다지 추천하지는 않는다.

 

[CATALINA_HOME]

  • Tomcat Engine 디렉토리 : bin, lib
  • Tomcat Instance 디렉토리 : conf(설정), logs(로그), webapps(소스), work(jsp구동), temp(임시)

 

위 내용들 중  Instance 디렉토리를 아래의 절차를 거쳐 별도로 구성해 주면 된다.(Tomcat 설치 생략)

 

  1. 필요한 만큼의 Tomcat Instance 디렉토리를 생성한다.
  2. CATALINA_HOME 으로부터 필요 디렉토리를 복제한다.(conf, webapps)
  3. server.xml 에서 port 등 환경을 변경한다.
  4. 인스턴스 실행/중지 스크립트를 만들고 실행한다.
  5. 방화벽에서 해당 port 를 추가한다.

 

테스트 환경 : CentOS 7 / Tomcat 8.5
테스트 목표 : 서버 ip 에 특정 포트들에 연결되는 여러 인스턴스 구동

 

 

1. Instance 디렉토리 생성

 

# mkdir -p /app/tomcat
# chown -R tomcat:tomcat /app/tomcat
# su - tomcat
$ cd /app/tomcat
$ mkdir -p instance1/logs

 

 

2. CATALINA_HOME 에서 디렉토리 복제

 

$ cp -a /etc/tomcat8/conf instance1
$ cp -a /etc/tomcat8/webapps instance1

 

 

3. server.xml 설정 변경

 

$ vi instance1/conf/server.xml

$ vi instance1/conf/server.xml

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

  <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

 

여기에 shutdown port 와 http 서비스 port / https port 를 바꿔준다. 인스턴스가 3개 라면 8005/8105/8205, 8080/8180/8280, 8443/8444/8445 처럼 포트가 겹치지 않고 기억하기 쉽도록 구성하면 된다.

 

 

4. 구동 스크립트 생성

 

$ vi instance1/startup.sh

#!/bin/sh
export CATALINA_HOME=/etc/tomcat8
export CATALINA_BASE=/app/tomcat/instance1
$CATALINA_HOME/bin/startup.sh

 

$ vi instance1/startup.sh

#!/bin/sh
export CATALINA_HOME=/etc/tomcat8
export CATALINA_BASE=/app/tomcat/instance1
$CATALINA_HOME/bin/shutdown.sh

 

$ chmod u+x startup.sh
$ chmod u+x shutdown.sh

 

이렇게 설정하면 Tomcat 설치 디렉토리에서는 구동 스크립트만 빌려 각각의 인스턴스를 구동할 수 있게 된다. 구성된 instance1 디렉토리를 필요한 만큼 복제한다.

 

$ cp -a instance1 instance2
$ cp -a instance1 instance3

 

복제 후에는 이미 진행했던 3,4 번 단계의 각 인스턴스 설정(server.xml, startup.sh, shutdown.sh)을 변경해 준다.

 

 

5. 방화벽 해당 port 추가

 

# firewall-cmd --permanent --zone=public --add-port=8080/tcp
# firewall-cmd --permanent --zone=public --add-port=8180/tcp
# firewall-cmd --permanent --zone=public --add-port=8280/tcp
# firewall-cmd --permanent --zone=public --add-port=8443-8445/tcp
# firewall-cmd --reload

 

 

6. 각 인스턴스 구동 후 확인

 

$ /app/tomcat/instance1/startup.sh
$ /app/tomcat/instance2/startup.sh
$ /app/tomcat/instance3/startup.sh

 

http://serverIP:instance1port
http://serverIP:instance2port
http://serverIP:instance3port


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Spring boot 웹 어플리케이션 개발시 Local 에서는 잘만 되던게, WAR 파일로 서버에 배포하면 404 error 날 때가 있다. 서버 로그에는 별 메시지가 없다. 단지 배포가 잘됐다는...;


INFO [dev.example.com-startStop-3] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive 
[/var/lib/tomcat8/webapps/auth/ROOT.war] has finished in [2,533] ms
cs


이럴 경우 local 에서 되던게 server 에서 안되는 것이니 서버 설정에 문제를 예상할 수도 있지만, 서버는 에러 발생 시 로그를 남긴다; 로그 없는 이 상황은 뭐라고 검색하기도 난해하고 참... 예상되는 문제를 하나씩 점검해 보는 수 밖에 없다. 내 경우는 main 클래스에 SpringBootServletInitializer 를 상속하지 않아서 생긴 현상임을 알게 됐다...


main 클래스에서 SpringBootServletInitializer 상속받고 configure 오버라이드 하면 된다.


@SpringBootApplication
public class Application extends SpringBootServletInitializer {
 
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
 
}
cs


이렇게 하면 컨테이너가 실행될 때 war로 배포된 Spring 웹 어플리케이션 컨텍스트가 준비된다.

Servlet3.0 이전의 web.xml 역할을 하는 셈.

또 깜빡하더라도 빨리 캐치하자.ㅋ


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,