1. init vs systemd 비교

부팅 프로세스

BIOS/UEFI → 부트로더(GRUB) → 커널(vmlinuz) → init/systemd (PID 1)
단계설명
BIOS/UEFI하드웨어 초기화, POST(Power-On Self-Test), 부트 디바이스 탐색
부트로더 (GRUB2)커널 이미지 로드, 커널 파라미터 전달, initramfs 로드
커널하드웨어 초기화, 드라이버 로드, 루트 파일시스템 마운트
init/systemdPID 1로 실행. 사용자 공간 초기화, 서비스 시작

SysV init vs systemd

구분SysV initsystemd
도입Unix 전통2010년~ (RHEL 7, Ubuntu 15.04~)
설정/etc/init.d/ 쉘 스크립트Unit 파일 (.service, .socket 등)
서비스 시작순차적 (느림)병렬 (빠름)
의존성순서 번호 기반 (S01, S02…)명시적 의존성 선언
제어service, /etc/init.d/xxxsystemctl
로그syslog (/var/log/)journald (journalctl)
런레벨/타겟런레벨 (0-6)타겟 (*.target)
소켓 활성화지원 안 함지원 (on-demand 서비스 시작)
cgroups미사용자원 관리에 활용
# 현재 init 시스템 확인
ps -p 1 -o comm=     # systemd 또는 init
readlink -f /sbin/init   # /usr/lib/systemd/systemd

2. 런레벨(SysV) vs 타겟(systemd)

SysV 런레벨

런레벨설명
0시스템 종료 (halt)
1단일 사용자 모드 (복구, 네트워크 없음)
2다중 사용자 (NFS 없음, Debian에서는 기본)
3다중 사용자 + 네트워크 (CLI, 서버 기본)
4미사용 (사용자 정의)
5다중 사용자 + 네트워크 + GUI (데스크톱 기본)
6재부팅 (reboot)
runlevel        # 이전 런레벨, 현재 런레벨 출력 (예: N 5)
who -r          # 현재 런레벨 (SysV)

systemd 타겟

타겟SysV 대응설명
poweroff.target0시스템 종료
rescue.target1단일 사용자 모드 (복구)
multi-user.target3CLI 다중 사용자 (서버 기본)
graphical.target5GUI 다중 사용자 (데스크톱 기본)
reboot.target6재부팅
emergency.target-비상 모드 (최소 환경)
# 현재 타겟 확인
systemctl get-default              # 기본 타겟 (예: multi-user.target)
 
# 기본 타겟 변경
sudo systemctl set-default multi-user.target    # CLI 모드로 부팅
sudo systemctl set-default graphical.target     # GUI 모드로 부팅
 
# 즉시 타겟 전환
sudo systemctl isolate multi-user.target        # GUI → CLI 전환
sudo systemctl isolate rescue.target            # 복구 모드 진입
 
# 타겟 목록 확인
systemctl list-units --type=target
systemctl list-units --type=target --all        # 비활성 포함

3. systemctl - 서비스 관리 핵심 명령

기본 서비스 제어

# 서비스 시작/중지/재시작
sudo systemctl start nginx          # 즉시 시작
sudo systemctl stop nginx           # 즉시 중지
sudo systemctl restart nginx        # 중지 후 시작 (연결 끊김)
sudo systemctl reload nginx         # 설정 재로드 (연결 유지, 지원하는 서비스만)
sudo systemctl reload-or-restart nginx   # reload 가능하면 reload, 아니면 restart
 
# 부팅 시 자동 실행 설정
sudo systemctl enable nginx         # 부팅 시 자동 시작 등록
sudo systemctl disable nginx        # 자동 시작 해제
sudo systemctl enable --now nginx   # 등록 + 즉시 시작 (enable + start 동시)
sudo systemctl disable --now nginx  # 해제 + 즉시 중지
 
