ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • docker를 활용한 apache-tomcat 이중화 서버 구현
    개발이야기 2021. 5. 13. 10:20

    개요

    이 글은 docker를 활용하여 httpd(apache) - tomcat 이중화 서버를 구현하는 방법을 정리한 글이다.
    이 글에서 사용된 소스코드는 github 에 업로드 되어 있으며 프로젝트 구조는 다음과 같다.

    디렉토리 구조
    ├── README.md
    ├── docker
    │   ├── docker-compose-httpd.yml
    │   └── docker-compose-tomcat.yml
    ├── httpd
    │   ├── build
    │   │   ├── Dockerfile
    │   │   └── run-httpd.sh
    │   ├── conf
    │   │   ├── httpd.conf
    │   │   └── magic
    │   └── conf.d
    │       ├── README
    │       ├── autoindex.conf
    │       ├── mod_jk.conf
    │       ├── uriworkermap.properties
    │       ├── userdir.conf
    │       ├── welcome.conf
    │       └── workers.properties
    ├── network.sh
    ├── scripts
    │   └── utils.sh
    ├── target
    │   └── ROOT.war
    └── tomcat
        ├── build1
        │   ├── Dockerfile
        │   ├── setenv.sh
        │   └── test.sh
        ├── build2
        │   ├── Dockerfile
        │   ├── setenv.sh
        │   └── test.sh
        ├── conf1
        │   ├── Catalina
        │   │   └── localhost
        │   ├── catalina.policy
        │   ├── catalina.properties
        │   ├── context.xml
        │   ├── jaspic-providers.xml
        │   ├── jaspic-providers.xsd
        │   ├── logging.properties
        │   ├── server.xml
        │   ├── tomcat-users.xml
        │   ├── tomcat-users.xsd
        │   └── web.xml
        └── conf2
            ├── Catalina
            │   └── localhost
            ├── catalina.policy
            ├── catalina.properties
            ├── context.xml
            ├── jaspic-providers.xml
            ├── jaspic-providers.xsd
            ├── logging.properties
            ├── server.xml
            ├── tomcat-users.xml
            ├── tomcat-users.xsd
            └── web.xml

    사용기술

    • docker
    • docker-compose
    • mod_jk, ajp/1.3

    버전정보(Dockerfile)

    • centos:7
    • apache 2.4
    • tomcat 9.0.45
    • tomcat-connectors 1.2.48
    • java-1.8.0-openjdk-devel.x86_64

    1. Dockerfile

    1.1 Httpd(Apache)

    FROM centos:7
    
    RUN yum -y update && yum clean all
    RUN yum -y install httpd httpd-devel gcc* make && yum clean all
    
    # Install mod_jk
    RUN curl -SL https://downloads.apache.org/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.48-src.tar.gz -o tomcat-connectors-1.2.48-src.tar.gz \
        && mkdir -p /src/tomcat-connectors \
        && tar xzf tomcat-connectors-1.2.48-src.tar.gz -C src/tomcat-connectors --strip-components=1 \
        && cd src/tomcat-connectors/native/ \
        && ./configure --with-apxs=/usr/bin/apxs \
        && make \
        && cp apache-2.0/mod_jk.so /usr/lib64/httpd/modules/ \
        && cd / \
        && rm -rf src/ \
        && rm -f tomcat-connectors-1.2.48-src.tar.gz
    EXPOSE 80
    
    # Timezone
    RUN mv /etc/localtime /etc/localtime_org \
        && ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
    
    # Simple startup script to avoid some issues observed with container restart
    ADD run-httpd.sh /run-httpd.sh
    RUN chmod -v +x /run-httpd.sh
    
    CMD ["/run-httpd.sh"]

    centos 7 기반에서 apache 웹 서버를 설치하고 tomcat과 연동하기 위해 mod_jk를 설치한다.

    1.2 Tomcat

    FROM centos:7
    
    RUN yum -y update && yum clean all
    
    # Install openjdk 1.8
    RUN yum install -y java-1.8.0-openjdk-devel.x86_64 
    # 다운로드 되는 파일의 버전과 일치
    ENV JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64 
    ENV export JAVA_HOME
    ENV PATH=$PATH:$JAVA_HOME/bin
    ENV export PATH
    
    # Install tomcat
    RUN curl -SL  https://downloads.apache.org/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz -o apache-tomcat-9.0.45.tar.gz \
      && mkdir -p /src/tomcat/ \
      && tar xzf apache-tomcat-9.0.45.tar.gz -C src/tomcat --strip-components=1 \
      && cd / \
      && mv /src/tomcat /usr/local \
      && rm -rf src/ \
      && rm -f apache-tomcat-9.0.45.tar.gz
    
    ENV CATALINA_HOME=/usr/local/tomcat
    ENV CATALINA_BASE=/usr/local/tomcat
    ADD ./setenv.sh /usr/local/tomcat/bin
    
    # Timezone
    RUN mv /etc/localtime /etc/localtime_org \
        && ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
    
    RUN rm -rf /usr/local/tomcat/webapps/*
    ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh", "run"]
    
    EXPOSE 8009

    마찬가지로 centos:7 기반에서 openjdk 1.8와 tomcat을 설치한다.
    openjdk 1.8을 설치하고 JAVA_HOME환경변수를 설정할 때 해당 경로에 설치된 파일의 버전을 확인하여 일치시켜야 한다.
    os시간과 tomcat 시간을 일치시키기 위해 setenv.sh파일을 Dockerfile 같은 경로에 생성한다. setenv.sh의 내용은 다음과 같다.

    #! /bin/bash
    export CATALINA_OPTS="$CATALINA_OPTS -Dfile.encoding=UTF8 -Duser.timezone=GMT+9"

    마지막으로 ajp/1.3 프로토콜에서 사용할 8009포트를 개방한다. tomcat은 ajp/1.3 프로토콜을 사용하여 httpd와 연결된다.
    tomcat 이중화를 위해 마지막 개방 포트를 다른 포트로 변경하여 또다른 Dockerfile을 준비한다.

    2 Docker-compose

    docker-compose를 사용하여 httpd, tomcat을 구동한다.

    • docker-compose-httpd.yml
    version: '3.7'
    
    services:
      httpd:
        container_name: httpd
        build: ../httpd/build
        volumes:
          - ../httpd/conf/:/etc/httpd/conf/
          - ../httpd/conf.d/:/etc/httpd/conf.d/
        ports:
          - "80:80"

    container의 이름을 httpd로 설정하고 위에서 만든 dockerfile을 사용하여 이미지를 생성한다.
    서버의 설정 정보를 담고 있는 conf 폴더를 외부에서 volume mapping하여 사용한다.

    • docker-compose-tomcat.yml
    version: '3.7'
    
    services:
      tomcat1:
        container_name: tomcat1
        build: ../tomcat/build1
        volumes:
          - ../target/ROOT.war:/usr/local/tomcat/webapps/ROOT.war
          - ../tomcat/conf1/:/usr/local/tomcat/conf/
        expose:
          - "8009"
        ports:
          - "8888:8080"
      tomcat2:
        container_name: tomcat2
        build: ../tomcat/build2
        volumes:
          - ../target/ROOT.war:/usr/local/tomcat/webapps/ROOT.war
          - ../tomcat/conf2/:/usr/local/tomcat/conf/
        expose:
          - "8019"
        ports:
          - "9999:8080"

    두 개의 tomcat container를 tomcat1, tomcat2 이름으로 구동한다. 각 tomcat의 설정 폴더를 외부에서 volume mapping 하여 사용하고 각 Dockerfile에서 개방한 포트와 일치하는 포트를 개방한다. tomcat에서 구동할 서비스는 target폴더 내의 ROOT.war 이름으로 준비한다.

    3 Configuration

    3.1 Httpd(Apache)

    • conf/httpd.conf
    ServerName httpd  # ----1
    Listen 80 # ----2
    LoadModule jk_module modules/mod_jk.so # ----3
    IncludeOptional conf.d/*.conf # ----4
    <VirtualHost *:80> 
      ServerName localhost
      JkMount /* loadbalancer # ----5
    
      <Directory "/message">
        Order Allow,Deny
        Allow from all
      </Directory>
    </VirtualHost>

    httpd.conf 파일의 일부를 위와 같이 수정/추가한다.

    1. ServerName은 httpd container 이름과 동일하게 설정하고
    2. 80포트로 들어온 요청을 listen한다.
    3. Dockerfile에서 설치한 mod_jk 모듈을 load한다.
    4. mod_jk와 관련된 설정파일은 conf.d 폴더에 있고 이 폴더를 include한다.
    5. 마지막으로 80 포트로 들어오는 모든 요청을 loadbalancer로 전달한다.
    • conf.d/mod_jk.conf
    # workers.properties location
    JkWorkersFile /etc/httpd/conf.d/workers.properties # ----1
    
    # url to worker mount
    JkMount /* loadbalancer # ----2
    
    # log settings
    JkLogFile /var/log/httpd/mod_jk.log # ----3
    JkLogLevel warn
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
    JkRequestLogFormat "%w %V %T"
    
    # JkOptions indicate to send SSL KEY SIZE,
    JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories

    conf.d/mod_jk.conf 파일을 위와 같이 생성한다.

    1. loadbalancer와 worker에 관한 설정 파일을 명시한다.
    2. 들어오는 모든 요청을 loadbalancer로 전달한다.
    3. mod_jk 모듈의 로그를 저장할 파일을 설정한다.
    • conf.d/workers.properties
    worker.list=loadbalancer # ----1
    
    worker.loadbalancer.type=lb # ----2
    worker.loadbalancer.balance_workers=worker1,worker2 # ----3
    worker.loadbalancer.sticky_session=true # ----4
    
    # server 1
    worker.worker1.type=ajp13 # ----5
    worker.worker1.host=tomcat1 # ----6
    worker.worker1.port=8009 # ----7
    worker.worker1.lbfactor=1
    worker.worker1.socket_keepalive=1
    
    # server 2 ----8
    worker.worker2.type=ajp13
    worker.worker2.host=tomcat2
    worker.worker2.port=8019
    worker.worker2.lbfactor=1
    worker.worker2.socket_keepalive=1

    conf.d/workers.properties 파일을 위와 같이 생성한다.

    1. worker.list에 loadbalancer를 추가하고
    2. loadbalancer의 type을 lb로 설정한다.
    3. loadbalancer 내의 workers 의 이름을 worker1, worker2로 설정하고
    4. 동일 접속일 경우 하나의 was에 지속적으로 연결되게 하기 위해 sticky_session을 true로 설정한다.
    5. worker1의 type을 ajp13으로 설정하고
    6. host를 container 이름인 tomcat1으로 설정하고
    7. worker1의 port를 container를 구동할때 개방한 port와 일치시킨다.
    8. worker2에 대해서도 같은 방법으로 작성한다.

    4 Network 구동

    스크립트 파일 network.sh를 사용하여 docker 네트워크를 구동한다.

    ./network.sh up

    httpd, tomcat 서버를 각각 재시작할때 다음 명령어를 입력한다.

    ./network.sh restartHttpd
    ./network.sh restartTomcat

    네트워크를 중지할 때 다음 명령어를 입력한다.

    ./network.sh down

    댓글

Designed by Tistory.