IT/기초 지식

[Docker] Supervisor을 Docker에서 사용하기

개발자 두더지 2021. 10. 14. 00:44
728x90

Supervisor이란?


 전통적(?)으로 Docker 컨테이너는 실행시에 1개의 프로세스를 실행한다. 예를 들어, Apache 데몬이나 SSH 서버의 데몬과 같은 것이 있다. 그러나 컨테이너 내에서 여러 개의 프로세스를 실행하고 싶을 경우가 있을 것이다. 이러한 소망을 실현시킬 수 있는 몇 가지 방법이 있다. 

 프로세스 관리 툴을 설치해 컨테이너의 CMD 명령으로 단순히 Bash 스크립트를 사용할 수 있도록 하면되는데, 이 때의 프로세스 관리 툴 중 하나가 Supervisor이다. Supervisor을 사용해, 컨테이너 내의 여러 개의 프로세스를 관리할 수 있다. 프로세스의 재실행도 가능하다. 

 즉 Docker시점에서 본다면, "Docker Container상에서는 Process가 Foreground로 실행되지 않으면 Container는 종료한다"는 Container의 제약이 있는데, 1개의 Container상에서 여러 개의 프로세스(예를 들어 Node+Mongo나 Fluentd+Elasticsearch등)을 작동시키고 싶다, 지속화하고 싶을 때 Supervisor이라는 Tool을 사용한다는 것이다. 

 참고로 Supervisor의 공식 사이트는 여기이다.

 Supervisor은 가동시키고 싶은 서비스를 "/ect/supervisord.conf" 파일에 기재한다. 아래서는 httpd데몬과 vsfpd데몬을 동시에 가동싶은 경우의 파일 예이다.  

# cat supervisord.conf
[supervisord]
nodaemon=true
 
[program:httpd]
command=/usr/sbin/httpd -k start
 
[program:vsftpd]
command=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

 위의 설정 예에서 httpd와 vsfpd의 실행시에 관련된 처리를 1개의 supervisord.conf 파일에 기재하고 있으나, 서비스마다 설정 파일을 나눠서 작성해, /ect/supservisord.conf 파일을 통해 서비스마다의 설정 파일을 로드하는 방법도 존재한다.

 이번 포스팅에서는 supervisor의 설치와 실행에 대해 알아본 후, Docker에 어떻게 적용하는지에 대해 알아 볼 생각이다.

 

 

Supervisor의 설치


 설치 부분과 관련해서 참고한 포스팅의 환경이 CentOS6.4였으므로, 운영체제에 따라 차이가 있을 것으로 예상됩니다.

설치~실행 확인 부분에 관련해 참고한 포스팅에서는 GrowthForecastHRForcasf를 사용하기 위한 흐름을 설명하고 있으니, 적절히 다른 프로그램으로 바꿔서 설정해주세요.

설치

설치 방법은 크게 두 가지가 있다.

1) EPEL 리포지토리를 이용해 설치

2) python패키지 매니저(pip/easy_install)의 사용해 설치

 1번의 방법으로는 이전 버전을 받을 가능성이 있기 때문에, 따라서 최신 버전을 바로 사용하고 싶다면 2번을 방법을 사용한다. 

1) EPEL 리포지토리를 이용해 설치

supervisord 자체 및 supervisord 관리 스크립트는 /etc/init.d에 들어가, service 커맨드로 관리할 수 있다.

yum install supervisor

 참고로 CentOS의 경우 EPEL 리포지토리가 기본적으로 유효화되지 않으므로 등록되어 있지 않은 경우 설치 전에 아래의 커맨드를 실행하다.

rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
rpm -ivh http://apt.sw.be/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm

2) python패키지 매니저(pip/easy_install)의 사용해 설치

sudo easy_install supervisor

# 혹은

sudo pip install supervisor

 

기본 conf파일 생성

 EPEL 리포지터리로 설치한 경우 자동으로 /etc/supervisord.conf가 생기지만, 수동으로 생성하고자하면 아래의 커맨드를 사용한다.

sudo echo_supervisord_conf > /etc/supervisord.conf

 

include 컨피그 파일용 디렉토리 생성

EPEL 리포지터리로 설치한 경우 자동으로/etc/supervisord.d가 생성되어 있으므로, 아래의 커맨드를 사용하자.

sudo mkdir /etc/supervisord.d

 

supervisord 로그 파일

supervisord 자체가 뱉어내는 로그 파일의 조정을 해야한다. 디폴트의 컨피그 파일에는 로그 파일 위치가 /tmp/supervisord.log인데 원하는 경우 /etc/supervisord.conf를 수정하면 된다.

[supervisord]
# 로그 디렉토리
;logfile=/tmp/supervisord.log
logfile=/var/log/supervisor/supervisord.log

 로그 출력처의 디렉토리를 생성하고, 내친 김에 log rotation의 설정도 해두자.