# 서비스 마스킹 (아예 시작 불가능하게)
sudo systemctl mask nginx           # 시작 시도해도 거부됨
sudo systemctl unmask nginx         # 마스크 해제

상태 확인

# 서비스 상태 상세 확인
systemctl status nginx              # 상태, PID, 최근 로그 등 표시
 
# 간단 확인
systemctl is-active nginx           # active 또는 inactive
systemctl is-enabled nginx          # enabled 또는 disabled
systemctl is-failed nginx           # failed 또는 active
 
# 서비스 목록
systemctl list-units --type=service                 # 로드된 서비스
systemctl list-units --type=service --state=running # 실행 중인 서비스만
systemctl list-units --type=service --failed        # 실패한 서비스
systemctl list-unit-files --type=service            # 모든 서비스 파일 (활성화 상태 포함)
 
# Unit 파일 내용 확인
systemctl cat nginx.service         # Unit 파일 내용 출력
systemctl show nginx.service        # 모든 속성(property) 표시
systemctl show nginx -p MainPID     # 특정 속성만

daemon-reload

Unit 파일을 수정한 후 systemd에 변경 사항을 알린다.

sudo systemctl daemon-reload        # Unit 파일 변경 반영 (서비스 재시작 아님!)
sudo systemctl restart nginx        # 이후 서비스 재시작

4. Unit 파일 구조

systemd의 설정 단위. /usr/lib/systemd/system/ (패키지 제공)과 /etc/systemd/system/ (관리자 커스텀)에 위치.

Unit 파일 위치 우선순위

경로용도우선순위
/etc/systemd/system/관리자 커스텀 설정최고 (가장 높음)
/run/systemd/system/런타임 생성중간
/usr/lib/systemd/system/패키지가 설치한 기본 설정최저

Unit 파일 섹션

# /etc/systemd/system/myapp.service
 
[Unit]
Description=My Application Service
Documentation=https://docs.example.com
After=network.target postgresql.service      # 이 유닛 이후에 시작
Requires=postgresql.service                   # 이 유닛이 실패하면 같이 실패
Wants=redis.service                           # 이 유닛이 실패해도 상관없음
 
[Service]
Type=simple                                   # 서비스 타입
User=appuser                                  # 실행 사용자
Group=appgroup                                # 실행 그룹
WorkingDirectory=/opt/myapp                   # 작업 디렉토리
Environment=NODE_ENV=production               # 환경변수
EnvironmentFile=/opt/myapp/.env               # 환경변수 파일
ExecStartPre=/usr/bin/echo "Starting..."      # 시작 전 실행
ExecStart=/usr/bin/node /opt/myapp/server.js  # 메인 프로세스 시작 명령
ExecStartPost=/usr/bin/echo "Started!"        # 시작 후 실행
ExecStop=/bin/kill -SIGTERM $MAINPID          # 중지 명령 (기본값이므로 보통 생략)
ExecReload=/bin/kill -HUP $MAINPID            # reload 명령
Restart=on-failure                            # 재시작 정책
RestartSec=5                                  # 재시작 대기 시간
TimeoutStartSec=30                            # 시작 타임아웃
TimeoutStopSec=30                             # 중지 타임아웃
 
# 보안 강화 옵션
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/myapp/data
 
[Install]
WantedBy=multi-user.target                    # enable 시 이 타겟에 연결됨

주요 속성 상세

[Unit] 섹션 - 의존성/순서:

속성설명
After=지정된 유닛이 시작된 후에 이 유닛 시작 (순서만, 의존성 아님)
Before=이 유닛이 먼저 시작된 후 지정된 유닛 시작
Requires=강한 의존성 - 지정된 유닛이 실패하면 이 유닛도 중지
Wants=약한 의존성 - 지정된 유닛이 실패해도 이 유닛은 계속 실행
Conflicts=동시에 실행될 수 없는 유닛

[Service] 섹션 - Type:

