전원 ON부터 로그인까지 30초 — 그 사이에 무슨 일이 일어나는가

서버 전원을 켰다. 30초~1분 뒤 SSH 로그인 프롬프트가 뜬다. 그 사이 30초 동안 무슨 일이 벌어지는가? 대부분 "부팅되겠지" 하고 넘긴다. 하지만 서비스가 부팅 후 자동으로 안 올라오거나, 부팅이 응급 모드(emergency)에 빠져 멈추거나, 부팅이 너무 느릴 때 — 이 연쇄를 모르면 어디서 막혔는지조차 진단할 수 없다.

이 글은 전원 ON부터 로그인 프롬프트까지의 연쇄를 따라간다. 핵심 인물은 systemd, PID 1 — 모든 서비스의 출발점이다.

부팅은 여섯 단계 연쇄다

flowchart LR
    P1["1. 펌웨어<br/>BIOS/UEFI + POST"] --> P2["2. 부트로더<br/>GRUB2 2.12"]
    P2 --> P3["3. 커널 로드<br/>vmlinuz + initramfs"]
    P3 --> P4["4. systemd<br/>PID 1"]
    P4 --> P5["5. target 도달<br/>default.target"]
    P5 --> P6["6. 로그인 프롬프트<br/>getty / 디스플레이 매니저"]

비유하자면 아침에 건물을 여는 절차와 비슷하다 — 경비원 출근(펌웨어) → 안내데스크가 관리실 열쇠 전달(GRUB2) → 임시 관리실 개방(initramfs) → 건물 관리자 출근(systemd) → 층별 전원 병렬 점등(target) → 로비 개방(로그인). 단, 건물은 순차적이지만 systemd는 병렬로 서비스를 올린다(의존성만 충족하면 동시).

각 단계를 좇아보자.

1. 펌웨어(BIOS/UEFI)

POST(Power-On Self-Test) 로 하드웨어를 점검한다(CPU·RAM·저장소가 살아있나). 그리고 부트 디바이스를 찾아 부트로더를 메모리에 올린다. UEFI 시스템이면 ESP(EFI System Partition)의 grubx64.efi를 실행한다.

2. GRUB2(부트로더)

Rocky 10은 GRUB2 2.12. 디스크에서 커널 이미지(vmlinuz-<버전>)와 initramfs를 메모리에 적재하고, 커널 명령줄 매개변수(root=, crashkernel=, rd.lvm.lv= 등)를 전달한다.

부트 엔트리는 과거의 거대한 grub.cfg 스크립트가 아니라 BLS(Boot Loader Specification) 방식 — 커널마다 독립된 .conf 스니펫으로 모듈화되어 있다:

title Rocky Linux (6.12.0-xxx.el10.x86_64)
version 6.12.0-xxx.el10.x86_64
linux /vmlinuz-6.12.0-xxx.el10.x86_64
initrd /initramfs-6.12.0-xxx.el10.x86_64.img
options root=/dev/mapper/rl-root ro crashkernel=2G-64G:256M rd.lvm.lv=rl/root

BLS가 왜 생겼나: 구 GRUB은 /boot/grub2/grub.cfg 하나에 모든 엔트리가 스크립트로 들어가 커널 업데이트마다 재생성이 필요했고 오류가 잦았다. BLS는 커널별 독립 스니펫으로 모듈화해 이 문제를 풀었다. grubby가 관리한다.

3. 커널 + initramfs

커널이 메모리에서 initramfs(압축 CPIO 아카이브)를 tmpfs로 풀어 임시 루트를 만들고, 제어를 systemd로 넘긴다. 왜 굳이 임시 루트를 거치는지는 바로 다음 절에서.

4-6. systemd(PID 1) → target → 로그인

커널이 시작하는 첫 사용자 공간 프로세스가 systemd다. systemd가 target(동기화 체크포인트)을 차례로 도달하며 서비스를 올리고, 마침내 로그인 서비스(getty/sshd/GDM)가 뜬다.

flowchart TD
    SYS["systemd 시작"] --> SYSINIT["sysinit.target<br/>(체크포인트)"]
    SYSINIT --> BASIC["basic.target<br/>(체크포인트)"]
    BASIC --> DEFAULT["default.target<br/>(multi-user 또는 graphical)"]
    DEFAULT --> LOGIN["로그인 서비스<br/>getty/sshd/GDM"]

sysinit.target, basic.target은 체크포인트다. 여기서 실패하면 emergency.target(응급 모드)로 빠진다.

커널은 왜 곧바로 루트를 마운트하지 못할까 — initramfs의 이유

여기서 의문이 든다: 커널이 임시 루트(initramfs)를 거치지 않고 곧바로 진짜 루트(/)를 마운트하면 안 되나? 귀찮게 왜 임시 루트를 거치는가?

핵심 사실: 커널은 만능이 아니다. 루트 파티션이 LVM이면, RAID면, 디스크 암호화면, NVMe/iSCSI 특수 드라이버가 필요하면 — 커널이 혼자서 마운트할 수 없다. 필요한 드라이버와 도구가 있어야 한다. 그 도구를 담은 임시 환경이 initramfs다.

