last edit 2023.11.25

2015년, 많은 리눅스 배포판들은 init system(pid 1)을 init.d에서 systemd로 전환했다. service 명령 대신 systemctl 명령어를, syslog 대신 journalctl을 사용하는 등 많은 변화가 있었다. 하지만 데비안, RHEL등 보편적인 배포판이 systemd를 서비스 매니저로 채택하고 많은 시간이 흘렀지만, 아직도 많은 자료들은 init.d를 기준으로 설명한다.

그 중 대표적인 것이 스케쥴링 작업이다. 많은 사람들은 일정한 주기마다 실행되어야 하는 작업들을 cron 서비스를 이용해 스케쥴링한다. 매 시간 my-program이라는 프로세스를 실행해야 한다면, 대부분 다음과 같은 설정을 /etc/crontab 파일에 추가했을 것이다.

0 * * * * /usr/bin/my-program

이 작업을 systemd를 이용해 구현해보자. 그리고, systemd를 이용한 구현에 어떤 장점이 있는지 알아보자.

(주: mac os는 2010년 launchd로 전환했다. 클러스터 맥에서 ps -f 1을 실행해서 어떤 init프로세스가 사용되었는지 확인할 수 있다.)

service, daemon

init.dsystemd는 데몬을 관리하는 서비스 매니저이다. cron은 정해진 시간마다 작업을 수행하는 데몬이다.

리눅스 환경에서, 서비스와 데몬은 동치이다. 데몬은 터미널에서 분리되어서 백그라운드에서 작업하는 프로세스를 말한다. 데몬 프로세스는 표준입력과 표준출력을 이용해 사용자와 상호작용할 수 없고, 서비스 매니저의 하위 프로세스이다.

터미널에서 분리되어서라는 말에 주목하자. 데몬 프로세스는 소켓 또는 파일을 통해 다른 프로세스와 상호작용하고, 서비스 매니저가 보내는 시그널(SIGTERM)로 제어된다. 터미널에서 잘못된 시그널이 입력되어 데몬이 정지되는 것을 막기 위해 데몬 프로세스는 터미널(tty)에서 분리되어야 하는 것이다.

전통적인 init.d에 의해 시작되는 서비스를 SysV daemon이라고 한다.

주목할 점은 double fork 과정을 거쳐 데몬을 생성하는 것이다. 이는 Unix Network Programming에 나온 방법으로, setsid를 이용해 터미널에서 분리시키기 위한 기법이다. 유닉스의 프로세스는 sesion, process group 속성을 갖는다.

이때 session별로 제어 터미널을 가지므로, 데몬 프로세스가 새로운 세션에서 실행된다면 이 세션을 tty가 아닌 제어 터미널로 지정할 수 있다. 따라서 setsid를 사용하기 위해 double fork 과정을 거쳐 세션을 분리한다. 또한, (fork된) 자식 프로세스보다 부모 프로세스가 먼저 종료되면 PPID가 자동적으로 1(init.d)로 지정되어 init.d 서비스 매니저의 PGID에 속하게 되고, 서비스 매니저가 데몬에 시그널을 보내 제어할 수 있게 된다. (자세한 설명)

그런데 서비스 매니저인 init.d는 최초로 실행한 프로세스의 PID만 알 수 있을 뿐, 이렇게 두 번 fork해서 만들어진 데몬 프로세스의 PID는 알 수 없다. 따라서 init.d가 데몬 프로세스를 제어할 수 있도록 별도의 파일에 PID를 기록하는 과정이 필요하다.(주로 /run 밑에 저장)