서비스 관리 (systemd)

Linux 시스템의 서비스, 데몬, 부팅 과정을 관리하는 systemd 완벽 가이드


Linux 시스템의 서비스, 데몬, 부팅 과정을 관리하는 systemd 완벽 가이드

목표: 서비스를 직접 작성하고, 부팅 과정을 제어할 수 있는 수준


🏗️ systemd 개요

systemd란?

Linux 시스템 및 서비스 관리자 (System and Service Manager)

  • 전통 init 시스템 대체: SysV init, Upstart를 대체
  • 병렬 부팅: 의존성 기반 병렬 시작으로 빠른 부팅
  • 온디맨드 데몬: 필요할 때만 서비스 시작 (소켓 활성화)
  • 컨트롤 그룹: 프로세스 추적 및 리소스 제한

주요 구성 요소

구성 요소설명
systemdPID 1, 시스템 및 서비스 관리자
systemctl서비스 제어 명령어
journald시스템 로그 관리
logind사용자 로그인 관리
networkd네트워크 설정 관리
timedated시스템 시간/날짜 관리
resolvedDNS 확인
udevd장치 관리

📋 서비스 제어

기본 명령어

# 서비스 시작
systemctl start nginx

# 서비스 중지
systemctl stop nginx

# 서비스 재시작
systemctl restart nginx

# 설정 재로드 (재시작 없이)
systemctl reload nginx

# 재시작 또는 시작 (상태에 따라)
systemctl try-restart nginx

# 재로드 또는 시작
systemctl try-reload-or-restart nginx

# 현재 상태 확인
systemctl status nginx

# 활성화 (부팅 시 자동 시작)
systemctl enable nginx

# 비활성화 (부팅 시 자동 시작 해제)
systemctl disable nginx

# 마스크 (완전히 비활성화, 수동 시작도 불가)
systemctl mask nginx

# 마스크 해제
systemctl unmask nginx

상태 확인

# 서비스 상태
systemctl is-active nginx       # 활성 상태 (active/inactive)
systemctl is-enabled nginx      # 활성화 상태 (enabled/disabled/masked)
systemctl is-failed nginx       # 실패 상태

# 모든 서비스 목록
systemctl list-units --type=service

# 활성 서비스만
systemctl list-units --type=service --state=active

# 실패한 서비스
systemctl list-units --type=service --state=failed

# 활성화된 서비스 (부팅 시 시작)
systemctl list-unit-files --type=service --state=enabled

# 전체 서비스 목록 (활성/비활성 모두)
systemctl list-unit-files --type=service

📝 유닛 파일 (Unit Files)

유닛 파일 위치

우선순위경로설명
1/etc/systemd/system/관리자 설정 (최우선)
2/run/systemd/system/런타임 설정
3/usr/lib/systemd/system/패키지 기본 설정 (Debian/Ubuntu)
4/lib/systemd/system/패키지 기본 설정 (RHEL/CentOS)

서비스 유닛 파일 구조

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application Service
Documentation=https://example.com/docs
After=network.target postgresql.service
Wants=network.target
Requires=postgresql.service

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
Environment="NODE_ENV=production"
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/bin/node /opt/myapp/server.js
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5
KillMode=process

[Install]
WantedBy=multi-user.target

[Unit] 섹션

[Unit]
Description=서비스 설명
Documentation=man:nginx(8) https://nginx.org/docs/

# 부팅 순서 (After: 나중에, Before: 먼저)
After=network.target remote-fs.target nss-lookup.target
Before=multi-user.target

# 의존성 (Wants: 약한 의존, Requires: 강한 의존)
Wants=network.target
Requires=postgresql.service

# 조걶
ConditionPathExists=/etc/myapp/config.yml
ConditionDirectoryNotEmpty=/var/lib/myapp

# 충돌
Conflicts=apache2.service

[Service] 섹션

서비스 유형 (Type)

타입설명사용처
simpleExecStart가 메인 프로세스대부분의 서비스
forking부모가 fork 후 종료전통적인 데몬 (Apache)
oneshot한 번 실행 후 종료초기화 스크립트
dbusD-Bus 이름 획득 후 완료D-Bus 서비스
notifysd-notify로 준비 완료 알림복잡한 서비스
idle다른 작업 완료 후 시작데스크톱 서비스