흐름:

  1. 커널이 initramfs를 tmpfs로 풀어 임시 루트 구성.
  2. initramfs가 LVM/RAID/암호화/특수 드라이버 초기화.
  3. 진짜 루트 장치가 준비되면 /sysroot에 마운트 → switch_root로 전환.
  4. 제어를 systemd로 넘김.

구 용어 initrdinitramfs가 혼용되지만 기술적 구분이 있다: initrd = 블록 장치 기반 ramdisk(구식), initramfs = tmpfs 기반 CPIO(현대). 현대 리눅스는 모두 initramfs. LVM/RAID/암호화 루트면 initramfs 없이는 부팅 자체가 불가능하다.

systemd가 모든 것을 총괄한다 — PID 1

systemd는 RHEL/Rocky 7부터 기본 init 시스템이며, PID 1으로 모든 서비스를 관리한다. 핵심 설계 네 가지:

  • 병렬 서비스 시작 — 의존성만 충족하면 동시에 올린다 → 부팅 속도 향상.
  • cgroup 기반 자원 관리 — 서비스별 CPU/메모리를 통제. Rocky 10은 cgroup v2 강제.
  • socket/D-bus activation — 요청이 올 때까지 서비스를 안 띄운다 → 메모리 절약. 첫 연결이 오면 그제야 서비스를 시작하고, 서비스가 죽어도 소켓이 요청을 큐에 담아둬 재시작 시 이어받는다.
  • 통합 로그(journald) — 커널·서비스·syslog 로그를 구조화해 한곳에 수집.

Rocky 10(systemd 257)의 변화: cgroup v1을 폐기하고 항상 v2를 쓴다. System V(init.d) 서비스 스크립트는 deprecated(향후 제거 → 네이티브 unit 파일 권장). 기본 설정 파일 위치가 /etc/systemd/에서 /usr/lib/systemd/로 이동했다(/etc/나 드롭인으로 오버라이드).

cgroup v2 강제의 함정: 구 모니터링 도구·컨테이너 런타임이 cgroup v1 경로(/sys/fs/cgroup/memory/...)를 쓰면 동작하지 않는다. v2 통일 경로(/sys/fs/cgroup/)를 써야 한다.

unit과 target — systemd가 세상을 보는 단위

systemd가 관리하는 모든 것은 unit이다. 접미사로 종류가 갈린다.

unit 종류 접미사 용도
service .service 데몬/서비스 (예: sshd.service)
target .target 동기화 지점/상태 (예: multi-user.target)
socket .socket 소켓 activation
timer .timer cron 대체 스케줄러
mount .mount 파일시스템 마운트
device .device 커널 장치
slice .slice cgroup 계층 그룹

unit 파일 우선순위(높은 순): /etc/systemd/system/(관리자 수정, 최우선) > /run/systemd/system/(런타임) > /usr/lib/systemd/system/(패키지 기본, Rocky 10부터 여기가 기본).

target — runlevel의 현대적 대체

과거 runlevel은 숫자였다(0~6). systemd는 이름 있는 target으로 대체했다.

target 구 runlevel 의미
poweroff.target 0 종료
rescue.target 1, s, single 단일 사용자(구조)
multi-user.target 3 텍스트 다중 사용자(서버 표준)
graphical.target 5 GUI 다중 사용자
reboot.target 6 재부팅
emergency.target 최소 응급(루트만, 거의 아무것도 마운트 안 함)

service unit 파일 구조

# /usr/lib/systemd/system/sshd.service (예시 형태)
[Unit]
Description=OpenSSH server daemon
After=network.target auditd.service       # 의존 순서

[Service]
Type=notify                                # 시작 완료 신호 방식
ExecStart=/usr/sbin/sshd -D $OPTIONS       # 시작 명령
ExecReload=/bin/kill -HUP $MAINPID         # 재로드 명령
Restart=on-failure

[Install]
WantedBy=multi-user.target                 # enable 시 어느 target에 걸지

Type이 서비스 시작을 어떻게 판정하느냐를 결정한다: simple(기본, 즉시 시작으로 간주), forking(fork 후 부모가 종료되면 시작 완료), notify(sd_notify로 준비 신호 받아야 시작 완료), oneshot(일회성).

부팅 시간은 어디서 걸리나 — systemd-analyze

systemd-analyze는 부팅 시간을 세 단계로 쪼개 보여준다.

단계 대략 시간 의미
kernel 1-5초 커널 자체 초기화
initrd 2-10초 initramfs에서 루트 마운트(LVM/암호화면 더 김)
userspace 5-30초 systemd가 서비스 올리는 시간
Startup finished in 3.1s (kernel) + 5.5s (initrd) + 12.8s (userspace) = 21.4s
graphical.target reached after 12.5s in userspace

