풀스택 개발 들여다보기

[Docker] 웹 메일 서버 dockerizing

영바이트 2022. 4. 4. 19:43

이번 예는 웹 메일 서버를 도커로 만드는 과정을 살펴볼까 한다. 굳이 웹 메일 서버를 왜...? 라고 묻는다면 메일 서버를  다른 컴퓨팅 인스턴스로 이전할 일이 있었어서 그 계기로 메일 서버를 도커 이미지로 만들게 되었다.

 

도커 이미지로 만들려는 메일 서버의 구조를 살펴보면 아래와 같다.

<웹 메일 서버 도커 이미지화>

 

우선 메일 서버(Mail server-client docker container)는 아래 4가지 요소로 구성되어 있다.

 

- Postfix: SMTP를 이용해서 외부 메일 서버와 메일을 주고 받는 MTA(Mail Transfer Agent)다.

 

- Dovecot: Postfix는 메일을 저장하고 관리하는 기능이 잘 되어 있지 않다. 따라서 Postfix와 같은 MTA로 부터 메일 데이터를 받아서 체계적으로 관리하는 MDA(Mail Delivery Agent)를 함께 사용한다. 여기서는 MDA로 Dovecot을 사용하였다.

 

- RoundCube: HTTP(S) 연결을 통해 웹 브라우저에서 메일을 사용할 수 있도록 UI를 제공한다. RoundCube 대신 Outlook 등을 MDA와 직접 연결해서 사용해도 된다.

 

- NginX: 웹을 통해 RoundCube와 연결하기 위한 HTTP(S) 연결 요청을 처리하기 위해 필요한 웹 서버로 NginX를 사용하였다. NginX 서버가 접근해야 할 필요가 있는 파일들이 컨테이너 내부에 있기 때문에 NginX 서버의 기능을 두 부분으로 분리하여 컨테이너와 호스트에 각각 따로 NginX 서버를 두었다.

 

호스트Host에는 DB를 설치해서 MTA, MDA, 그리고 RoundCube가 필요로하는 데이터를 저장하고 관리할 수 있도록 하였다. 호스트에도 NginX 서버를 두어 외부에서 들어오는 HTTP(S) 요청을 컨테이너의 NginX로 전달하도록 하였다.

 


1. 베이스 이미지 준비

이미지를 생성(building)할 때 마다 매 번 설치할 필요가 없는 패키지나 프로그램들은 미리 설치하여 베이스 이미지로 만들어둔다. 예를 들면 postfix(MTA), dovecot(MDA), RoundCube 그리고 NginX 등을 미리 설치해둔다.

 

ubuntu:20.04 클린 이미지를 다운로드 하고(예, docker pull ubuntu:20.04) 인터랙티브 모드로 실행시킨다(docker run -it ubuntu:20.04 /bin/bash). 가장 먼저 apt 툴킷을 업데이트한다.

★여기 베이스 이미지 준비의 실행 명령은 모두 컨테이너의 쉘에서 실행시킨다.

$> apt-get update

 

postfix, dovecot, 그리고 rsyslog(시스템 logger)를 설치하자. rsyslog는 postfix, dovecot에서 발생한 로그를 var/log/mail.log에 기록하기 위해 필요하다.

$> apt-get install -y postfix postfix-mysql
$> apt-get install -y dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql
$> apt-get install -y rsyslog

 