Type설명
simple기본값. ExecStart가 메인 프로세스
forking데몬 방식. 부모 프로세스가 fork 후 종료 (PIDFile 필요)
oneshot한 번 실행 후 종료 (스크립트 등). RemainAfterExit=yes와 함께 사용
notifysd_notify()로 준비 완료를 알림
idle모든 작업 완료 후 시작

[Service] 섹션 - Restart:

Restart 값재시작 조건
no재시작 안 함 (기본)
on-failure비정상 종료 시 (exit code != 0, signal, timeout)
on-abnormalsignal, timeout, watchdog에 의한 종료 시
on-success정상 종료 시 (exit code 0)
always항상 재시작 (systemctl stop 제외)

[Install] 섹션:

속성설명
WantedBy=enable 시 심볼릭 링크가 생성될 타겟 디렉토리
RequiredBy=강한 의존성으로 연결
Alias=서비스의 별칭

5. 커스텀 서비스 작성 예시

예시 1: Node.js 웹 애플리케이션

# /etc/systemd/system/nodeapp.service
[Unit]
Description=Node.js Application
After=network.target
 
[Service]
Type=simple
User=nodeapp
Group=nodeapp
WorkingDirectory=/opt/nodeapp
ExecStart=/usr/bin/node app.js
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=nodeapp
Environment=NODE_ENV=production PORT=3000
 
[Install]
WantedBy=multi-user.target

예시 2: Python 서비스 (Gunicorn)

# /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn WSGI Server
After=network.target
 
