Infra/Docker

[Docker] Apache - Tomcat(SpringBoot) 연동하기 (mod_jk)

당닝 2021. 11. 19. 10:57
728x90

Web Server와 WAS(Web Application Server)의 분리를 위해, Web Server인 Apache와 WAS인 Tomcat을 연동하는 방법에 대해 알아보도록 하겠다.

 

Web Server vs WAS

먼저, Web Server와 WAS의 차이에 대해서 알아보자.

  • 웹 서버는 정적인 컨텐츠(html, css, js)를 제공하는 서버이다.
    • ex) Apache, Nginx
  • WAS는 DB 조회나, 어떤 로직을 처리해야 하는 동적인 컨텐츠를 제공하는 서버이다.
    • ex) Tomcas, Jeus

즉, 웹서버와 WAS의 차이는 어떤 타입의 컨텐츠를 제공하느냐의 차이이다.

웹서버와 WAS는 각각 독립적으로 존재할 수 있다.

대부분의 WAS는 정적인 컨텐츠를 제공해주고 있기 때문에, 웹 서버 없이 WAS만 존재할 수 있다.

 

그럼 왜 웹서버를 사용해야 할까?

 

1. WAS가 해야 할 일의 부담을 줄이기 위해서이다.

WAS 앞에 웹 서버를 둬서, 웹 서버에서는 정적인 문서만 처리하도록 하고, WAS는 동적인 로직을 수행하도록 기능을 분배하여, 서버의 부담을 줄이기 위한 것이다.

 

2. WAS의 환경설정 파일을 외부에 노출시키지 않도록 하기 위해서이다.

클라이언트와 연결하는 포트가 직접 WAS에 연결되어있다면 중요한 설정 파일들이 노출될 수 있기 떄문에 WAS 설정 파일을 외부에 노출시키지 않도록 하기 위해 웹 서버를 앞단에 배치시킨다.

웹 서버와 WAS에 접근하는 포트가 다르기 떄문에, WAS에 들어오는 포트에는 방화벽을 쳐서 보안을 강화할 수 있다.

 

 

 

아파치(Apache)와 CGI, 그리고 톰캣(Tomcat)

자바 웹 애플리케이션을 개발할 때 주로 사용하는 조합이 아파치와 톰캣이다.

아파치는 CGI(Common Gateway Interface)라는 것을 제공한다.

CGI는 이름 그대로 인터페이스로서, 웹 서버 상에서 프로그램을 동작시키기 위한 방법을 정의한 프로그램이다.

즉, PHP, Perl, Python 등의 언어들은 CGI를 구현해놓았기 떄문에, 아파치에서 다양한 언어로 짜여진 각 프로그램을 실행할 수 있다.

 

그런데 자바는 CGI로 구현되어 있지 않다. 따라서 톰캣은 Default Servlet을 통해 정적인 파일을 제공해주기 때문에 웹 서버의 역할을 할 수 있는 것이다.

 

아파치와 톰캣의 연동 원리는 다음과 같다.

 

Apache와 Tomcat이 연동하기 위해선 Apache가 외부서비스(WAS, Tomcat 등)와 연동하기 위해 정한 프로토콜인 AJP를 통해 서로 통신해야 한다. Apache는 AJP를 이용해 80포트(예시)로 들어오는 요청은 자신이 받고, 동적 컨텐츠를 필요로 하는 요청은 Tomcat에 접속하여 처리한다.

 

1. Apache는 httpd.conf에 Tomcat 연동을 위한 설정을 추가 및 Tomcat에서 처리할 요청 지정

2. 클라리언트는 Apache에 접속(80포트)

3. 만일 클라이언트의 요청이 Tomcat에서 처리하도록 지정된 요청이라면 Apache는 Tomcat의 AJP포트(8080포트, 예시)에 접속하여 요청을 전달

3. Tomcat은 Apache로부터 받은 요청을 처리하고 Apache에게 응답

5. Apache는 Tomcat에게 받은 응답을 클라이언트에 전달

 

연동 방식은 다음과 같다.

연결 방식 장점 단점
mod_jk - Tomcat Connector를 사용하는 방식
- 가장 많이 사용해온 방식
- mod_jk 관련 자료가 많음
- JKMount 옵션을 이용하면 URL이나 컨텐츠 별로 유연한 설정 가능
- 별도의 모듈 설치 필요
- 설정이 어려움
- Tomcat 전용
mod_proxy - Reverse Proxy 기능을 사용하는 방식
- 별도 모듈 설치를 필요로 하지 않음
- 특정 WAS에 의존적이지 않음
mod_proxy_ajp
mod_proxy_ajp - AJP Protocol을 Reverse Proxy로 사용하는 방식
- 별도 모듈 설치를 필요로 하지 않음
- 특정 WAS에 의존적이지 않음
- URL에 따른 유연한 설정이 어려움

 

 

 

 

아파치 웹 서버 구축하기
 

[Docker] Apache Web Server 구축하기

docker pull httpd httpd 이미지를 다운받는다. httpd는 아파치 HTTP Server 공식 이미지이다. 실습을 위해 프로젝트 폴더를 생성한다. 파일 구성은 다음과 같다. <!DOCTYPE html> Apache Web Server + Tomcat W..

