UNIX 부팅 흐름과 init 시스템의 동작 원리
UNIX 부팅 과정에서 펌웨어, 부트 로더, 커널, initramfs, init과 systemd가 이어지는 흐름을 정리합니다.
2026-08-14 · 최초 발행 2026-01-16
전원 투입부터 로그인 프롬프트까지
UNIX 계열 시스템은 하드웨어 초기화 뒤 부트 로더를 실행하고, 커널과 초기 사용자 공간을 준비한 다음 PID 1이 서비스들을 올리는 방식으로 부팅을 완료한다. 오늘날 리눅스에서는 systemd가 널리 쓰이지만, 펌웨어에서 커널까지 이어지는 기본 구조와 init의 역할은 시스템 운영에서 그대로 중요하다.
이 흐름은 앞 단계가 성공해야 다음 단계로 넘어가는 순서를 가진다. 문제 발생 시 단일 사용자 모드로 진입할 수 있고, 단계별 구성 요소가 분리되어 있어 부트 로더나 init 시스템을 교체할 수도 있다.
펌웨어가 부팅 대상을 찾는 방식
PC 기반 UNIX 시스템은 BIOS 또는 UEFI에서 출발한다. BIOS는 POST를 수행한 뒤 MBR을 읽어 부트 로더를 실행한다.
POST 수행 → MBR 읽기 → 부트 로더 실행
UEFI는 POST 이후 ESP를 찾고 EFI 애플리케이션을 실행한다.
POST 수행 → ESP 탐색 → EFI 애플리케이션 실행
SPARC 시스템의 Sun/Oracle 환경에서는 OpenBoot가 이 역할을 맡는다. Forth 기반 명령어 인터프리터를 제공하며, ok 프롬프트에서 장치를 제어하고 부팅 장치·파라미터를 설정하거나 하드웨어 진단을 수행할 수 있다.
| 명령어 | 설명 |
|---|---|
| boot | 기본 장치에서 부팅 |
| boot disk0 | 특정 디스크에서 부팅 |
| boot -s | 단일 사용자 모드 |
| probe-scsi | SCSI 장치 탐색 |
| printenv | 환경 변수 출력 |
부트 로더가 커널을 넘겨받기까지
현대 리눅스에서 GRUB는 표준 부트 로더로 사용된다. GRUB2는 펌웨어가 MBR 또는 EFI를 실행한 뒤 boot.img, core.img, 모듈과 설정을 거쳐 커널 및 initrd를 로드한다.
grub.cfg에는 부팅 메뉴와 커널 경로, 루트 파일시스템, initrd 같은 정보가 들어간다.
# /boot/grub/grub.cfg 구조
menuentry 'Linux' {
set root='hd0,msdos1'
linux /vmlinuz root=/dev/sda1 ro quiet
initrd /initrd.img
}
GRUB 셸에서는 장치와 파티션을 확인하는 ls, 변수를 설정·확인하는 set, 커널을 적재하는 linux, initrd를 적재하는 initrd, 부팅을 시작하는 boot를 사용할 수 있다.
LILO는 전통적인 리눅스 부트 로더다. 구조가 단순하고 MBR에 직접 설치되지만, 변경 사항을 반영하려면 재설치가 필요하며 설정 파일은 /etc/lilo.conf다. SPARC용 SILO는 OpenBoot와 연동하고 UFS 및 ext2/3를 지원하며 /etc/silo.conf에서 설정한다.
압축된 커널이 실행 상태가 되는 과정
vmlinuz는 압축된 커널 이미지이며 자체 압축 해제 코드를 포함한다. 형식은 big zImage인 bzImage다. 부트 로더는 이를 메모리에 적재하고 커널 커맨드 라인 파라미터를 넘긴다. 이후 압축 해제와 재배치를 마치면 커널 진입점으로 제어가 이동한다.
커널 커맨드 라인에는 루트 파일시스템과 초기 동작 방식을 지정하는 값이 들어갈 수 있다.
| 파라미터 | 설명 |
|---|---|
| root=/dev/sda1 | 루트 파일시스템 |
| ro | 읽기 전용 마운트 |
| quiet | 부팅 메시지 최소화 |
| single, 1 | 단일 사용자 모드 |
| init=/bin/bash | 대체 init 지정 |
| nomodeset | 커널 모드 설정 비활성화 |
start_kernel()은 아키텍처별 초기화, 메모리 관리, 스케줄러, 타이머와 인터럽트, VFS(Virtual File System), 드라이버 서브시스템을 차례로 준비한다. 이어 루트 파일시스템을 마운트하고 init 프로세스를 실행한다.
실제 루트 파일시스템 전의 임시 환경
initrd는 루트 파일시스템을 마운트하기 전에 필요한 모듈을 제공하고, 하드웨어 감지와 드라이버 로드를 수행할 임시 환경이다. 커널은 initrd를 RAM에 압축 해제해 임시 루트로 마운트하고 /linuxrc 또는 /init을 실행한다. 필요한 모듈과 실제 루트 장치가 준비되면 pivot_root 또는 switch_root로 실제 루트로 전환한다.
initramfs도 같은 시점에 필요한 초기 사용자 공간을 제공하지만, initrd와 구조가 다르다.
| 항목 | initrd | initramfs |
|---|---|---|
| 형식 | 블록 장치 이미지 | cpio 아카이브 |
| 파일시스템 | ext2/cramfs | tmpfs |
| 크기 | 고정 | 동적 |
| 전환 방식 | pivot_root | switch_root |
| 유연성 | 낮음 | 높음 |
배포판별 initramfs 생성 명령은 다음과 같다.
# Debian/Ubuntu
update-initramfs -u -k $(uname -r)
# RHEL/CentOS
dracut -f /boot/initramfs-$(uname -r).img $(uname -r)
일반적인 initramfs에는 셸과 모듈 적재 도구, /proc·/sys·/dev 같은 초기 환경이 포함된다.
/
├── bin/
│ ├── busybox
│ └── sh -> busybox
├── etc/
├── init
├── lib/
│ └── modules/
├── proc/
├── sys/
├── dev/
└── sbin/
└── modprobe
PID 1이 시스템 서비스를 준비하는 방식
커널이 시작하는 첫 사용자 공간 프로세스는 init이며 PID는 1이다. init은 시스템 초기화 스크립트를 실행하고 런레벨을 관리하며, 고아 프로세스를 수용하고 시스템 종료도 처리한다.
전통적인 SysV init은 /etc/inittab과 런레벨을 중심으로 동작한다. 서비스는 /etc/rc.d 스크립트에 따라 순차적으로 시작된다.
/etc/inittab은 기본 런레벨과 각 런레벨에서 실행할 스크립트를 정의한다.
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l3:3:wait:/etc/rc.d/rc 3
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
| 런레벨 | 설명 |
|---|---|
| 0 | 시스템 종료 (halt) |
| 1, S | 단일 사용자 모드 |
| 2 | 다중 사용자 (NFS 없음) |
| 3 | 다중 사용자 (텍스트) |
| 4 | 사용자 정의 |
| 5 | 다중 사용자 (GUI) |
| 6 | 재부팅 |
# 현재 런레벨 확인
runlevel
who -r
# 런레벨 변경
init 3 # 런레벨 3으로 전환
telinit 5 # 런레벨 5로 전환
SysV rc 디렉터리에서는 S로 시작하는 스크립트가 서비스를 시작하고 K로 시작하는 스크립트가 서비스를 종료한다. 뒤의 숫자는 실행 순서이며 값이 낮을수록 먼저 실행된다.
/etc/rc.d/
├── rc.sysinit # 시스템 초기화
├── rc # 런레벨 전환 스크립트
├── rc.local # 로컬 커스텀 스크립트
├── rc0.d/ # 런레벨 0 스크립트
│ ├── K01httpd -> ../init.d/httpd
│ └── K90network -> ../init.d/network
├── rc3.d/ # 런레벨 3 스크립트
│ ├── S10network -> ../init.d/network
│ └── S85httpd -> ../init.d/httpd
└── init.d/ # 서비스 스크립트
├── httpd
└── network
systemd는 의존성을 기준으로 서비스를 올린다
현대 리눅스 배포판의 표준 init 시스템인 systemd는 서비스의 의존성을 기반으로 유닛을 관리한다. 병렬 서비스 시작, 소켓 활성화, cgroup 기반 자원 관리, 저널 로깅을 제공한다.
부팅 시 systemd는 PID 1로 실행되어 default.target을 읽고 의존성을 해결한다. sysinit.target, basic.target을 거쳐 multi-user.target 또는 graphical.target으로 진행하며, 서비스 유닛을 병렬로 시작한다.
| 런레벨 | systemd 타겟 |
|---|---|
| 0 | poweroff.target |
| 1 | rescue.target |
| 2, 3, 4 | multi-user.target |
| 5 | graphical.target |
| 6 | reboot.target |
# 현재 타겟 확인
systemctl get-default
# 기본 타겟 설정
systemctl set-default multi-user.target
# 타겟 전환
systemctl isolate rescue.target
유닛 파일은 배포판 기본 경로인 /lib/systemd/system/, 관리자 설정 경로인 /etc/systemd/system/, 런타임 설정 경로인 /run/systemd/system/에 둘 수 있다.
[Unit]
Description=Apache HTTP Server
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/httpd -k start
ExecReload=/usr/sbin/httpd -k graceful
ExecStop=/usr/sbin/httpd -k stop
[Install]
WantedBy=multi-user.target
서비스 관리와 부팅 분석에는 다음 명령을 사용한다.
# 서비스 관리
systemctl start httpd
systemctl stop httpd
systemctl restart httpd
systemctl status httpd
# 부팅 시 자동 시작
systemctl enable httpd
systemctl disable httpd
# 부팅 분석
systemd-analyze
systemd-analyze blame
systemd-analyze critical-chain
BSD 계열의 rc 기반 초기화
BSD 계열은 런레벨 대신 단일 사용자 모드와 다중 사용자 모드를 사용하며, /etc/rc를 기반으로 초기화를 진행한다. FreeBSD에서는 loader가 /boot/kernel/kernel을 로드한 뒤 init이 /etc/rc와 /etc/rc.d/* 스크립트를 실행해 다중 사용자 모드로 진입한다.
/etc/rc.conf에는 호스트 이름, 네트워크, 서비스 활성화 설정을 둘 수 있다.
# /etc/rc.conf
hostname="freebsd-server"
ifconfig_em0="inet 192.168.1.100 netmask 255.255.255.0"
defaultrouter="192.168.1.1"
sshd_enable="YES"
apache24_enable="YES"
부팅이 멈췄을 때 확인할 지점
커널과 시스템 로그를 보면 실패가 어느 단계에서 일어났는지 확인할 수 있다.
# 커널 메시지
dmesg
cat /var/log/dmesg
# 시스템 로그
journalctl -b # 현재 부팅
journalctl -b -1 # 이전 부팅
journalctl --list-boots # 부팅 목록
GRUB 메뉴에서 e 키를 눌러 linux 줄 끝에 single 또는 1, init=/bin/bash, systemd.unit=rescue.target을 추가하면 단일 사용자 환경, 직접 셸, 복구 타겟으로 부팅할 수 있다. 변경 뒤에는 Ctrl+X 또는 F10으로 부팅한다.
| 문제 | 원인 | 해결 방법 |
|---|---|---|
| Kernel panic | 커널/드라이버 문제 | 이전 커널로 부팅 |
| fsck 실패 | 파일시스템 손상 | 수동 fsck 실행 |
| 서비스 시작 실패 | 설정 오류 | 해당 서비스 점검 |
| 부트 로더 손상 | MBR/EFI 손상 | grub-install 재실행 |