데몬이란
터미널과 분리되어 백그라운드에서 항상 실행되는 서비스 프로세스를 말한다.
예를 들어 sshd, nginx, mysqld, cron처럼.. 보통 이름 끝에 d가 붙는다.
터미널을 종료해도 죽지 않고, 로그인 사용자와 무관하다.
데몬은 대부분 부모 프로세스를 갖지 않는다. 따라서 PPID가 1이다.
데몬 생성 daemonization
전통적
- fork() -> 부모 프로세스는 종료되고 자식만 남는다.
- setsid() 호출 -> 새로운 세션을 생성하고 터미널 컨트롤을 차단한다.
- 한번 더 fork() -> 세션 리더 권한을 제거하고 터미널 재연결을 차단한다.
- standalone 방식 : 부팅 시부터 종료될 때까지 계속 실행된다. 웹서버, 디비, ssh처럼 빈번히 요청이 들어오고 속도가 중요할 때 사용한다. 프로세스가 항상 메모리에 상주하고 있기 때문에 사용하지 않아도 메모리를 계속 차지한다.
- inetd 방식 : 짐작되겠지만 필요할 때만 데몬을 생성하는 것이다. 클라이언트가 접속하면 그 순간에만 실행한다. 리소스 사용이 적고 관리가 쉽지만 요청이 들어올 때마다 프로세스를 생성하니 첫 응답이 느리고 대량 접속에는 취약하다.
systemd
지금은 inetd 대신 systemd socket activation 이 대체한다.
현대 리눅스는 대부분 systemd로 데몬을 관리한다.
systemctl start nginx 데몬 실행
systemctl stop nginx 데몬 중지
systemctl restart nginx 재시작
systemctl enable nginx 부팅 시 자동 실행
systemctl status nginx 상태 확인
예시로 nginx를 들어본 건데 예전부터 그냥 우분투로 서버관리 할 때 nginx 쓰면서 systemctl을 자연스럽게 썼었는데 이렇게 데몬 공부하면서 다시 보니까 새로운 느낌이다.
systemd 서비스 파일 구조
/etc/systemd/system/mydaemon.service
[Unit]
Description=My Custom Daemon
After=network.target
[Service]
ExecStart=/usr/local/bin/mydaemon
Restart=always
User=root
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable mydaemon
systemctl start mydaemon
이렇게 등록할 수 있다.
journalctl -u nginx : systemd 로그
journalctl -f -u nginx : 실시간
journalctl로 데몬 로그를 확인할 수 있다.
실습
간단하게 데몬 만들고 실행시켜보는 실습을 해보았다.
10초마다 /var/log/mydaemon.log 파일에 alive 로그를 찍는 데몬을 만들었다.
multipass로 우분투 서버를 하나 새로 파서 했다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
int main() {
pid_t pid;
pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0);
if (setsid() < 0) exit(1);
pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0);
umask(0);
chdir("/");
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
int fd = open("/var/log/mydaemon.log",
O_WRONLY | O_CREAT | O_APPEND,
0644);
if (fd < 0) exit(1);
while (1) {
time_t now = time(NULL);
char buf[128];
int len = snprintf(buf, sizeof(buf),
"%s daemon alive\n", ctime(&now));
write(fd, buf, len);
sleep(10);
}
}
mydaemon.c 파일이다. 첫번째 fork -> setsid -> 두 번째 fork로 전통적 데모나이제이션에 맞춰 작성했다.
umask는 파일 권한 제한 제거, chdir은 현재 디렉토리 점유 방지를 위해 넣었다.
close 부분은 터미널과의 모든 입출력을 차단한다.
int fd.. 여기는 로그 파일 열고, 없으면 생성, 이어서기록하라는 뜻이다.
while 문에서 10초마다 로그를 찍는 내용을 작성했다.

실행해본 결과이다.