실행 설정

[Service]
# 실행 사용자/그룹
User=myapp
Group=myapp

# 작업 디렉토리
WorkingDirectory=/opt/myapp

# 환경변수
Environment="NODE_ENV=production"
Environment="PORT=8080"
EnvironmentFile=-/etc/myapp/env    # - 접두사: 파일 없어도 OK

# 실행 명령
ExecStart=/usr/bin/node server.js
ExecStartPre=/opt/myapp/bin/check-config
ExecStartPost=/opt/myapp/bin/notify-start
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
ExecStopPost=/opt/myapp/bin/cleanup

# 재시작 정책
Restart=on-failure
RestartSec=5
StartLimitInterval=60
StartLimitBurst=3

# 타임아웃
TimeoutStartSec=30
TimeoutStopSec=30
TimeoutSec=30

# PID 파일 (forking 타입)
PIDFile=/run/myapp.pid

# 표준 출력/에러
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp

재시작 정책 (Restart)

설명
no재시작 안함 (기본)
on-success정상 종료 시 (exit code 0)
on-failure실패 시 (exit code ≠ 0)
on-abnormal시그널/타임아웃/감시 실패
on-abort정상 종료를 제외한 모든 경우
always항상

킬 모드 (KillMode)

설명
control-group전체 컨트롤 그룹 종료 (기본)
process메인 프로세스만
mixed메인 프로세스 SIGTERM, 나머지 SIGKILL
none종료하지 않음

[Install] 섹션

[Install]
# 활성화 시 타겟
WantedBy=multi-user.target

# 별칭
Alias=myappd.service

주요 타겟:

타겟설명
graphical.targetGUI 환경
multi-user.target다중 사용자 CLI (runlevel 3)
rescue.target복구 모드 (runlevel 1)
emergency.target긴급 모드

🔄 유닛 파일 관리

새 서비스 등록

# 1. 유닛 파일 생성
sudo nano /etc/systemd/system/myapp.service

# 2. systemd 데몬 재로드
sudo systemctl daemon-reload

# 3. 서비스 시작
sudo systemctl start myapp

# 4. 부팅 시 자동 시작
sudo systemctl enable myapp

# 5. 상태 확인
sudo systemctl status myapp

유닛 파일 수정

# 기본 설정 오버라이드
sudo systemctl edit nginx
# → /etc/systemd/system/nginx.service.d/override.conf 생성

# 전체 유닛 파일 교체
sudo systemctl edit --full nginx

# 수정 후 반드시 데몬 재로드
sudo systemctl daemon-reload

유닛 파일 검증

# 문법 검사
systemd-analyze verify /etc/systemd/system/myapp.service

# 전체 설정 검사
systemd-analyze verify

📊 로그 관리 (journald)

journalctl 사용법

# 모든 로그 (역순)
journalctl

# 최신 로그 실시간 (-f = follow)
journalctl -f

# 특정 서비스 로그
journalctl -u nginx
journalctl -u nginx -f

# 특정 시간 이후
journalctl --since "2026-06-01 10:00"
journalctl --since "1 hour ago"
journalctl --since yesterday

# 시간 범위
journalctl --since "2026-06-01 00:00" --until "2026-06-01 12:00"

# 부팅 이후 로그
journalctl -b
journalctl -b -1          # 이전 부팅

# 특정 PID
journalctl _PID=1234

# 특정 실행 파일
journalctl /usr/bin/nginx

# 로그 레벨 필터
journalctl -p err
# emerg, alert, crit, err, warning, notice, info, debug

# 역순 출력 (최신 먼저)
journalctl -r

# 출력 라인 수 제한
journalctl -n 100

# JSON 형식 출력
journalctl -o json
journalctl -o json-pretty

# 로그 크기 확인
journalctl --disk-usage

# 로그 정리
sudo journalctl --vacuum-time=30d    # 30일 이전 삭제
sudo journalctl --vacuum-size=500M   # 500MB로 제한

영구 로그 저장

# 기본적으로 /run/log에 휘발성 저장
# 영구 저장 활성화
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

🎯 실전 예시

웹 애플리케이션 서비스

# /etc/systemd/system/webapp.service
[Unit]
Description=Web Application
After=network.target postgresql.service