userspace가 길면 systemd-analyze blame으로 어떤 서비스가 느린지 찾아라. 보통 NetworkManager(네트워크 대기)나 초기화가 무거운 DB가 병목이다. 부팅 최적화의 첫 단추는 "어디서 걸리나"를 아는 것이다.

Rocky 10에서 직접 확인하기

미검증(출처 인용). Rocky 10 VM에서 직접 실행 권장.

# Rocky 10 — UEFI인가 BIOS인가
[ -d /sys/firmware/efi ] && echo "UEFI" || echo "BIOS/Legacy"
# Rocky 10 — 어느 커널로 부팅하나 (BLS 엔트리)
ls /boot/loader/entries/
cat /boot/loader/entries/$(ls /boot/loader/entries/ | head -1)
systemctl --version

확인할 것: Rocky 10은 systemd 257.

systemd 257 (257.x)
+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP ...
# Rocky 10 — 서비스 운영
systemctl status sshd              # 현재 상태
sudo systemctl start sshd          # 즉시 시작
sudo systemctl enable sshd         # 부팅 시 자동 시작 등록
systemctl is-enabled sshd          # 자동 시작 여부
● sshd.service - OpenSSH server daemon
     Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
     Active: active (running) since ...
   Main PID: 1234 (sshd)
# Rocky 10 — target 관리
systemctl get-default              # 현재 기본 target (보통 multi-user.target)
sudo systemctl set-default graphical.target   # 기본 변경
sudo systemctl isolate rescue.target          # 즉시 전환(로그아웃 발생)
# Rocky 10 — 부팅 로그 분석 (어디서 느리거나 막혔나)
journalctl -b                      # 현재 부팅 전체 로그
systemd-analyze                    # 부팅 시간 요약
systemd-analyze blame | head       # 서비스별 시작 시간(느린 순)
systemd-analyze critical-chain     # 병목 서비스
journalctl -u sshd                 # 특정 서비스 로그
journalctl -p err -b               # 이번 부팅 에러만

흔히 묻는 것, 흔히 틀리는 것

오해 정정
"enable하면 지금 시작된다" 아니다. enable은 부팅 시 자동 시작 등록만. 즉시 시작은 start
"start하면 부팅 후에도 자동이다" 아니다. start는 즉시 시작만. 재부팅 후엔 자동 아님
"unit 파일을 고치면 바로 적용된다" 아니다. systemctl daemon-reload로 systemd가 다시 읽게 해야
"구 /etc/sysconfig/network-scripts/를 써야 한다" Rocky 10은 NetworkManager(nmcli) 중심
"service sshd restart는 안 된다" 된다(호환 래퍼). 단 System V 스크립트 자체는 deprecated
"모든 서비스가 순차 시작한다" 아니다. systemd는 병렬 시작(의존성만 충족하면 동시)
"initramfs는 안 쓰는 게 빠르다" LVM/RAID/암호화 루트면 initramfs 없이 부팅 불가
"Rocky 10도 cgroup v1을 쓴다" 아니다. systemd 257이 cgroup v2 강제. v1 경로는 동작 안 함

요약 — 이 글의 결론

  • 부팅 6단계: 펌웨어(POST) → GRUB2 → 커널+initramfs → systemd(PID 1) → target → 로그인.
  • initramfs = 임시 루트. 커널이 혼자 마운트 못 하는 루트(LVM/RAID/암호화) 환경을 제공. 없으면 부팅 불가.
  • systemd = PID 1. 병렬 시작 + cgroup 자원 관리 + socket activation + journald 통합 로그.
  • unit/target: systemd의 관리 단위(unit)와 동기화 지점(target=runlevel 대체, multi-user=3, graphical=5).
  • enable vs start: enable=부팅 자동 등록, start=즉시 시작. 보통 둘 다 필요. unit 수정 후엔 반드시 daemon-reload.
  • Rocky 10 특이: systemd 257, cgroup v2 강제(v1 폐기), System V deprecated, BLS 부트 엔트리, 설정 기본 위치 /usr/lib/systemd/.
  • 부팅 병목systemd-analyze blame으로 잡는다 — userspace가 길면 서비스 탓.

생각해 볼 문제

  1. 전원 ON부터 systemd가 시작되기까지의 단계를 순서대로 말하라.
  2. 왜 커널이 곧바로 루트 파티션을 마운트하지 않고 initramfs를 거치는가?
  3. systemd의 PID는 왜 1인가? (03장의 fork 연쇄와 연결해 생각해 보라)
  4. enablestart의 차이. 두 단계 모두 필요한 이유는?
  5. unit 파일을 수정한 뒤 반드시 해야 하는 명령은? 안 하면 어떻게 되는가?
  6. 부팅이 느릴 때 어느 명령으로 병목 서비스를 찾는가?

참고

'Tech Artifacts > Linux' 카테고리의 다른 글

Linux - 06. io device  (0) 2026.07.09
Linux - 05. filesystem  (0) 2026.07.09
Linux - 04. memory  (0) 2026.07.09
Linux - 03. process  (0) 2026.07.09
Linux - 01. overview  (0) 2026.07.08