[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/opt/mydjango
ExecStart=/opt/mydjango/venv/bin/gunicorn \
    --workers 4 \
    --bind unix:/run/gunicorn.sock \
    myproject.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
 
[Install]
WantedBy=multi-user.target

예시 3: 원샷 스크립트 (시스템 초기화 작업)

# /etc/systemd/system/cleanup.service
[Unit]
Description=Cleanup Temporary Files on Boot
After=local-fs.target
 
[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh
RemainAfterExit=yes
 
[Install]
WantedBy=multi-user.target

커스텀 서비스 등록 절차

# 1. Unit 파일 작성
sudo vi /etc/systemd/system/myapp.service
 
# 2. systemd 리로드 (새 파일 인식)
sudo systemctl daemon-reload
 
# 3. 서비스 시작 및 테스트
sudo systemctl start myapp
sudo systemctl status myapp
 
# 4. 부팅 시 자동 시작 등록
sudo systemctl enable myapp
 
# 5. 로그 확인
journalctl -u myapp -f

6. journalctl - systemd 저널 로그

systemd의 통합 로깅 시스템. 바이너리 형식으로 저장되어 구조화된 검색이 가능하다.

# 전체 로그
journalctl                         # 모든 로그 (oldest first)
journalctl -r                      # 역순 (newest first)
journalctl --no-pager              # 페이저 없이 출력
 
# 특정 서비스 로그 (-u: unit)
journalctl -u nginx                # nginx 서비스 로그
journalctl -u nginx -u php-fpm    # 여러 서비스
 
# 실시간 추적 (-f: follow, tail -f와 유사)
journalctl -f                      # 전체 실시간
journalctl -u nginx -f            # nginx 실시간
 
# 시간 범위 필터
journalctl --since "2026-03-20 09:00:00"
journalctl --since "1 hour ago"
journalctl --since "2026-03-19" --until "2026-03-20"
journalctl --since yesterday
 
# 부팅 기준
journalctl -b                      # 현재 부팅의 로그
journalctl -b -1                   # 이전 부팅의 로그
journalctl --list-boots            # 부팅 목록
 
# 우선순위 필터 (-p: priority)
journalctl -p err                  # error 이상만
journalctl -p warning              # warning 이상만
# 우선순위 레벨: emerg(0) > alert(1) > crit(2) > err(3) > warning(4) > notice(5) > info(6) > debug(7)
 
# 커널 메시지 (dmesg 대안)
journalctl -k                      # 커널 메시지만
 
# 특정 PID / UID
journalctl _PID=1234
journalctl _UID=1000
 
# 출력 형식
journalctl -o json                 # JSON 형식
journalctl -o json-pretty          # JSON (가독성)
journalctl -o short-iso            # ISO 타임스탬프
journalctl -o verbose              # 모든 필드 표시
 
# 디스크 사용량 관리
journalctl --disk-usage            # 저널 디스크 사용량
sudo journalctl --vacuum-size=500M # 500MB로 축소
sudo journalctl --vacuum-time=30d  # 30일 이전 로그 삭제

journald 설정

# /etc/systemd/journald.conf
# [Journal]
# Storage=persistent              # 재부팅 후에도 로그 유지 (/var/log/journal/)
# SystemMaxUse=500M               # 최대 디스크 사용량
# MaxRetentionSec=30day           # 최대 보관 기간
# ForwardToSyslog=yes             # rsyslog로 전달
 
# 설정 변경 후 적용
sudo systemctl restart systemd-journald

7. cron - 반복 예약 작업

crontab 명령

crontab -e          # 현재 사용자의 crontab 편집
crontab -l          # 현재 사용자의 crontab 목록 확인
crontab -r          # 현재 사용자의 crontab 전체 삭제 (주의!)
crontab -u phh -l   # 특정 사용자의 crontab 확인 (root만)

cron 표현식

특수 문자:

문자설명예시
*모든 값* * * * * (매분)
,여러 값0,30 * * * * (매시 0분, 30분)
-범위0 9-17 * * * (9시~17시 매시 0분)
/간격*/5 * * * * (5분마다)

cron 표현식 예시:

# 매분 실행
* * * * * /path/to/script.sh
 
# 매일 새벽 2시 30분
30 2 * * * /path/to/backup.sh
 
# 매주 월요일 오전 9시
0 9 * * 1 /path/to/weekly.sh
 
# 매월 1일 자정
0 0 1 * * /path/to/monthly.sh
 
# 평일(월-금) 매 6시간마다
0 */6 * * 1-5 /path/to/script.sh
 
# 매년 1월 1일 자정
0 0 1 1 * /path/to/yearly.sh
 
# 1월과 7월의 매주 일요일 새벽 3시
0 3 * 1,7 0 /path/to/script.sh
 
# 5분마다 (가장 흔한 모니터링 패턴)
*/5 * * * * /path/to/check.sh
 
# 업무 시간 중 10분마다
*/10 9-18 * * 1-5 /path/to/script.sh

crontab 실전 작성 팁:

# 환경변수 설정 (cron은 최소 환경에서 실행됨!)
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com            # 출력을 이메일로 전송
 
# 출력 리다이렉션 (메일 방지)
0 2 * * * /path/to/script.sh > /var/log/myscript.log 2>&1
 
# 출력 완전히 버리기
0 2 * * * /path/to/script.sh &>/dev/null
 
# 잠금 (중복 실행 방지)
*/5 * * * * flock -n /tmp/myjob.lock /path/to/script.sh

시스템 cron

# /etc/crontab - 시스템 전체 crontab (사용자 필드 포함)
cat /etc/crontab
# 분 시 일 월 요일 사용자 명령
# 0 3 * * * root /usr/local/bin/backup.sh
 
# /etc/cron.d/ - 추가 시스템 cron 파일 (형식은 /etc/crontab과 동일)
ls /etc/cron.d/
 
# 주기별 디렉토리 (스크립트 넣으면 자동 실행)
ls /etc/cron.hourly/       # 매시
ls /etc/cron.daily/        # 매일
ls /etc/cron.weekly/       # 매주
ls /etc/cron.monthly/      # 매월
# 이 디렉토리의 스크립트는 run-parts에 의해 실행됨 (확장자 없어야 함)
 
# 접근 제어
/etc/cron.allow             # 이 파일에 있는 사용자만 cron 사용 가능
/etc/cron.deny              # 이 파일에 있는 사용자는 cron 사용 불가
# allow가 있으면 deny는 무시됨

anacron

시스템이 꺼져 있을 때 놓친 작업을 나중에 실행해주는 도구. 서버보다는 데스크톱에서 유용.

cat /etc/anacrontab
# period_in_days  delay_in_minutes  job-identifier  command
# 1               5                 cron.daily      nice run-parts /etc/cron.daily
# 7               25                cron.weekly     nice run-parts /etc/cron.weekly
# @monthly        45                cron.monthly    nice run-parts /etc/cron.monthly
필드설명
period실행 주기 (일 단위)
delay부팅 후 대기 시간 (분)
job-id작업 식별자 (/var/spool/anacron/에 타임스탬프 저장)
command실행할 명령

8. at - 일회성 예약 작업

특정 시간에 한 번만 실행되는 작업을 예약한다.

# 작업 예약
at 2:00 AM                          # 오전 2시에 실행
at 14:30                             # 오후 2시 30분
at now + 30 minutes                  # 30분 후
at now + 2 hours                     # 2시간 후
at now + 1 day                       # 내일 지금 시각
at 10:00 AM 2026-03-25              # 특정 날짜/시각
at midnight                          # 자정
at noon                              # 정오
at teatime                           # 오후 4시
 
# at 프롬프트에서 명령 입력 후 Ctrl+D로 저장
at now + 5 minutes
at> /path/to/backup.sh
at> echo "백업 완료" | mail -s "Backup" admin@example.com
at> <Ctrl+D>
 
# 파이프로 입력
echo "/path/to/script.sh" | at now + 1 hour
 
# heredoc으로 입력
at now + 10 minutes << 'EOF'
/path/to/script.sh
echo "완료" >> /tmp/log.txt
EOF

작업 관리

atq                 # 예약된 작업 목록 (= at -l)
at -c 5             # 작업 번호 5의 내용 확인
atrm 5              # 작업 번호 5 삭제 (= at -d 5)

접근 제어

/etc/at.allow       # 이 파일에 있는 사용자만 at 사용 가능
/etc/at.deny        # 이 파일에 있는 사용자는 at 사용 불가

9. 부팅 시 자동 실행 설정

systemd (권장)

# 서비스 자동 시작 등록
sudo systemctl enable myservice              # WantedBy 타겟에 심볼릭 링크 생성
sudo systemctl enable --now myservice        # 등록 + 즉시 시작
 
# 자동 시작 해제
sudo systemctl disable myservice
 
# 확인
systemctl is-enabled myservice
systemctl list-unit-files --state=enabled    # 활성화된 모든 서비스

원리: systemctl enable/etc/systemd/system/<target>.wants/ 디렉토리에 Unit 파일의 심볼릭 링크를 생성한다.

ls -la /etc/systemd/system/multi-user.target.wants/
# lrwxrwxrwx 1 root root 38 ... nginx.service -> /lib/systemd/system/nginx.service

SysV init (레거시)

# Debian/Ubuntu
sudo update-rc.d myservice defaults     # 자동 시작 등록
sudo update-rc.d myservice remove       # 해제
 
# RHEL/CentOS 6
sudo chkconfig myservice on             # 자동 시작 등록
sudo chkconfig myservice off            # 해제
sudo chkconfig --list                    # 모든 서비스 런레벨별 상태

/etc/rc.local (레거시)

모든 서비스 시작 후 마지막에 실행되는 스크립트. 현대 systemd 시스템에서도 rc-local.service로 호환 지원하는 경우가 있다.

# /etc/rc.local (실행 권한 필요: chmod +x)
#!/bin/bash
/usr/local/bin/custom_startup.sh
exit 0

cron @reboot

# crontab에서
@reboot /path/to/startup_script.sh