systemd 서비스 관리 완벽 가이드 — 등록, 로그, 타이머

systemd란?

systemd는 대부분의 최신 Linux 배포판(Ubuntu, CentOS, Fedora, Debian 등)에서 사용하는 시스템 및 서비스 매니저입니다. 부팅 시 프로세스를 시작하고, 서비스의 생명주기를 관리하며, 로그를 수집합니다. 기존 SysVinit의 순차 부팅 방식을 대체하여 병렬 부팅을 지원하므로 부팅 속도가 빠릅니다.

systemd의 핵심 구성 요소는 다음과 같습니다.

구성 요소역할
systemctl서비스 제어 CLI 도구
journalctl로그 조회 도구
unit 파일서비스 정의 파일 (.service, .timer 등)
target서비스 그룹 (런레벨 대체)

서비스 상태 관리

systemctl 명령어로 서비스를 시작, 중지, 재시작하고 상태를 확인합니다.

# 서비스 상태 확인
sudo systemctl status nginx
# ● nginx.service - A high performance web server
#      Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
#      Active: active (running) since Mon 2026-02-19 09:00:00 KST
#    Main PID: 1234 (nginx)

# 서비스 시작 / 중지 / 재시작
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx

# 설정 변경 후 프로세스 재시작 없이 리로드
sudo systemctl reload nginx

# 부팅 시 자동 시작 등록 / 해제
sudo systemctl enable nginx
sudo systemctl disable nginx

# 서비스를 활성화하면서 즉시 시작
sudo systemctl enable --now nginx

enable은 부팅 시 자동 시작을 등록하는 것이고, start는 지금 즉시 시작하는 것입니다. 신규 서비스를 등록할 때는 enable --now를 사용하면 두 명령을 한 번에 처리할 수 있습니다.

커스텀 서비스 파일 작성

Node.js 애플리케이션을 systemd 서비스로 등록하는 예제입니다. 서비스 파일은 /etc/systemd/system/ 디렉토리에 .service 확장자로 생성합니다.

# /etc/systemd/system/my-app.service
[Unit]
# 서비스 설명
Description=My Node.js Application
# 네트워크가 올라온 후 시작
After=network.target
# PostgreSQL 서비스가 먼저 시작된 후 실행
Wants=postgresql.service

[Service]
# 서비스 타입 (simple: 프로세스가 곧 서비스)
Type=simple
# 실행 사용자/그룹
User=deploy
Group=deploy
# 작업 디렉토리
WorkingDirectory=/opt/my-app
# 환경변수 파일 로드
EnvironmentFile=/opt/my-app/.env
# 실행 명령어
ExecStart=/usr/bin/node /opt/my-app/dist/server.js
# 재시작 정책 (비정상 종료 시 재시작)
Restart=on-failure
# 재시작 대기 시간 (초)
RestartSec=5
# 최대 파일 디스크립터 수
LimitNOFILE=65535
# 표준 출력/에러를 journal로 전송
StandardOutput=journal
StandardError=journal
# journal에서 식별할 태그
SyslogIdentifier=my-app

[Install]
# multi-user.target에 포함 (일반 부팅 시 시작)
WantedBy=multi-user.target

서비스 파일을 작성한 후 다음 순서로 등록합니다.

# 서비스 파일 변경 사항 반영
sudo systemctl daemon-reload

# 서비스 활성화 + 즉시 시작
sudo systemctl enable --now my-app.service

# 상태 확인
sudo systemctl status my-app.service
# ● my-app.service - My Node.js Application
#      Loaded: loaded (/etc/systemd/system/my-app.service; enabled)
#      Active: active (running) since Mon 2026-02-19 09:10:00 KST
#    Main PID: 5678 (node)

# 서비스 파일 문법 검증
sudo systemd-analyze verify /etc/systemd/system/my-app.service

daemon-reload는 서비스 파일을 수정할 때마다 반드시 실행해야 합니다. 이 명령 없이는 변경 사항이 반영되지 않습니다.

Service 섹션 주요 옵션

서비스의 동작 방식을 세밀하게 제어하는 옵션들입니다.

옵션설명
Typesimple프로세스 자체가 서비스 (기본값)
Typeforking데몬 방식 (부모 프로세스가 fork 후 종료)
Typeoneshot한 번 실행 후 종료 (스크립트 등)
Typenotify서비스가 준비 완료를 systemd에 알림
Restartno재시작 안 함 (기본값)
Restarton-failure비정상 종료 시만 재시작
Restartalways어떤 이유로든 재시작
RestartSec재시작 전 대기 시간
TimeoutStartSec시작 타임아웃
TimeoutStopSec종료 타임아웃

journalctl 로그 확인

systemd는 모든 서비스 로그를 journal에 통합 저장합니다. journalctl로 조회합니다.

# 특정 서비스 로그 (최신 50줄)
sudo journalctl -u my-app.service -n 50

# 실시간 로그 스트리밍 (tail -f 처럼)
sudo journalctl -u my-app.service -f

# 오늘 로그만 보기
sudo journalctl -u my-app.service --since today

