1. init vs systemd 비교
부팅 프로세스
BIOS/UEFI → 부트로더(GRUB) → 커널(vmlinuz) → init/systemd (PID 1)
| 단계 | 설명 |
|---|---|
| BIOS/UEFI | 하드웨어 초기화, POST(Power-On Self-Test), 부트 디바이스 탐색 |
| 부트로더 (GRUB2) | 커널 이미지 로드, 커널 파라미터 전달, initramfs 로드 |
| 커널 | 하드웨어 초기화, 드라이버 로드, 루트 파일시스템 마운트 |
| init/systemd | PID 1로 실행. 사용자 공간 초기화, 서비스 시작 |
SysV init vs systemd
| 구분 | SysV init | systemd |
|---|---|---|
| 도입 | Unix 전통 | 2010년~ (RHEL 7, Ubuntu 15.04~) |
| 설정 | /etc/init.d/ 쉘 스크립트 | Unit 파일 (.service, .socket 등) |
| 서비스 시작 | 순차적 (느림) | 병렬 (빠름) |
| 의존성 | 순서 번호 기반 (S01, S02…) | 명시적 의존성 선언 |
| 제어 | service, /etc/init.d/xxx | systemctl |
| 로그 | 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/systemd2. 런레벨(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.target | 0 | 시스템 종료 |
rescue.target | 1 | 단일 사용자 모드 (복구) |
multi-user.target | 3 | CLI 다중 사용자 (서버 기본) |
graphical.target | 5 | GUI 다중 사용자 (데스크톱 기본) |
reboot.target | 6 | 재부팅 |
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와 함께 사용 |
notify | sd_notify()로 준비 완료를 알림 |
idle | 모든 작업 완료 후 시작 |
[Service] 섹션 - Restart:
| Restart 값 | 재시작 조건 |
|---|---|
no | 재시작 안 함 (기본) |
on-failure | 비정상 종료 시 (exit code != 0, signal, timeout) |
on-abnormal | signal, 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 -f6. 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-journald7. 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.shcrontab 실전 작성 팁:
# 환경변수 설정 (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.serviceSysV 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 0cron @reboot
# crontab에서
@reboot /path/to/startup_script.sh