1. Standalone 방식
Standalone 방식은 가장 보편적이며, 데몬 자체가 독립적으로 시스템 부팅 시부터 항상 실행 상태를 유지하는 방식이다.
특징
- 시스템 부팅 시 자동으로 실행 (systemd service)
- 지속적으로 포트를 점유하고 클라이언트의 요청을 직접 처리
예시: docker.service
# docker.service 예시
[Unit]
Description=Docker Application Container Engine
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
Restart=always
[Install]
WantedBy=multi-user.target
내부 동작
- 데몬이 자체적으로 포트를 bind()하고 listen()하여 요청을 대기
- 요청이 오면 데몬 프로세스가 직접 accept() 시스템 콜을 통해 처리
- 항상 메모리를 점유하지만, 요청 처리 속도가 빠르고 안정적
2. Socket Activation 방식 (On-demand)
Socket Activation 방식은 systemd가 특정 소켓을 미리 열어두고 클라이언트 요청이 있을 때만 데몬을 실행하는 방식이다. 메모리 효율성이 뛰어나고 필요할 때만 실행된다.
구조
- .socket 유닛: 소켓 리스닝을 systemd가 수행
- .service 유닛: 소켓 연결 시에만 실제 서비스(데몬)가 실행
docker.socket 예시
# docker.socket 예시
[Unit]
Description=Docker Socket for the API
PartOf=docker.service
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
내부 동작 상세
- systemd가 socket(), bind(), listen() 시스템 콜을 이용해 소켓을 미리 열어둠 (포트 또는 파일 점유).
- Docker 클라이언트가 connect() 시스템 콜로 연결 요청을 하면, systemd가 이를 감지.
- systemd는 docker.service를 실행하며, 이미 열린 소켓 파일 디스크립터를 dockerd 프로세스에 전달 (fd 상속).
- dockerd는 전달받은 소켓을 accept()하여 요청 처리 시작.
예시 상황: docker ps 명령 실행 시 내부적으로 일어나는 과정
- 사용자가 터미널에서 docker ps 명령 실행.
- Docker 클라이언트는 /var/run/docker.sock에 connect() 시스템 콜을 호출.
- systemd가 이미 점유 중인 소켓에서 이 연결 요청을 감지.
- systemd가 즉시 docker.service를 실행하고, dockerd 프로세스에 소켓 fd를 넘겨줌.
- dockerd가 요청을 받아 처리하고, 결과를 Docker 클라이언트에 응답으로 전송.
포트 점유에 대한 오해와 진실
systemd에서 .socket 유닛이 많으면 시스템 포트를 다 점유하는 것 아닌가 오해의 소지가 있지만 실제로는 그렇지 않다.
.socket 유닛이 포트를 점유하려면 ListenStream=포트번호나 ListenDatagram=포트번호와 같은 설정이 있어야 한다. 이는 INET 소켓(TCP/UDP)만 해당된다. 대부분의 현대 서비스는 /run/foo.sock처럼 유닉스 도메인 소켓(UNIX domain socket)을 사용한다. 이 경우는 포트가 아니라 파일 경로를 통해 통신하며, 포트 자원과 무관하다. 따라서 systemd의 socket 유닛이 4만 개 있다고 해도, 포트를 지정하지 않았다면 0개의 포트만 점유하고 있을 수도 있다.
유닉스 도메인 소켓이란?
유닉스 도메인 소켓(UNIX domain socket)은 네트워크를 통하지 않고 동일한 시스템 내의 프로세스 간 통신(IPC)을 위한 소켓이다. 일반적으로 /var/run/*.sock 같은 파일 경로 형태로 존재하며, 파일 시스템 상에 생성된다. 통신은 커널이 처리하며, TCP/IP 스택을 거치지 않으므로 매우 빠르고 효율적이다. 접근 권한 제어가 파일 시스템 수준에서 가능하다 (퍼미션, 소유자, 그룹 등).
대표적인 예: Docker의 /var/run/docker.sock, X11의 /tmp/.X11-unix/X0, systemd의 journald 소켓 등
3. Timer 방식 (주기적 작업 실행)
Timer 방식은 특정 주기 또는 시간을 기준으로 데몬이나 명령을 자동으로 실행할 때 사용한다. cron의 개선된 대체 방식이다.
구조
- .timer 유닛: 특정 시간이나 주기를 정의
- .service 유닛: 실제로 실행할 작업을 정의
docker-cleanup.timer 예시
# docker-cleanup.timer 예시
[Unit]
Description=Docker Cleanup Timer
[Timer]
OnCalendar=weekly
Persistent=true
[Install]
WantedBy=timers.target
docker-cleanup.service 예시
# docker-cleanup.service 예시
[Unit]
Description=Docker Cleanup Service
[Service]
Type=oneshot
ExecStart=/usr/bin/docker system prune -af
내부 동작
- systemd가 타이머를 모니터링하며 지정된 시간이 도달하면 해당 서비스 유닛을 실행
- 서비스가 oneshot 형태로 실행되므로 작업 완료 후 바로 종료됨
4. xinetd 방식 (슈퍼 데몬 방식)
xinetd 방식은 별도의 슈퍼 데몬(xinetd)이 다수의 서비스 요청을 감지하여, 요청이 들어왔을 때만 해당 데몬을 실행하는 방식이다. 현재는 많이 사용되지 않지만 여전히 중요한 개념이다.
특징
- xinetd가 미리 여러 포트를 listen 상태로 유지 (포트 점유)
- 클라이언트 요청이 들어오면 xinetd가 해당 요청을 accept()하고 별도의 자식 프로세스를 fork()하여 데몬 실행
내부 동작 상세
- xinetd가 여러 소켓을 미리 열고 listen 상태 유지
- 클라이언트가 접속하면 xinetd가 이를 accept()한 뒤 새로운 자식 프로세스를 fork()
- fork()된 프로세스가 해당 서비스를 exec()하여 요청 처리
장단점
- 장점: 자원을 절약하고 여러 서비스를 효율적으로 관리
- 단점: 프로세스 생성(fork/exec)으로 인한 성능 저하, 관리 복잡성
'CS > Linux' 카테고리의 다른 글
| [Linux] X Window System (3) | 2025.07.27 |
|---|---|
| [Linux] systemd 기반 시스템 운영에 필요한 필수 명령어 (1) | 2025.07.27 |
| [Linux] 파이프와 리다이렉션에서 셸의 역할과 프로세스 생성 원리 (0) | 2025.07.23 |
| [Linux] 마운트 개념 `df -h` 으로 이해하기 (0) | 2024.12.11 |
| [Linux] NAT를 설정하는 방법 (0) | 2024.10.05 |