da2uns2.tistory.com

먼저, 아파치 웹 서버가 구축되어있지 않다면 다음 글을 참고해주세요.

 

 

 

mod_jk 연동하기

mod_jk를 통해 아파치와 톰캣을 연동할 것이다.

 

 

tomcat-connectors 설치
docker exec -it 3tier-web-server-1 bash

먼저 도커로 만들어둔 아파치 웹서버를 실행한다.

 

apt-get update
apt-get upgrade

먼저, wget를 설치하기 위해 apt-get을 업그레이드한다.

 

apt-get install wget
apt-get install tar

wget과 tar을 설치한다.

 

cd /usr/local/src
wget http://www.apache.org/dist/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.48-src.tar.gz
tar -xzf tomcat-connectors-1.2.48-src.tar.gz

Index of /tomcat/tomcat-connectors/jk (apache.org) 에 접속해, 최신 버전에 맞게 1.2.48 부분을 변경한 후 wget 명령어를 통해 tomcat-connectors를 다운받는다.

tar 명령어를 통해 압축을 해제한다.

 

cd tomcat-connectors-1.2.48-src/native
./configure --with-apxs=/usr/local/apache2/bin/apxs

이 부분에서 애를 먹었다.

일단, cd 명령어를 통해 native 폴더로 이동한다.

 

이후, ./configure --with-apxs=/usr/local/apache2/bin/apxs를 통해 빌드를 해야한다.

만약 

need to check for Perl first, apxs depends on it...
checking for perl... /usr/bin/perl
could not find /usr/local/apache2/bin/apxs
configure: error: You must specify a valid --with-apxs path

와 같은 오류가 뜨면서 제대로 진행이 되지 않는다면, 다음을 확인해보자.

 

1. apxs 경로를 확인한다.

find / -name apxs

다음과 같이 입력해, 경로를 확인하고 /usr/local/apache2/bin/apxs과 다르다면, 올바른 경로로 수정한다.

 

2.

apt-get install libaprutil1-dev
apt-get install perl
apt-get install gcc
apt-get install gwak

내가 해결한 방법이다. 설치한 후, 재진행하면 정상적으로 빌드된다.

 

만약 위 방법으로도 해결되지 않는다면 apache - "You must specify a valid --with-apxs path" when building mod_jk on ubuntu - Stack Overflow를 참고해보자.

 

 

make && make install

마지막으로 make 명령어를 실행한다.

 

find / -name "mod_jk.so"

find 명령어를 통해, mod_jk.so가 잘 설치되었는지 확인한다. 

나의 경우엔 /usr/local/apache2/modules에 설치되었다.

 

 

아파치 설정

1. httpd.conf 수정

find / -name httpd.conf
vi 경로

를 입력해 httpd.conf의 위치를 찾고, vi 명령어에 그 경로를 입력한다.

 

LoadModule jk_module modules/mod_jk.so

<IfModule jk_module>
        JkWorkersFile conf/workers.properties
        JkLogFile logs/mod_jk.log
        JkLogLevel info
        JkLogStampFormat "[%y %m %d %H:%M:%S] "
        JkShmFile logs/mod_jk.shm
	JkMount /* worker1
</IfModule>

httpd.conf 파일 맨 아래에 다음과 같이 추가한다.

 

2. workers.properties 추가

vi worker.properties

같은 위치에 workers.properties를 추가한다.

 

worker.list=worker1
 
worker.worker1.port=8009
worker.worker1.host=톰캣 서버의 IP 주소
worker.worker1.type=ajp13

 

 

SpringBoot 설정

1. application.properties 값 추가

tomcat.ajp.protocol=AJP/1.3
tomcat.ajp.port=8009
tomcat.ajp.enabled=true

 

2. ContainerConfig 클래스 추가

package com.sample;

import org.apache.catalina.connector.Connector;
import org.apache.coyote.ajp.AbstractAjpProtocol;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ContainerConfig {
    @Value("${tomcat.ajp.protocol}")
    String ajpProtocol;

    @Value("${tomcat.ajp.port}")
    int ajpPort;

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createAjpConnector());

        return tomcat;
    }

    private Connector createAjpConnector() {
        Connector ajpConnector = new Connector(ajpProtocol);
        ajpConnector.setPort(ajpPort);
        ajpConnector.setSecure(false);
        ajpConnector.setAllowTrace(false);
        ajpConnector.setScheme("http");
        ((AbstractAjpProtocol<?>)ajpConnector.getProtocolHandler()).setSecretRequired(false);
        return ajpConnector;
    }
}

 

 

확인하기
2021-11-19 10:53:28.880  INFO 2584 --- [  restartedMain] org.apache.coyote.ajp.AjpNioProtocol     : Starting ProtocolHandler ["ajp-nio-127.0.0.1-18009"]

Springboot 프로젝트를 실행하고, 로그에 다음과 같이 떴다면 연동이 완료된 것이다.

 

 

 

 

참고

웹 서버와 WAS( Web Application Server ) 차이 :: victolee (tistory.com)

[Apache] Apache와 Tomcat 연동하기 (tistory.com)

Apache와 SpringBoot(Embedded Tomcat) 연동 (tistory.com)

 

728x90