sudo mkdir /etc/supervisord.d
sudo sh -c "echo '/var/log/supervisor/*.log {
       missingok
       weekly
       notifempty
       nocompress
}' > /etc/logrotate.d/supervisor"

 

pid, include의 설정

이와 관련된 설정도 /etc/supervisord.conf에서 할 수 있다.

pid 파일은 /var/run 아래에 생성되게 하고, /etc/supervisord.d/ 아래의 설정 파일을 include할 수 있게 했다.

[supervisord]
# ...중략
# pid파일
;pidfile=/tmp/supervisord.pid
pidfile=/var/run/supervisord.pid

# ...중략

# include섹션이 주석처리되어 있으므로, 주석 처리르 지우고 아래와 같이 수정했다.
[include]
files = supervisord.d/*.ini

 

supervisord 자체의 시스템 서비스 등록(CentOS6버전)

init 스크립트는 작성해두신 분이 있어 그 내용을 참고했다. 

https://github.com/Supervisor/initscripts

 

GitHub - Supervisor/initscripts: User-contributed OS init scripts for Supervisor

User-contributed OS init scripts for Supervisor. Contribute to Supervisor/initscripts development by creating an account on GitHub.

github.com

sudo curl -o /etc/rc.d/init.d/supervisord https://raw.githubusercontent.com/Supervisor/initscripts/master/redhat-init-equeffelec
sudo chmod 755 /etc/rc.d/init.d/supervisord
sudo chkconfig --add supervisord

 

 

supervisord의 컨피그 파일


/ect/supervisord.conf를 아래와 같이 편집했다.

[inet_http_server]
port=127.0.0.1:9001

[supervisorctl]
serverurl=unix:///var/tmp/supervisor.sock
serverurl=http://127.0.0.1:9001

 web 관리 컨솔을 개방하여, 동시에 root이외의 유저로 부터 클라이언트 커맨드를 사용할 수 있도록 허가했다.

 

 

프로세스 관리 등록


당시 설치한 supervisor는 version3으로 2버전에서는 컨피그 파일이 특히 로그 출력 부분이 약간 다를 수 있다.

아래에서는 Job의 표준 출력 로그 저장 디렉토리를 /var/log/supervisor/jobs로 하였다. 또한 로테이션 설정도 아래와 같이 해두는 것이 적당하다.

GrowthForecast 등록의 예

[program:GrowthForecast]
command=/usr/local/bin/growthforecast.pl --enable-float-number --data-dir /data/gf    ; 실행 커맨드
user=monadmin  ; 실행 유저
autorestart=true  ; 프로세스 다운시에 자동 재실행
stdout_logfile=/var/log/supervisor/jobs/GrowthForecast-supervisord.log ; 표준 출력 로그
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=5
stdout_capture_maxbytes=1MB
redirect_stderr=true  ; 에러 출력을 표준 출력으로 리다이렉트

이것을 /ect/supervisord.d/GrowthForecast.ini에도 작성해뒀다.

HRForecast 등록의 예

/opt/HRForecast 디렉토리에 설치하고 있다.

[program:HRForecast]
command=perl hrforecast.pl --config config.pl  ; direcotry로 부터의 상대경로로 OK。
user=monadmin
directory=/opt/HRForecast  ; 설치 디렉토리가 있는 경우 여기에
autorestart=true
stdout_logfile=/var/log/supervisor/jobs/HRForecast-supervisord.log
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=5
stdout_capture_maxbytes=1MB
redirect_stderr=true

 이 내용도 동일하게 /etc/supervisord.d/HRForecast.ini에도 작성해뒀다.

 

실행 확인


sudo service supervisor start

/var/log/supervisor아래의 로그를 체크해두는 것이 좋을 것이다. 이번에 했던 설정의 경우, 설정한 프로세스(GrowthForecast나 HRForecast)의 stdout/err도 출력된다.

 실행 후에는 root이외로부터 클라이언트 커맨드의 supervisorctl를 파악해보고자한다. 커맨드 라인의 관리 인터페이스에들어가면, 커맨드를 입력하면 문제 없다는 가정하에 아래와 같은 내용이 출력된다.

[monadmin@myhost]% supervisorctl
GrowthForecast                   RUNNING    pid 24955, uptime 0:12:00
HRForecast                       RUNNING    pid 24956, uptime 0:12:00
supervisor>

CLI콘솔 상에서는 start|stop|restart [프로세스명], status으로 관리 프로세스의 목록을 확인할 수 있다. CLI콘솔에 들어가지 않아도 supervisorctl {start|stop|restart|status} [프로세스 명] 등으로도 확인할 수 있다.

root가 아니어도 되므로, 유저 레벨로 관리할 수 있는 데몬이 됐다.

 

 

Supervisor를 Docker에 적용하기


여기서부터는 nginx를 supervisor상에서 움직여보고 싶은 경우를 상정해, Docker에 적용한 내용에 대한 포스팅을 참고한 것 입니다. 

기본적인 사용법

 nginx를 supervisor상에서 움직여보고 싶은 경우, Dockerfile을 작성하면 다음과 같다.

FROM ubuntu:14.04

#Install nginx
RUN apt-get update && apt-get -y install nginx curl
RUN echo "daemon off;" >> /etc/nginx/nginx.conf

#Install Supervisor and config
RUN apt-get install -y supervisor
RUN touch /etc/supervisord.conf
RUN echo '[supervisord]'  >> /etc/supervisord.conf
RUN echo 'nodaemon=true'  >> /etc/supervisord.conf
RUN echo '[program:nginx]' >> /etc/supervisord.conf
RUN echo 'command=nginx'   >> /etc/supervisord.conf

EXPOSE 80
CMD /usr/bin/supervisord -c /etc/supervisord.conf

 [supervisord]와 nodaemon=true는 필수 항목으로, nodaemon =True로 supervisor 자체가 foreground 프로세스로써 다뤄져 Docker container의 종료를 예방하는 역할을 한다. command=에서는 Container상에서 nginx가 단체로 계속해서 움직일 경우에 작성해야만 하는 command를 작성한다.

 Dockerfile은 간결하게 작성해 컨피그 파일과 구분하는 것이 좋다. supervisord.conf파일에는 아래의 내용을 작성해, /etc/ 이하에 배치하도록 Dockerfile쪽에 작성하면 OK이다.

[supervisord]
nodaemon=true

[program:nginx]
command=nginx

 

여러 개의 프로세스를 움직일 경우의 사용법

Elasticsearch + Fluentd와 supervisor상에 움직이고 싶은 경우는 다음과 같이 Dockerfile을 작성하면 될 것이다.

FROM ubuntu:14.04
RUN apt-get update -y

#Install Elasticsearch
ENV ELASTICSEARCH_VERSION elasticsearch-1.4.4
RUN apt-get install -y curl openjdk-7-jdk
RUN mkdir /opt/elasticsearch
RUN curl -sL "https://download.elasticsearch.org/elasticsearch/elasticsearch/${ELASTICSEARCH_VERSION}.tar.gz" | tar xz -C /opt/elasticsearch --strip=1

#Install Fluentd and plugins
RUN apt-get install -y libcurl4-openssl-dev git-core build-essential ruby-dev
RUN curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh
COPY td-agent.conf /etc/td-agent/td-agent.conf
RUN ulimit -n 65536

#Install Supervisor and config
RUN apt-get install -y supervisor
RUN touch /etc/supervisord.conf
RUN echo '[supervisord]'  >> /etc/supervisord.conf
RUN echo 'nodaemon=true'  >> /etc/supervisord.conf
RUN echo '[program:elasticsearch]'             >> /etc/supervisord.conf
RUN echo 'command=/opt/elasticsearch/bin/elasticsearch' >> /etc/supervisord.conf
RUN echo '[program:td-agent]'             >> /etc/supervisord.conf
RUN echo 'command=/usr/sbin/td-agent' >> /etc/supervisord.conf

# expose port for elasticsearch
EXPOSE 9200

# expose port for fluentd
EXPOSE 24224

CMD /usr/bin/supervisord -c /etc/supervisord.conf

 

Docker에서 Supervisor사용시에 주의해야할 설정

각 프로세스의 표준 출력

 Supervisor은 기본적으로 각 프로세스로 부터의 표준 출력을 받아내어 file로 작성한다. 따라서 Supervisor을 경유하여 각 프로세스를 움직이는 경우에 각 프로세스의 표준 출력 내용을 확인할 수 없다.

 file이 아닌 표준출력을 작성해내고 싶다면, stdout_logfile를 /dev/fd/1에 설정하면 된다. 예를 들어, 아래와 같이 설정하면, td-agent의 프로세스로부터 출력된 표준 출력은 (Supervisor를 경유하여) 시스템 전체의 표준 출력에 Route된다.

[supervisord]
nodaemon=true

[program:elasticsearch]
command=/opt/elasticsearch/bin/elasticsearch

[program:td-agent]
command=/usr/sbin/td-agent
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0

참고자료

https://qiita.com/taka4sato/items/1f59371ead748d88635a

https://qiita.com/yushin/items/15f4f90c5663710dbd56

https://techracho.bpsinc.jp/morimorihoge/2017_06_05/40936

https://www.itmedia.co.jp/enterprise/articles/1602/17/news004_2.html

https://docs.docker.jp/engine/admin/using_supervisord.html

728x90