http(s)를 이용해 메일을 이용할 수 있도록 웹 메일 서버로 roundcube mail(https://github.com/roundcube/roundcubemail/releases)을 사용할 것이다. Roundcube는 PHP를 사용하기 때문에 PHP 실행 환경을 필요로 한다. Roundcube를 설치하기 전에 PHP를 먼저 설치하자.

※ php 설치가 끝나면 php의 버전을 확인한 후(php --version) php 부수 패키지들을 버전에 맞게 설치한다.

$> apt-get install -y php php-mysql
$> (php --version)
$> apt-get install -y php7.4-fpm php7.4-mbstring
$> apt-get install -y php7.4-xml php7.4-gd php7.4-ldap php7.4-intl php7.4-imagick php7.4-zip

 

이제 웹 메일 서버를 설치한다. wget을 이용해서 파일을 받은 후 압축을 풀어준다. 필자는 /var/www/html 아래에 압축을 풀었다. Roundcube mail의 버전에 따라 다운로드 주소가 달라지기 때문에 다운로드 전에 roundcube 웹 페이지를 한 번 방문해 볼 것을 추천한다.

$> apt-get install -y wget
$> wget https://github.com/roundcube/roundcubemail/releases/download/1.4.13/roundcubemail-1.4.13-complete.tar.gz
$> tar xvzf roundcubemail-1.4.13-complete.tar.gz -C /var/www/html/

 

Roundcube mail 설치를 마치면 추가적으로 링크를 만들어 주고 디렉토리 및 파일의 소유 권한도 조정해 준다.

$> ln -s /var/www/html/roundcubemail-1.4.13 /var/www/html/roundcube
$> chown -R www-data:www-data /var/www/html/roundcube
$> chown -R www-data:www-data /var/www/html/roundcubemail-1.4.13

 

마지막으로 nginx를 설치해준다.

$> apt-get install -y nginx

 

이제 컨테이너에서 빠져 나온 후(예, $> exit) Postfix, Dovecot, Roundcube, 그리고 NginX를 설치했던 컨테이너를 이미지로 만든다.

★ 아래 docker 명령을 호스트host의 쉘에서 실행한다.

$> docker commit '컨테이너 ID' ubuntu_20.04:pfx-dvct-rc-nginx

 

2. Dockerfile

웹 메일 서버를 컨테이너로 만들기 위해 Dockerfile에서 수행하는 작업들을 순서대로 요약하면 다음과 같다.

① MTA(Postfix) 설정 파일들을 컨테이너 내부로 복사한다.

② MDA(Dovecot) 설정 파일들을 컨테이너 내부로 복사한다.

③ MDA가 메일 데이터를 저장하기 위해 특정 디렉토리를 이용할 수 있도록 그룹을 지정해준다.

④ NginX 설정 파일들을 컨테이너 내부로 복사한다.

⑤ Roundcube 설정 파일들을 컨테이너 내부로 복사한다.

⑥ 메일 서버 실행을 위한 쉘 스크립트 파일을 컨테이너 내부로 복사한다.

 

※ 이미지 생성 과정은 일괄처리(batch) 방식으로 스크립트 파일의 명령에 따라 순차적으로 진행되기 때문에 생성 과정에 사용자가 간섭할 수 없다. 따라서 설정 변경이 필요한 파일들은 미리 준비했다가 이미지 내부로 복사하는 방식으로 진행한다.

 

위 과정을 수행하는 Dockerfile의 전체 내용을 먼저 살펴보면 아래와 같다.

FROM ubuntu_20.04:pfx-dvct-rc-nginx
MAINTAINER sgkim08@gmail.com

WORKDIR /etc
COPY rsyslog/rsyslog.conf /etc/rsyslog.conf

WORKDIR /etc/postfix
RUN cp main.cf main.cf.bak
RUN cp master.cf master.cf.bak

COPY postfix/main.cf /etc/postfix/main.cf
COPY postfix/master.cf /etc/postfix/master.cf
COPY postfix/mysql-virtual-mailbox-domains.cf /etc/postfix/mysql-virtual-mailbox-domains.cf
COPY postfix/mysql-virtual-mailbox-maps.cf /etc/postfix/mysql-virtual-mailbox-maps.cf
COPY postfix/mysql-virtual-alias-maps.cf /etc/postfix/mysql-virtual-alias-maps.cf
COPY postfix/mysql-virtual-email2email.cf /etc/postfix/mysql-virtual-email2email.cf

WORKDIR /etc/dovecot
RUN cp dovecot.conf dovecot.conf.bak
RUN cp dovecot-sql.conf.ext dovecot-sql.conf.ext.bak

WORKDIR /etc/dovecot/conf.d
RUN cp 10-mail.conf 10-mail.conf.bak
RUN cp 10-auth.conf 10-auth.conf.bak
RUN cp auth-sql.conf.ext auth-sql.conf.ext.bak
RUN cp 10-master.conf 10-master.conf.bak
RUN cp 10-ssl.conf 10-ssl.conf.bak

COPY dovecot/dovecot.conf /etc/dovecot/dovecot.conf
COPY dovecot/10-mail.conf /etc/dovecot/conf.d/10-mail.conf
COPY dovecot/10-auth.conf /etc/dovecot/conf.d/10-auth.conf
COPY dovecot/auth-sql.conf.ext /etc/dovecot/conf.d/auth-sql.conf.ext
COPY dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext
COPY dovecot/10-master.conf /etc/dovecot/conf.d/10-master.conf
COPY dovecot/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf

RUN ["groupadd", "-g", "5000", "vmail"]
RUN ["useradd", "-g", "vmail", "-u", "5000", "-d", "/var/mail", "vmail"]

COPY nginx/roundcube /etc/nginx/sites-available/roundcube
WORKDIR /etc/nginx/sites-enabled
RUN ln -s /etc/nginx/sites-available/roundcube roundcube
RUN rm -f default

WORKDIR /etc/nginx
RUN mv nginx.conf nginx.conf.bak
COPY nginx/nginx.conf /etc/nginx/nginx.conf

WORKDIR /etc/php/7.4/fpm
RUN mv php.ini php.ini.bak
COPY roundcube/php.7p4.ini /etc/php/7.4/fpm/php.ini

COPY roundcube/config.inc.php /var/www/html/roundcube/config/config.inc.php
COPY roundcube/images /var/www/html/roundcube/images

WORKDIR /var/www/html/roundcube
RUN tar czf installer.tar.gz installer
RUN rm -f -R installer

WORKDIR /root
COPY run /root/run
ENV PATH /root:$PATH

ENTRYPOINT ["/bin/bash", "-c", "run"]

 

FROM ubuntu_20.04:pfx-dvct-rc-nginx

MAINTAINER sgkim08@gmail.com

가장 먼저 베이스이미지를 지정하고 관리자 정보를 설정하는 부분이다. 앞서 만들어 두었던 도커 이미지를 베이스이미지로 지정하였다.

 

WORKDIR /etc
COPY rsyslog/rsyslog.conf /etc/rsyslog.conf

이미지 빌딩 과정은 배치batch(일괄처리) 방식이기 때문에 사용자가 간섭할 수 없다. 따라서 설정을 변경해야 하는 경우 미지 준비해 둔 설정 파일을 호스트host에서 도커 이미지로 가져오는 방법을 사용해야 한다. 여기서는 rsyslog 설정 파일을 이미지로 복사한다.

WORKDIR /etc/postfix
RUN cp main.cf main.cf.bak
RUN cp master.cf master.cf.bak

MTA인 Postfix의 설정 파일을 호스트에서 이미지로 복사하기 전에 기존 파일들의 복사본을 생성하였다. 기존 파일들이 필요 없다면 RUN 명령어 부분은 굳이 없어도 된다.

COPY postfix/main.cf /etc/postfix/main.cf
COPY postfix/master.cf /etc/postfix/master.cf
COPY postfix/mysql-virtual-mailbox-domains.cf /etc/postfix/mysql-virtual-mailbox-domains.cf
COPY postfix/mysql-virtual-mailbox-maps.cf /etc/postfix/mysql-virtual-mailbox-maps.cf
COPY postfix/mysql-virtual-alias-maps.cf /etc/postfix/mysql-virtual-alias-maps.cf
COPY postfix/mysql-virtual-email2email.cf /etc/postfix/mysql-virtual-email2email.cf

MTA인 Postfix의 설정 파일을 호스트에서 도커 이미지 내부로 복사하는 부분이다.


WORKDIR /etc/dovecot
RUN cp dovecot.conf dovecot.conf.bak

RUN cp dovecot-sql.conf.ext dovecot-sql.conf.ext.bak

MDA인 Dovecot의 설정 파일들을 이미지로 복사하기 전에 기존 파일들의 복사본을 생성하였다. 기존 파일들이 필요없다면 필요 없는 부분이다.


WORKDIR /etc/dovecot/conf.d
RUN cp 10-mail.conf 10-mail.conf.bak
RUN cp 10-auth.conf 10-auth.conf.bak
RUN cp auth-sql.conf.ext auth-sql.conf.ext.bak
RUN cp 10-master.conf 10-master.conf.bak
RUN cp 10-ssl.conf 10-ssl.conf.bak

역시 MDA인 Dovecot의 설정 파일들을 이미지로 복사하기 전에 기존 파일들의 복사본을 생성하였다. 기존 파일들이 필요 없다면 RUN 명령 라인들은 필요 없는 부분이다.

COPY dovecot/dovecot.conf /etc/dovecot/dovecot.conf
COPY dovecot/10-mail.conf /etc/dovecot/conf.d/10-mail.conf
COPY dovecot/10-auth.conf /etc/dovecot/conf.d/10-auth.conf
COPY dovecot/auth-sql.conf.ext /etc/dovecot/conf.d/auth-sql.conf.ext
COPY dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext
COPY dovecot/10-master.conf /etc/dovecot/conf.d/10-master.conf
COPY dovecot/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf

MDA인 Dovecot의 설정 파일들을 도터 이미지로 내부로 복사하는 부분이다.


RUN ["groupadd", "-g", "5000", "vmail"]
RUN ["useradd", "-g", "vmail", "-u", "5000", "-d", "/var/mail", "vmail"]

vmail이라는 계정과 그룹으로 메일 데이터들을 저장하도록 Dovecot을 설정하였다(10-master.conf). 따라서 vmail 유저 그룹과 vmail 계정을 생성하고 home 디렉토리로 /var/mail을 지정하였다.


COPY nginx/roundcube /etc/nginx/sites-available/roundcube
WORKDIR /etc/nginx/sites-enabled
RUN ln -s /etc/nginx/sites-available/roundcube roundcube
RUN rm -f default

NginX의 서버 설정 파일을 호스트로부터 가져오는 단계를 기술하였다. 웹 메일 서버인 RoundCube의 구동을 위해 NginX가 컨테이너 내부의 파일을 직접 읽고 쓸 수 있어야 하기 때문에 NginX를 컨테이너 부분과 호스트 부분 둘로 나누었다. 이 부분은 이어지는 포스팅에서 내용을 살펴보도록 하겠다.


WORKDIR /etc/nginx
RUN mv nginx.conf nginx.conf.bak
COPY nginx/nginx.conf /etc/nginx/nginx.conf

NginX의 기존 설정 파일(nginx.conf)의 복사본을 생성하고 준비했던 설정 파일을 호스트에서 도커 이미지로 복사해서 가져온다.

WORKDIR /etc/php/7.4/fpm
RUN mv php.ini php.ini.bak
COPY roundcube/php.7p4.ini /etc/php/7.4/fpm/php.ini

RoundCube는 PHP 언어로 만들어져 있기 때문에 PHP 해석기(interpreter)가 필요하다. PHP 설정 파일을 호스트로부터 가져오도록 하였다.

COPY roundcube/config.inc.php /var/www/html/roundcube/config/config.inc.php
COPY roundcube/images /var/www/html/roundcube/images

RoundCube 설정 파일을 호스트에서 이미지로 복사한다. images의 경우 RoundCube의 기본 이미지를 대체하려 한다면 필요한 이미지를 복사한다.


WORKDIR /var/www/html/roundcube
RUN tar czf installer.tar.gz installer
RUN rm -f -R installer

RoundCube를 설치하면 install 디렉토리가 들어있다. 이 install 디렉토리를 이용해 웹 브라우저로 설정을 할 수 있게끔 되어 있는데 보안 측면에서 안전하지 않을 수 있기 때문에 압축하여 복사본을 남겨놓고 디렉토리 자체는 삭제하였다.


WORKDIR /root
COPY run /root/run
ENV PATH /root:$PATH

호스트에 준비되어 있는 웹 메일 실행 스크립트 run을 이미지로 복사한다. 필자가 사용한 run 스크립트의 내용은 아래와 같다. run 스크립트의 내용은 각자 원하는 메일 서버의 기능이나 구동 환경에 따라 다를 것이다.

run
#!/bin/bash
service rsyslog start
service postfix start
service dovecot start
service php7.4-fpm start
nginx
tail -f /var/log/mail.log


ENTRYPOINT ["/bin/bash", "-c", "run"]

이미지가 컨테이너로 활성화될 때 run 스크립트를 실행하도록 설정한다.

 


 

Dockerfile이 준비되면 docker build 명령을 이용해서 이미지를 생성하면 된다(아래 예 참고). 한 가지 주의할 점은 이미지로 복사할 설정 파일들을 Dockerfile이 위치한 디렉토리에 미리 준비해두어야 한다는 점이다.

$> docker build -t ubuntu_20.04:webmailserver .

 

필자도 TLDR(Too Long Don't Read)인 게으른 사람임에 어쩔 수 없다. 글이 길어질 것 같아 docker-compose 스크립트 그리고 도커 이미지와 호스트로 나뉘어진 NginX의 설정 예는 이어지는 포스팅에서 살펴보는 것이 좋을 것 같다.