[우분투] 서비스 자동 시작 및 종료 Develop Tip

예전 UNIX에서 System V 부터 그 계보가 이어져 온다고 볼 수 있는데,
우분투에도 RunLevel 이 존재합니다.

이것은 /etc/rc0.d .. /etc/rc6.d 과 /etc/rcS.d 가 존재하고 
그것이 러닝 레벨에 따라 필요한 스크립트가 실행된다는 것을 의미하는데요,

우선 0, 1, 6, S는 특별한 의미를 갖습니다.
0은 시스템이 종료될 때 호출되는 의미이고,
6은 reboot되는 상태에서 호출됩니다.
1은 single 모드로 진입할 때 불렸다가 후에 S로 된다고 합니다.

나머지 2,3,4,5 는 차이는 있지만 사용자 러닝 레벨로 볼 수 있습니다.

2 - Multiusermode : NFS를 사용하지 않는 텍스트 환경
3 - Full multiuser mode : 일반 텍스트 사용자 환경
4 - Unused : 사용되지 않지만 필요시 사용할 수 있다고 하네요
5 - X11 : GUI 환경으로 동작할 때

자... 이제 자신만의 새로운 mysvc 라는 서비스 데몬 프로그램이 있다고 가정합니다.

#include <stdio.h>
int main()
{
system("mkdir -p /var/run/mysvc");
int cnt = 0;
while(1) {
FILE * ofp = fopen("/var/run/mysvc/mysvc.log","a");
if (ofp == NULL) return 1;
fprintf(ofp,"[%08d]\n", ++cnt);
fclose(ofp);
sleep(1);
}
return 0;
}

간단한 C 로 만든 것이구요,
이것을 mysvc 라는 결과로 만들어
/uar/local/bin/mysvc 에 있다고 합니다.

그러면, /etc/init.d/mysvc
라는 파일에는 다음과 같은 내용을 넣습니다.

$ cat /etc/init.d/mysvc
#!/bin/sh -e
#
# start/stop mysvc daemons
#
### BEGIN INIT INFO
# Provides:  mysvc
# Required-Start: $network $remote_fs
# Required-Stop: $network $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop:  0 1 6
# Short-Description: My Service
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=mysvc
DAEMON=/usr/local/bin/mysvc
PIDDIR=/var/run/$NAME
DESC="Test My Service"
USERID=root

. /lib/lsb/init-functions

check_root()  {
if [ "$(id -u)" != "0" ]; then
log_failure_msg "You must be root to start, stop or restart $NAME."
exit 4
fi
}

###################################################################################################
case "$1" in
  start)
check_root
exitval=0
log_daemon_msg "Starting $DESC " 
if pidofproc -p $PIDDIR/$NAME.pid $DAEMON > /dev/null; then
log_progress_msg "$NAME apparently already running"
log_end_msg 0
exit 0
fi
start-stop-daemon --start --quiet --oknodo  --pidfile $PIDDIR/$NAME.pid \
--chuid $USERID:$USERID --exec $DAEMON --background --make-pidfile
log_progress_msg $NAME
# start my service
exitval=$?
log_end_msg $exitval
;;
  stop)
check_root
exitval=0
log_daemon_msg "Stopping $DESC " 
log_progress_msg $NAME
# stop my service
if pidofproc -p  $PIDDIR/$NAME.pid $DAEMON  > /dev/null; then
start-stop-daemon --stop --verbose --oknodo --pidfile $PIDDIR/$NAME.pid \
--exec $DAEMON
exitval=$?
else
log_progress_msg "apparently not running"
fi
exitval=$?
log_end_msg $exitval
;;
  restart|force-reload)
check_root
$0 stop
# Wait for things to settle down
sleep 1
$0 start
;;
  reload)
log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
log_warning_msg "cannot re-read the config file (use restart)."
;;
  status)
log_warning_msg "Status check $NAME daemon: not implemented, as the daemon"
;;
  *)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac

exit 0

몇가지 특별히 알아야 할 점은,

