computer program that runs as a background process
드디어 돌아온 Daily CS, 올해의 첫 주제는 Daemon이다. 데이먼... 다이먼... 다들 다양하게 읽지만, 어떻게 또 다들 알아듣는 마법의 단어... 오늘은 이 친구에 대해서 알아보자.
Daemon은 일반적으로 운영체제에서 백그라운드에서 실행되는 프로그램을 의미한다. 이들은 사용자와 직접 상호작용하지 않고, 시스템의 특정 작업을 지속적으로 처리하거나 서비스를 제공하는 데 초점을 맞춘다.
cron
Daemon은 사용자 정의 일정에 따라 작업을 수행한다.udevd
는 플러그앤플레이 장치의 연결 상태를 관리한다.Daemon이라는 용어는 그리스 신화의 '다이몬(Daemon)' 에서 유래했다. 이는 인간을 돕는 영적 존재로, 특정 작업을 수행하며 뒤에서 보이지 않게 작동한다는 의미에서 사용되었다.
inetd
)나 스케줄링 작업(cron
)을 담당했다.Daemon은 백그라운드 프로세스의 한 유형으로 볼 수 있지만, 특정한 차별화된 특성을 지닌다.
특징 | Daemon | 백그라운드 프로세스 |
---|---|---|
실행 방식 | 시스템에 의해 자동으로 시작되고 종료됨 | 사용자 또는 프로그램에 의해 수동으로 실행 |
독립성 | 부모 프로세스로부터 완전히 독립적 | 부모 프로세스에 종속적 |
주요 목적 | 시스템 서비스 제공 및 유지 관리 | 특정 사용자 작업 수행 |
종료 시점 | 시스템 종료 시 종료 | 작업 완료 또는 명시적 종료 |
예시 | cron , httpd , sshd | CLI 명령어(cp , find )로 실행된 백그라운드 작업 |
fork()
시스템 호출을 사용하여 부모 프로세스와의 연결을 끊고, 독립적인 프로세스로 전환한다.Daemon 프로세스는 일반적인 백그라운드 프로세스와 구별되는 몇 가지 중요한 특성을 가진다.
fork()
시스템 호출을 사용해 부모와 자식을 분리한다.syslog
데몬은 시스템 로그를 중앙화하고 기록한다.Daemon 프로세스는 부모 프로세스로부터 독립하기 위해 특정한 생성 과정을 거친다.
fork()
호출로 부모와 자식 분리init
프로세스의 자식이 된다.pid_t pid = fork();
if (pid > 0) exit(0); // 부모 프로세스 종료
setsid()
호출로 세션 생성if (setsid() < 0) exit(1); // 새로운 세션 생성 실패 시 종료
/
)로 이동.chdir("/"); // 루트 디렉토리로 이동
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
import os
import sys
def daemonize():
if os.fork() > 0:
sys.exit(0) # 부모 종료
os.setsid() # 새로운 세션 생성
if os.fork() > 0:
sys.exit(0) # 자식 종료
sys.stdout.flush()
sys.stderr.flush()
with open("/dev/null", "r") as devnull:
os.dup2(devnull.fileno(), sys.stdin.fileno())
os.dup2(devnull.fileno(), sys.stdout.fileno())
os.dup2(devnull.fileno(), sys.stderr.fileno())
if __name__ == "__main__":
daemonize()
while True:
pass # Daemon 작업 수행
Daemon 프로세스는 시스템이 부팅될 때 자동으로 시작되는 경우가 많다. 이는 운영체제의 서비스 관리 시스템에 의해 제어된다.
/etc/init.d
스크립트를 사용해 Daemon 프로세스를 시작하고 관리했다.[Unit]
Description=Example Daemon
[Service]
ExecStart=/usr/bin/example_daemon
Restart=always
[Install]
WantedBy=multi-user.target
systemctl start example.service # Daemon 시작
systemctl enable example.service # 부팅 시 자동 실행
운영체제는 Daemon 프로세스를 활용해 사용자와 직접 상호작용하지 않으면서 시스템 유지 관리, 작업 스케줄링, 서비스 시작과 같은 핵심 기능을 수행한다.
# 매일 자정에 백업 스크립트 실행
0 0 * * * /usr/local/bin/backup.sh
systemctl start nginx # Nginx Daemon 시작
systemctl status nginx # Nginx 상태 확인
운영체제에서 이러한 Daemon은 사용자 경험을 향상시키고 시스템의 신뢰성을 유지하는 데 필수적이다.
서버 애플리케이션은 Daemon 프로세스를 사용해 사용자 요청을 처리하고, 안정적인 네트워크 서비스를 제공한다.
httpd.conf
)을 기반으로 동작하며, 필요한 리소스를 미리 로드하여 성능을 최적화한다.systemctl start apache2
systemctl stop apache2
worker_processes 4;
events {
worker_connections 1024;
}
서버 애플리케이션에서 Daemon은 안정적인 네트워크 서비스 제공과 고성능 처리를 보장한다.
Daemon은 네트워크 서비스에서 중요한 역할을 하며, 데이터 전송, 연결 관리, 보안 등의 작업을 담당한다.
sshd
)systemctl status sshd
dhcpd
)named
)named.conf
)을 통해 동작을 정의.multiprocessing
모듈을 사용한 Daemon 프로세스Python의 multiprocessing
모듈은 Daemon 프로세스를 간단히 생성하고 관리할 수 있도록 지원한다. Daemon 프로세스는 부모 프로세스와 독립적으로 실행되지 않고, 부모 프로세스가 종료되면 함께 종료된다.
multiprocessing
의 주요 특징multiprocessing
을 사용한 Daemon 프로세스from multiprocessing import Process
import time
def background_task(name):
while True:
print(f"Running {name} in the background...")
time.sleep(2)
if __name__ == "__main__":
# Daemon 프로세스 생성
daemon_process = Process(target=background_task, args=("Daemon Process",), daemon=True)
daemon_process.start()
print("Main process is running. Daemon process will stop if this process ends.")
# Main 프로세스가 5초 후 종료
time.sleep(5)
print("Main process exiting. Daemon process will stop now.")
Process
클래스:target
: 실행할 함수args
: 함수에 전달할 인자daemon=True
: Daemon 프로세스로 설정daemon=True
설정: Daemon 프로세스는 부모 프로세스 종료와 함께 종료된다.아래 코드는 파일에 주기적으로 로그를 기록하는 Daemon 서비스를 구현한 예제이다.
import os
import sys
import time
def daemonize(log_file):
# 1. 부모 프로세스 종료
if os.fork() > 0:
sys.exit(0)
# 2. 새로운 세션 생성
os.setsid()
# 3. 자식 프로세스 생성 후 부모 종료
if os.fork() > 0:
sys.exit(0)
# 4. 파일 디스크립터 닫기
sys.stdout.flush()
sys.stderr.flush()
with open("/dev/null", "w") as null_out:
os.dup2(null_out.fileno(), sys.stdout.fileno())
os.dup2(null_out.fileno(), sys.stderr.fileno())
# 5. 로그 작성
with open(log_file, "a") as f:
while True:
f.write(f"Daemon is running at {time.ctime()}\n")
f.flush()
time.sleep(5)
if __name__ == "__main__":
log_file = "/tmp/daemon.log"
daemonize(log_file)
os.fork()
호출:os.setsid()
: 새로운 세션 생성으로 터미널과 연결을 끊음.sys.stdout
과 sys.stderr
를 /dev/null
로 리다이렉트하여 표준 입출력을 비활성화.tail -f /tmp/daemon.log
Python으로 Daemon을 구현할 때는 다음과 같은 사항을 고려해야 한다.
logging
모듈을 활용하면 로그 관리가 용이하다.import logging
logging.basicConfig(filename='/tmp/daemon.log', level=logging.INFO)
logging.info('Daemon started successfully.')
Daemon 프로세스는 무한 루프에서 작동하므로 예외 발생 시 종료되지 않도록 오류를 처리해야 한다.
try:
# 작업 수행
pass
except Exception as e:
logging.error(f"Error: {e}")
import signal
def terminate_handler(signum, frame):
logging.info("Daemon shutting down.")
sys.exit(0)
signal.signal(signal.SIGTERM, terminate_handler)
Daemon 프로세스는 시스템의 핵심 서비스로 작동하며, 잘못된 설정이나 취약점이 발생할 경우 심각한 보안 문제를 유발할 수 있다.
# 전용 사용자 계정 생성
sudo useradd -r -s /bin/false daemon_user
# 서비스 실행 권한 부여
sudo chown daemon_user:daemon_user /var/daemon_directory
# UFW를 활용한 포트 제한
sudo ufw allow from 192.168.1.0/24 to any port 8080
pip-audit
)를 사용한다.Daemon은 사용자와 직접 상호작용하지 않으므로, 로그를 통해 상태를 파악하고 문제를 진단하는 것이 필수적이다.
logging
모듈을 활용하여 효율적으로 로그를 관리할 수 있다.import logging
logging.basicConfig(
filename="/var/log/daemon.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.info("Daemon started successfully.")
/var/log/daemon.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
}
htop
, top
, ps
등을 활용한다.ps -ef | grep daemon_name
Daemon은 시스템의 필수 구성 요소로서 지속적인 유지보수와 업데이트가 필요하다.
systemctl
명령을 통해 Daemon의 상태를 확인하고 로그를 분석한다.systemctl status daemon_name
테스트 환경에서의 검증:
점진적 배포:
핫스왑 기술 활용:
systemd
의 reload 명령으로 실행 중인 프로세스를 중단 없이 재구성.systemctl reload daemon_name
올 한 해는 여러 일들이 겹쳐서 다사다난한 한 해가 될 것으로 예상된다. 교육 수료에 자격증, 복학까지... 최선을 다해보자!