systemd socket 활성화, 서비스를 지연 시작하려면
systemd socket 활성화는 부팅 때 데몬 프로세스를 바로 띄우지 않고, 먼저 소켓(또는 FIFO)만 열어 둔 뒤 첫 연결·트래픽이 오면 짝 .service를 시작합니다. 유닛 형식·지시어는 man systemd.socket(systemd.socket(5))에 정의되어 있습니다.
이 글은 **socket 유닛은? · Accept= 의미는? · timer와 차이는?**만 다룹니다. systemd-timer-oncalendar는 달력·주기, systemd-path-unit은 파일·디렉터리 조건(inotify) 축입니다. 여기서는 IPC·네트워크 소켓·FIFO에 트래픽이 올 때 서비스를 지연 시작하는 축입니다. 제휴·가격·창작 현장 후기는 없습니다.
근거: systemd.socket(5), sd_listen_fds(3), 대비만 systemd.timer(5)·systemd.path(5).
socket 유닛은?
한 줄 답: 이름 끝이 .socket인 유닛은 systemd가 감시하는 소켓·FIFO를 정의하고, 들어오는 트래픽에 맞춰 짝 .service를 시작합니다. enable은 보통 **.socket**만 합니다.
man 요지:
- 짝 서비스 필수 —
foo.socket에는 기본적으로foo.service가 필요합니다(Service=로 바꿀 수 있음).Accept=에 따라 동명 일반 서비스이거나foo@.service템플릿입니다(아래 절). - 암시적 WantedBy/RequiredBy는 없음 — 소켓 → 서비스로 자동
WantedBy=/RequiredBy=가 붙지 않습니다. 서비스만 단독으로 뜨면 스스로 소켓을 열 수 있어야 합니다. 막으려면 서비스 쪽에 명시적Requires=(및 보통After=)를 둡니다. - 데몬 측 수신 — 프로세스는 systemd 네이티브 전달(sd_listen_fds(3), FD는 보통 3부터) 또는 inetd식(
StandardInput=socket)으로 소켓을 받아야 합니다. - 기본 의존 —
DefaultDependencies=를 끄지 않으면 소켓 유닛은sockets.target에Before=등이 붙고, 부팅 초기에 소켓을 준비한 뒤 셧다운에 맞춥니다. 설치 시[Install]에WantedBy=sockets.target을 두는 패턴이 흔합니다.
최소 스케치(Accept=no, TCP 루프백):
# /etc/systemd/system/demo-echo.socket
[Unit]
Description=Demo echo socket (delay-start service)
[Socket]
ListenStream=127.0.0.1:12345
Accept=no
[Install]
WantedBy=sockets.target
# /etc/systemd/system/demo-echo.service
[Unit]
Description=Demo echo service (socket-activated)
Requires=demo-echo.socket
After=demo-echo.socket
[Service]
ExecStart=/usr/local/bin/demo-echo
# 데몬은 sd_listen_fds 등으로 전달된 listening FD를 사용
적용:
sudo systemctl daemon-reload
sudo systemctl enable --now demo-echo.socket
systemctl status demo-echo.socket
# 서비스는 첫 연결 전까지 inactive인 것이 정상인 경우가 많음
ListenStream= / ListenDatagram= / ListenSequentialPacket= 주소 형식(man 요약): /path → AF_UNIX 파일 시스템, @name → abstract UNIX, 포트숫자 → IPv6(및 BindIPv6Only=에 따라 IPv4), v.w.x.y:z → IPv4, [x]:y → IPv6.
vs path / timer: path의 “파일은 어디에?”·timer의 “몇 시에?”가 아니라, 어느 주소·경로의 소켓에 누가 붙었을 때입니다.
Accept= 의미는?
한 줄 답: Accept=no(기본)는 listening 소켓 자체를 하나의 서비스에 넘기고 연결은 그 프로세스가 accept합니다. Accept=yes는 연결마다 템플릿 인스턴스를 띄우고 연결된 소켓만 넘깁니다.
Accept= | 짝 서비스 이름(기본) | 전달되는 FD | 비고(man) |
|---|---|---|---|
no (기본) | foo.service | listening 소켓들 | 성능 민감 시 권장 — 첫 연결만 기동 비용 |
yes | foo@.service 인스턴스 | connection 소켓만 | 연결당 프로세스·샌드박스 분리, inetd형 데몬에 유용 |
| (datagram·FIFO) | — | 값 무시 — 단일 서비스가 트래픽 전부 처리 | man 명시 |
추가 요지:
- 새 데몬은 man이
Accept=no에 맞게 쓰라고 권합니다. 연결 다중화는 서비스 코드 쪽입니다. - AF_UNIX — 받은 소켓을 종료 전
close(2)할 수는 있으나 파일 시스템에서 unlink하면 안 됩니다.Accept=no로 받은 소켓에는shutdown(2)을 쓰지 말 것을,Accept=yes면 허용한다고 적혀 있습니다. - IPv4/IPv6 연결 — 활성화된 서비스에
$REMOTE_ADDR/$REMOTE_PORT가 설정될 수 있습니다(CGI·RFC 3875와 대응한다고 man이 언급). - 네이티브 전달 —
Accept=no에서 데몬은LISTEN_FDS등으로 listening FD를 받고, 보통 FD 번호 3(SD_LISTEN_FDS_START)부터입니다. 자세한 순서는 sd_listen_fds(3).
Accept=yes 이름 규칙 예: foo.socket → 인스턴스 foo@<id>.service (foo@.service 템플릿 필요).
timer와 차이는?
한 줄 답: 시각·주기면 .timer, 경로 조건이면 .path, 소켓·FIFO 트래픽이면 .socket입니다. 셋 다 “짝 서비스를 대신 시작”하지만 트리거 축이 다릅니다.
| 축 | .timer | .path | .socket |
|---|---|---|---|
| 트리거 | OnCalendar= 등 일정 | PathExists= / PathChanged= 등 | ListenStream= 등 + 수신 트래픽 |
| 대표 질문 | 매일 03:00에? | 이 파일이 생겼을 때? | 이 포트·UNIX 소켓에 붙었을 때? |
| 내부 | 타이머fd·캘린더 | inotify | 커널 소켓/FIFO를 systemd가 bind·listen |
| 설치 타깃(흔한 패턴) | timers.target | paths.target | sockets.target |
| 지연 시작 의미 | 다음 시각까지 대기 | 조건 충족까지 대기 | 리스닝만 먼저, 프로세스 기동은 트래픽 시 |
짧게만 대비합니다.
- systemd-timer-oncalendar —
OnCalendar=표현·Persistent=본문은 여기로 가져오지 않습니다. - systemd-path-unit — PathExists/PathChanged·journal 점검은 path 글 축입니다.
- 이 글 — listening을 부팅에 준비해 두고, 데몬 RSS·기동을 수요 시점으로 미루는 socket activation입니다. “매일 돌아야 하는데 소켓은 없음” → timer. “드롭 디렉터리에 파일” → path. “클라이언트가 포트에 접속할 때만” → socket.
FAQ
서비스를 enable해야 하나요?
보통 .socket만 enable --now합니다. 소켓이 트래픽 때 서비스를 시작합니다. 단독 테스트는 systemctl start demo-echo.service로 할 수 있으나, 그때는 서비스가 스스로 소켓을 열 수 있어야 하거나 Requires=로 소켓을 끌어옵니다(man: 암시적 WantedBy 없음).
path·timer와 같은 작업에 겹쳐 써도 되나요?
가능하지만 트리거가 겹치면 기동이 중복될 수 있습니다. 하나의 주 트리거를 고르는 편이 단순합니다. 축이 다르면 글을 갈라 읽습니다.
Accept=yes인데 foo.service만 있으면?
man 규칙상 Accept=yes면 foo@.service 템플릿이 필요합니다. 동명 비템플릿만 있으면 인스턴스화에 실패합니다.
임베디드에서 왜 쓰나요?
항상 상주할 필요가 없는 관리·디버그 리스너에 부팅 시 리스닝 FD만 준비해 두면, 평소 메모리·CPU를 아낄 수 있습니다. 구체 SoC·보드 수치는 이 글 범위 밖입니다.
출처 (Sources)
- systemd.socket(5) —
.socket설명,Accept=,Listen*, 짝 서비스 이름, 기본 의존(sockets.target) - sd_listen_fds(3) — 네이티브 FD 전달
- 인접 축(본문 재탕 없음): systemd-timer-oncalendar (달력), systemd-path-unit (경로/inotify)