[Service]
Type=simple
User=webapp
Group=webapp
WorkingDirectory=/opt/webapp
Environment="NODE_ENV=production"
Environment="PORT=3000"
ExecStart=/usr/bin/node /opt/webapp/server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=webapp

# 리소스 제한
LimitNOFILE=65536
LimitNPROC=4096

# 보안
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/webapp/data

[Install]
WantedBy=multi-user.target

Python 가상환경 서비스

# /etc/systemd/system/python-app.service
[Unit]
Description=Python Application
After=network.target

[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/python-app
Environment="PATH=/opt/python-app/venv/bin:/usr/local/bin:/usr/bin"
Environment="PYTHONPATH=/opt/python-app"
ExecStart=/opt/python-app/venv/bin/python /opt/python-app/main.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Docker Compose 서비스

# /etc/systemd/system/docker-compose-app.service
[Unit]
Description=Docker Compose Application
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/docker-app
ExecStart=/usr/local/bin/docker-compose up -d
ExecStop=/usr/local/bin/docker-compose down
ExecReload=/usr/local/bin/docker-compose restart

[Install]
WantedBy=multi-user.target

백그라운드 작업 (타이머)

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

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=backup
Group=backup
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily

[Timer]
OnCalendar=daily
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
# 타이머 활성화
systemctl enable backup.timer
systemctl start backup.timer
systemctl list-timers

🔧 고급 기능

소켓 활성화 (Socket Activation)

# /etc/systemd/system/myapp.socket
[Unit]
Description=My Application Socket

[Socket]
ListenStream=8080
Accept=no

[Install]
WantedBy=sockets.target
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
Requires=myapp.socket

[Service]
ExecStart=/usr/bin/myapp
StandardInput=socket

장점:

  • 서비스가 필요할 때만 시작 (메모리 절약)
  • 소켓 유실 없이 서비스 재시작

타겟 (Target) 관리

# 현재 타겟 확인
systemctl get-default

# 기본 타겟 변경
systemctl set-default multi-user.target
systemctl set-default graphical.target

# 특정 타겟으로 부팅
systemctl isolate rescue.target

# 타겟 의존성 확인
systemctl list-dependencies multi-user.target

컨트롤 그룹 (cgroups) 통합

[Service]
# CPU 제한
CPUQuota=50%
CPUShares=512

# 메모리 제한
MemoryMax=512M
MemorySwapMax=0

# I/O 제한
IOReadBandwidthMax=/dev/sda 10M
IOWriteBandwidthMax=/dev/sda 10M

# 태스크 수 제한
TasksMax=100

🚨 트러블슈팅

서비스 시작 실패

# 상세 오류 확인
systemctl status nginx -l
journalctl -u nginx --no-pager

# 유닛 파일 검증
systemd-analyze verify /etc/systemd/system/nginx.service

# 디버그 모드로 실행
systemd-analyze set-log-level debug

# 서비스 수동 실행 (환경 동일하게)
systemctl show-environment
systemd-run --unit=test --service-type=simple /path/to/command

의존성 문제

# 의존성 트리 확인
systemctl list-dependencies nginx

# 역방향 의존성
systemctl list-dependencies --reverse nginx

# 타겟 상태
systemctl list-units --type=target

무한 재시작 루프

# 재시작 횟수 확인
systemctl show nginx -p NRestarts

# StartLimit 설정 확인
systemctl cat nginx | grep -i startlimit

# 일시적으로 재시작 중지
systemctl stop nginx
systemctl reset-failed nginx

📋 체크리스트

  • 유닛 파일 작성 (Unit, Service, Install)
  • systemd 데몬 재로드
  • 서비스 시작/중지/재시작
  • 부팅 시 자동 시작 설정
  • 로그 확인 (journalctl)
  • 의존성 설정 (After, Requires, Wants)
  • 재시작 정책 설정
  • 리소스 제한 (cgroups)
  • 보안 설정 (NoNewPrivileges, ProtectSystem)

🔗 관련 노트

  • 01-04-프로세스-관리 — 프로세스 제어
  • 02-03-부팅-과정-GRUB — 부팅 과정
  • 03-02-성능-모니터링 — 리소스 모니터링
  • 03-03-보안-하드닝 — 서비스 보안
  • 03-00-Linux-내부동작-자가학습 — 커널 낮은 수준

마지막 업데이트: 2026-06-01