본문 바로가기
Programming/Docker

Docker 활용기(2) - tomcat 서버 구성해보기

by ★용호★ 2017. 1. 16.

웹서버를 구동시킬 톰캣 서버의 경우 jenkins를 통해 배포를 해야하기 때문에 ssh 접근이 필요했다. 기본적으로 docker container는 root 계정을 사용하고 있기 때문에 새로운 계정을 생성하여 tomcat 디렉토리에 권한을 부여하는 방식으로 사용했다. 이 때 발생한 문제는 최초 구동 시 tomcat을 시작시키는 계정이 root이기 때문에 log파일이 root 권한으로 생성이 되기 때문에 새로 만든 계정으로 톰캣을 재시작 하는 경우 문제가 발생했다. 그래서 아래와 같이 설정을 마친 뒤 새로 만든 계정으로 전환한 후 CMD 명령을 수행하도록 하였다.

FROM tomcat:8.0
MAINTAINER Server Team <yongho1037@vinusent.com>

RUN apt-get update -y && apt-get install -y openssh-server vim

# SSH 관련 설정
RUN adduser --disabled-password --gecos "" new_user  \
    && echo 'new_user:1234' | chpasswd \
    && mkdir /var/run/sshd

RUN chown -R new_user /usr/local/tomcat

EXPOSE 22

USER new_user

CMD ["catalina.sh", "run"]

이렇게 설정을 한 경우 docker exec -it <CONTAINER_ID> bash 명령으로 컨테이너에 접속하는 경우 root가 아닌 new_user 계정으로 접속하게 된다. root 권한이 필요한 경우 docker exec -it -u root <CONTAINER_ID> bash 명령으로 접속 계정을 명시하는 방법을 사용하면 된다.

이 때도 발생했던 한가지 문제는 catalina.sh stop을 수행했을 때 도커 컨테이너도 함께 stop 된다는 것이었다. docker container가 만들어진 후 해당 컨테이너에서 ps 명령을 통해 PID를 확인해보면 CMD를 통해 실행 된 프로세스의 PID가 init 프로세스를 의미하는 1번인 것을 볼 수 있다. 그래서 이 프로세스가 종료되면 컨테이너까지 종료되는 것이다. 이 때문에 jenkins를 통해 배포를 하고나면 tomcat을 재시작하지 못하는 문제가 발생했다. docker container가 아닌 호스트로 접근하여 docker 컨테이너 안으로 war 파일을 복사하고 재시작을 수행하면 되긴 하지만 절차가 복잡해져서 제외시켰다. 

이 후 아래와 같이 도커 컨테이너가 시작될 때 catalina.sh start를 수행하지 않고 sshd를 수행하도록 해서 tomcat이 종료되도 sshd가 종료되지 않는 이상 컨테이너가 종료되지 않도록 하였다. 이렇게 하면 물론 수동으로 tomcat 서버를 시작시켜줘야 하지만 이 과정은 모두 jenkins 를 통해 자동화 할 것이기 때문에 문제가 되지 않을 거라고 판단했다.

FROM tomcat:8.0
MAINTAINER Server Team <yongho1037@vinusent.com>

RUN apt-get update -y && apt-get install -y openssh-server vim

# SSH 관련 설정
RUN adduser --disabled-password --gecos "" new_user  \
    && echo 'new_user:1234' | chpasswd \
    && mkdir /var/run/sshd

RUN chown -R new_user /usr/local/tomcat

EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]

그리고 이제 CMD 명령으로 톰캣을 실행시키지 않고 jenkins를 통해서만 톰캣이 구동되므로 USER 명령을 통해 사용자를 변경시킬 필요가 없어졌다. 그래서 USER 변경 구문은 제거했다.


openjdk:8-jre 사용 시 오류

7이나 9에서는 문제가 발생하지 않는데, jre 8을 사용하는 경우에 apt-get update를 수행하면 아래와 같은 오류가 발생한다.

W: Failed to fetch http://deb.debian.org/debian/dists/jessie-backports/main/binary-amd64/Packages  Hash Sum mismatch

E: Some index files failed to download. They have been ignored, or old ones used instead.

문제가 되는 위의 URL을 curl 명령으로 request를 날려보니 주소가 이전되었다는 메시지가 출력되었다.

$ curl http://deb.debian.org/debian/dists/jessie-backports/main/binary-amd64/Packages
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="http://cdn-fastly.deb.debian.org/debian/dists/jessie-backports/main/binary-amd64/Packages">here</a>.</p>
<hr>
<address>Apache Server at deb.debian.org Port 80</address>
</body></html>

정상 동작하는 다른 버전과 Dockerfile을 비교해보니 8-jre에는 아래의 구문이 추가된 것을 찾을 수 있었다.

RUN echo 'deb http://deb.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list