NAME에는 서비스 명을
DAEMON은 데몬으로 돌릴 프로그램 명을
PIDDIR은 pid가 위치할 곳
USERID는 실행될 데몬의 uid 를 지정합니다.

또한 /etc/init.d에 있는 각종 start-stop 서비스 스크립트 들은 로깅 등을 위해서
/lib/lsb/init-functions 를 디폴트로 이용한다고 보면 되네요.

check_root()는 root 계정 외에는 실행안되도록 하는 것이구요,

start, stop 을 채워 주면 됩니다.

실행하는 것은 

start-stop-daemon --start --quiet --oknodo  --pidfile $PIDDIR/$NAME.pid \
        --chuid $USERID:$USERID --exec $DAEMON --background --make-pidfile
라는 식으로 호출하는데
start-stop-daemon 을 힘을 빌어 실행합니다.
특별한 것은 /usr/local/bin/mysvc 라는 실행파일은 자체 데몬화 역활을 하지 않으므로
--background --make-pidfile 라는 옵션을 추가해 주었습니다. 자체 데몬화 기능을 제공하면
이 두 옵션을 빼면 됩니다.

종료도 유사하게
start-stop-daemon --stop --verbose --oknodo --pidfile $PIDDIR/$NAME.pid --exec $DAEMON
와 같이 start-stop-daemon을 이용하였습니다.

이렇게 /etc/init.d/mysvc 를 저장하고
sudo chown root:root /etc/init.d/mysvc
sudo chmod +x /etc/init.d/mysvc

를 준 다음,

$ sudo /etc/init.d/mysvc start
[sudo] password for future: 
 * Starting Test My Service                                                         [ OK ]

로 실행시켜보고
(tail -F /var/run/mysvc/mysvc.log 라고 명령을 내려 놓고 있으면,
[00000001]
[00000002]
[00000003]
[00000004]
...
라고 계속 나옵니다)

pid 는 /var/run/mysvc/mysvc.pid 에 저장되어 있습니다.

이제
$ sudo /etc/init.d/mysvc stop
 * Stopping Test My Service                                                                
 Stopped /usr/local/bin/mysvc (pid 32809).
                                                                                    [ OK ]

와 같이 서비스를 멈출 수 있습니다.

이제는 위와 같은 상황에서 실제 자동으로 시스템이 내려가거나 올라올 때 동작하도록 하려면,

update-rc.d 라는 명령을 이용합니다.

$ sudo update-rc.d mysvc defaults 99
 Adding system startup for /etc/init.d/mysvc ...
   /etc/rc0.d/K99mysvc -> ../init.d/mysvc
   /etc/rc1.d/K99mysvc -> ../init.d/mysvc
   /etc/rc6.d/K99mysvc -> ../init.d/mysvc
   /etc/rc2.d/S99mysvc -> ../init.d/mysvc
   /etc/rc3.d/S99mysvc -> ../init.d/mysvc
   /etc/rc4.d/S99mysvc -> ../init.d/mysvc
   /etc/rc5.d/S99mysvc -> ../init.d/mysvc

위의 명령은 시스템 종료 또는 single 모드의 경우에는
rc[016].d 안에 K99mysvc 가 /etc/init.d/mysvc 로 symbolic 링크가 걸려있고
해당 러닝 레벨로 진입할 때 해당 K99mysvc stop 으로 종료되는 것을 의미합니다.
K는 종료되는 것이고 99라는 번호는 rc.local 과 같이 사용자가 사용하는 마지막 
스크립트 순서를 의미합니다.

이제는 위와 같이 설정한 것을 빼려고 할 때 사용하는 방법입니다.

$ sudo update-rc.d -f mysvc remove
 Removing any system startup links for /etc/init.d/mysvc ...
   /etc/rc0.d/K90mysvc
   /etc/rc1.d/K90mysvc
   /etc/rc2.d/S90mysvc
   /etc/rc3.d/S90mysvc
   /etc/rc4.d/S90mysvc
   /etc/rc5.d/S90mysvc
   /etc/rc6.d/K90mysvc


어느분께는 도움이 되셨기를....


덧글

댓글 입력 영역

구글애드텍스트