# 특정 시간 범위 로그
sudo journalctl -u my-app.service \
  --since "2026-02-19 09:00" \
  --until "2026-02-19 12:00"

# 에러 로그만 필터링 (priority: emerg, alert, crit, err, warning, notice, info, debug)
sudo journalctl -u my-app.service -p err

# 부팅 이후 로그만 보기
sudo journalctl -u my-app.service -b

# JSON 형식으로 출력 (파싱용)
sudo journalctl -u my-app.service -o json-pretty -n 5

# journal 디스크 사용량 확인 및 정리
sudo journalctl --disk-usage
sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-time=7d

-f 옵션은 장애 대응 시 실시간 로그를 확인할 때 유용합니다. -p err로 에러만 필터링하면 대량의 로그 속에서 문제를 빠르게 찾을 수 있습니다.

systemd 타이머

cron 대신 systemd 타이머를 사용하면 journal과 통합 로깅, 의존성 관리, 실행 실패 시 재시도 등의 이점이 있습니다. 타이머는 .timer 파일과 .service 파일 한 쌍으로 구성합니다.

매일 새벽 3시에 백업 스크립트를 실행하는 예제입니다.

# /etc/systemd/system/backup.service
[Unit]
Description=Daily Database Backup

[Service]
Type=oneshot
User=deploy
ExecStart=/opt/scripts/backup.sh
# 실행 시간 제한 (30분)
TimeoutStartSec=1800
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 3 AM

[Timer]
# 매일 새벽 3시 실행
OnCalendar=*-*-* 03:00:00
# 서버가 꺼져있다가 켜지면 놓친 실행을 즉시 수행
Persistent=true
# 실행 시간에 0~5분 랜덤 지연 (여러 타이머가 동시에 실행되는 것 방지)
RandomizedDelaySec=300

[Install]
WantedBy=timers.target
# 타이머 활성화 + 시작
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

# 등록된 타이머 목록 확인
sudo systemctl list-timers --all
# NEXT                         LEFT          LAST   PASSED   UNIT          ACTIVATES
# Tue 2026-02-20 03:00:00 KST  17h left      -      -        backup.timer  backup.service

# 타이머 수동 실행 (테스트)
sudo systemctl start backup.service

# 타이머 실행 로그 확인
sudo journalctl -u backup.service --since today

OnCalendar 표현식은 cron보다 가독성이 좋습니다. Mon *-*-* 09:00:00(매주 월요일 9시), *-*-01 00:00:00(매월 1일 자정) 같은 형식도 지원합니다.

서비스 디버깅

서비스가 시작되지 않을 때 원인을 찾는 순서입니다.

# 1. 상태 확인 — Active 상태와 에러 메시지 확인
sudo systemctl status my-app.service

# 2. 전체 로그 확인 — 시작 시도 시점부터의 로그
sudo journalctl -u my-app.service --no-pager

# 3. 서비스 파일 문법 검증
sudo systemd-analyze verify /etc/systemd/system/my-app.service

# 4. 의존성 그래프 확인
sudo systemctl list-dependencies my-app.service

# 5. 부팅 시간 병목 분석
sudo systemd-analyze blame
# 3.456s my-app.service
# 2.123s postgresql.service
# 1.234s nginx.service

자주 발생하는 문제와 해결법입니다.

증상원인해결
code=exited, status=203ExecStart 경로 오류실행 파일 경로 확인, which 명령으로 검증
code=exited, status=217User가 존재하지 않음id 사용자명으로 확인
activating (auto-restart) 반복서비스 즉시 종료 후 재시작로그 확인, 환경변수/설정 파일 점검
inactive (dead)enable 안 됨systemctl enable --now 실행

실전 팁

  • 서비스 파일 위치: 직접 작성한 서비스는 /etc/systemd/system/에, 패키지 매니저가 설치한 서비스는 /lib/systemd/system/에 위치합니다. 패키지 서비스를 수정하려면 원본을 편집하지 말고 systemctl edit nginx.service로 오버라이드 파일을 생성하세요.
  • Restart=always vs on-failure: 웹 서버처럼 항상 떠 있어야 하는 서비스는 always, 배치 작업처럼 정상 종료가 의미 있는 경우 on-failure를 사용합니다.
  • 타이머 vs cron: 새 프로젝트에서는 systemd 타이머를 권장합니다. journal 통합 로깅, Persistent=true로 놓친 실행 보완, 의존성 관리 등 cron보다 관리 편의성이 높습니다.
  • 보안 강화: ProtectSystem=strict, ProtectHome=true, NoNewPrivileges=true 옵션으로 서비스의 파일시스템 접근을 제한할 수 있습니다. 프로덕션 서비스에는 적극 활용하세요.
  • 로그 관리: journal은 기본적으로 부팅 시마다 초기화됩니다. /var/log/journal/ 디렉토리를 생성하면 영구 저장됩니다. 디스크 용량 관리를 위해 SystemMaxUse=1G 같은 설정을 /etc/systemd/journald.conf에 추가하세요.

이 글이 도움이 되었나요?