그래서 /etc/apt/sources.list.d/jessie-backports.list 에 명시된 경로를 아래와 같이 수정한 후 apt-get update를 수행했더니 정상동작했다.

$ echo 'deb http://http.debian.net/debian jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list
$ rm -rf /var/lib/apt/lists/*
$ apt-get clean
$ apt-get update


docker container로 ssh 접근 시도 시 LANG 값이 변경되는 이슈

  • ssh 접근을 시도하는 host의 LANG과 동일한 LANG으로 변경됨.
  • ssh 접근 시 -v 옵션을 사용하여 debug 메시지를 확인해보니 환경 변수를 보내는 메세지가 출력된다.
debug1: Authentication succeeded (password).
Authenticated to 192.168.0.201 ([192.168.0.201]:9122).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: pledge: network
debug1: Sending environment.
debug1: Sending env LANG = ko_KR.UTF-8
  • 여기서는 env LANG을 보내고 있는데 이 정보는 /etc/ssh/ssh_config를 확인해보면 보낼 환경 변수에 대한 정보가 있다. 기본적으로 LC_*을 보내게끔 되어 있는데 이조차 보내지 않으려면 주석처리 한다.
SendEnv LANG LC_*
  • 위의 환경 변수를 ssh로 접속할 서버에 적용하려면 이를 허용하도록 해당 서버의 sshd_config 파일에 명시되어야 한다. 기본적으로 LANG LC_*을 허용하도록 되어 있다.
AcceptEnv LANG LC_*
  • 작업 중 문제가 되었던 부분은 다른 ssh 통신에 있어서는 LANG 값이 덮어써지는 경우가 없었는데 docker를 사용한 경우에만 문제가 발생했다.
  • ssh 접속 시 보내지는 LC_*는 /etc/default/locale 파일이 존재하지 않는 경우에만 적용된다.
    • docker container에는 /etc/default/locale 파일이 존재하지 않았기 때문에 host의 LANG 값이 적용됨.
    • 해당 파일 생성 후 기본 locale 값 설정을 해주면 host의 LANG을 따라가지 않고 설정된 locale로 사용된다.
    • /etc/default/locale 파일 작성
    LANG="ko_KR.UTF-8"
    
    • locale 적용
    update-locale
    
  • 이슈를 확인하기 위해서는 ssh 접속에 대한 로그가 필요했는데 기본적으로 docker container에서 syslog를 제공하지 않고 있었다.
  • 이를 위해서 rsyslog를 설치 후 /var/log/auth.log를 확인하여 이슈를 해결하였다.
$ apt-get install rsyslog
$ rsyslogd
$ tail -f /var/log/auth.log


언어 설정

debian:jessie 기반의 환경에서는 기본적으로 C.UTF-8 로 LANG이 설정되어 있기 때문에 한글이 깨져서 출력된다. 한글을 사용하기 위해 아래 명령을 수행한다.

sed -i -e 's/# ko_KR.UTF-8 UTF-8/ko_KR.UTF-8 UTF-8/' /etc/locale.gen && \
echo 'LANG="ko_KR.UTF-8 UTF-8"'>/etc/default/locale && \
dpkg-reconfigure --frontend=noninteractive locales && \
echo 'export LANG=ko_KR.utf-8' >> /etc/bash.bashrc && \
source /etc/bash.bashrc
  • sed 명령은 파일 내 문자열을 편집할 수 있도록 해주는 명령어 인데 vi에서 문자열 치환하는 방식과 동일하게 사용할 수 있다. 위의 명령은 # ko_KR.UTF-8 UTF-8 문자열을 찾아서 ko_KR.UTF-8 UTF-8으로 치환하는 명령인데 결국 주석을 풀어주는 역할을 수행한다.
  • 다음으로 ko_KR.UTF-8 UTF-8을 기본 locale로 설정하도록 /etc/default/locale 파일을 생성한다.
  • dpkg-reconfigure 명령으로 locales 셋팅을 하는데 docker에서는 대화형으로 진행하면 안되므로 noninteractive 옵션을 주었다.
  • 언어 설정이 bash가 실행될 때 기본적으로 적용되도록 하기 위해 /etc/bash.bashrc에 export 명령을 추가했다.

ssh로 접속하는 환경과 상관없이 tomcat 구동 시에 file의 encoding을 utf-8로 설정하려면 setenv.sh 파일을 $CATALINA_HOME/bin에 추가한다.

echo '#!/bin/bash' > $CATALINA_HOME/bin/setenv.sh && \
echo 'JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=\"utf-8\""' >> $CATALINA_HOME/bin/setenv.sh


docker exec 명령으로 컨테이너 접속시 스크립트 실행

ssh 접속 시에는 bashrc와 profile이 모두 실행 되지만 docker exec로 접속하는 경우 bashrc만 실행된다. 그러므로 shell 접속 시 반영해야 하는 사항에 대해서는 bashrc 파일에 기록해야한다.

댓글