"OS랑 커널이랑 같은 거 아니야?"
저도 처음엔 같은 말인 줄 알았습니다. 리눅스 서버를 처음 만졌을 때, "리눅스 커널 업데이트"라는 말이 따로 있더군요. 그럼 리눅스 OS 업데이트랑은 뭐가 다른 걸까요? 둘 다 리눅스인데?
이게 와닿지 않아서 하루 종일 삽질하다가, 문득 이렇게 이해했습니다.
비유하자면,
- OS: 자동차 전체 (엔진 + 핸들 + 바퀴 + 에어컨 + 오디오)
- 커널: 엔진 그 자체
에어컨(유틸리티 프로그램)이 고장 나도 차는 굴러가지만, 엔진(커널)이 멈추면 차는 그냥 고철입니다. 컴퓨터가 켜져 있는 동안, 단 한순간도 쉬지 않고 메모리에 상주하는 핵심 프로그램, 그게 바로 커널입니다.
결국, 리눅스에서 "OS 업데이트"는 쉘, 파일 매니저, GUI 같은 주변 도구를 업데이트하는 것이고, "커널 업데이트"는 엔진 자체를 새 모델로 바꾸는 것이라고 받아들였습니다.
커널 버전 확인하는 법 - 처음엔 막막했는데
처음 서버 접속했을 때 "커널 버전이 뭐냐?"고 물어보는 사람이 있었습니다. 저는 당연히 몰랐죠. 어디서 확인하는 건데?
그냥 터미널에서 이렇게 하면 됩니다.
uname -r
# 출력 예시: 5.15.0-56-generic
이 숫자가 커널의 버전 번호입니다.
5: 메이저 버전15: 마이너 버전0-56-generic: 패치 레벨 + 배포판별 추가 정보
macOS에서 해보니까 Darwin Kernel Version 23.3.0이라고 나오더군요.
macOS도 결국 Unix 기반이라 커널이 따로 있는 겁니다.
이걸 알고 나서는 서버 문서에 "Kernel Version: ..." 항목을 넣는 게 왜 필요한지 이해했습니다.
커널이 하는 일 - 보안관 역할
커널의 가장 중요한 임무는 "하드웨어 보호"입니다. 아무 프로그램이나 하드디스크에 막 접근해서 중요 문서를 지워버리면 안 되니까요.
받아들인 바로는, 커널은 이런 3가지 일을 합니다.
- 메모리 관리: "A 프로그램은 100번지부터 200번지까지만 써. 넘어가면 죽여."
- 프로세스 관리: "B 프로그램, 너는 0.1초만 실행하고 비켜. C 프로그램 차례야."
- 장치 드라이버 중개: 마우스, 키보드, 네트워크 카드와 대화하기.
만약 이게 없다면? 프로그램끼리 메모리 싸움이 벌어지고, CPU는 하나의 프로그램이 독점하고, 하드웨어는 무질서하게 접근당할 겁니다. 커널은 경찰관 겸 중재자입니다.
커널 공간 vs 유저 공간 - Ring 0과 Ring 3
처음 듣는 용어가 또 나왔습니다. "커널 공간(Kernel Space)"과 "유저 공간(User Space)".
이건 CPU가 메모리를 나누는 방식입니다.
- Ring 0 (커널 공간): 커널이 실행되는 영역. 하드웨어에 직접 접근 가능. 무한 권력.
- Ring 3 (유저 공간): 일반 프로그램이 실행되는 영역. 하드웨어에 직접 접근 불가. 제한된 권한.
예를 들어, 크롬 브라우저(Ring 3)가 파일을 읽고 싶으면, 커널(Ring 0)에게 부탁해야 합니다. 이 부탁하는 방법이 시스템 콜(System Call)입니다.
비유하자면,
- Ring 0 (커널): 대통령. 모든 권한 가능.
- Ring 3 (유저 프로그램): 일반 시민. 대통령에게 청원해야 함.
이걸 이해하고 나니, "왜 프로그램이 직접 하드웨어를 못 건드리냐?"라는 질문의 답이 선명해졌습니다. CPU가 애초에 권한을 나눠놓은 겁니다.
시스템 콜 - 유저와 커널의 다리
예를 들어, Python에서 파일을 열 때 이렇게 씁니다.
file = open("data.txt", "r")
이 한 줄 뒤에서는 대략 이런 일이 벌어집니다.
- Python 인터프리터가
open()함수를 호출. - 내부적으로 C 라이브러리의
fopen()호출. fopen()은 다시 시스템 콜open()을 호출. (Ring 3 → Ring 0으로 전환)- 커널이 파일 시스템에 접근해서 파일을 열고, 파일 디스크립터 반환.
- Python이 파일 디스크립터를 받아서 계속 작업.
시스템 콜은 유저 공간과 커널 공간을 이어주는 유일한 다리입니다.
리눅스에는 약 300개 이상의 시스템 콜이 있습니다: read(), write(), fork(), exec(), socket() 등등.
이게 결국 "프로그램은 커널 없이 아무것도 못한다"는 말의 의미였습니다.
모놀리식 vs 마이크로 커널 - 설계 철학의 차이
커널을 어떻게 설계하느냐에 따라 크게 두 파벌로 나뉩니다.
1. 모놀리식 커널 (Monolithic Kernel)
철학: "다 귀찮다, 한 방에 넣자."
핵심 기능뿐만 아니라 디바이스 드라이버, 파일 시스템, 네트워크 스택까지 싹 다 커널 안에 집어넣음.
장점:
- 빠름: 함수 호출만 하면 됨. 별도의 프로세스 간 통신(IPC) 없음.
- 효율적: 메모리 복사, 컨텍스트 스위칭 없음.
단점:
- 불안정: 드라이버 하나만 버그가 나도 커널 전체가 뻗음 (Kernel Panic).
- 덩치가 큼: 리눅스 커널은 수천만 줄의 코드.
대표주자: 리눅스 (Linux), 전통적인 Unix.
처음엔 "왜 이렇게 불안정한 구조를 쓸까?"라고 생각했는데, 서버 환경에서는 속도가 생명이더군요. 그래서 모놀리식 구조가 압도적입니다.
2. 마이크로 커널 (Micro Kernel)
철학: "핵심만 남기고 다 밖으로 빼!"
메모리 관리, 스케줄링, IPC(프로세스 간 통신) 같은 진짜 필수 기능만 커널에 남기고, 나머지(드라이버, 파일 시스템)는 일반 프로그램(유저 공간의 서버 프로세스)처럼 돌림.
장점:
- 안정적: 드라이버가 죽어도 커널은 살아있음.
- 가벼움: 커널 코드가 작음 (수만 줄).
- 보안: 각 모듈이 격리되어 있어 침투하기 어려움.
단점:
- 느림: 모듈끼리 메시지를 주고받아야 해서 오버헤드 발생.
- 복잡함: 모듈 간 통신 설계가 어려움.
대표주자: Mach (macOS의 기반), Minix, QNX.
저는 macOS를 쓰는데, "왜 macOS는 리눅스보다 안정적인 느낌이지?"라는 의문이 있었습니다. 마이크로 커널 기반(정확히는 하이브리드)이라는 걸 알고 나서 이해했습니다.
하이브리드 커널 - 둘 다 섞어보자
현대의 OS들은 순수 모놀리식도, 순수 마이크로도 아닙니다.
- Windows NT: 마이크로 커널처럼 설계했지만, 성능을 위해 드라이버를 커널 공간으로 옮김.
- macOS XNU: Mach 마이크로 커널 + BSD 모놀리식 커널을 섞음.
결국 "성능 vs 안정성"의 타협점을 찾은 겁니다.
Tanenbaum-Torvalds 논쟁 - 1992년의 대혼돈
리눅스를 만든 Linus Torvalds와 Minix(마이크로 커널)를 만든 Andrew Tanenbaum이 1992년에 Usenet에서 개싸움(?)을 벌였습니다.
Tanenbaum: "모놀리식 커널은 시대착오적이다. 마이크로 커널이 미래다." Torvalds: "마이크로 커널은 느리다. 실용성이 답이다."
결과는?
- 리눅스(모놀리식)가 서버 시장 장악.
- Minix(마이크로)는 학술용으로만 쓰임.
하지만 아이러니하게도, Tanenbaum의 아이디어는 macOS, QNX(자동차), Fuchsia(구글) 같은 곳에서 살아남았습니다. 결국 이거였습니다: 둘 다 맞다. 용도에 따라 다르다.
커널 모듈 - 필요할 때만 끼워넣기
모놀리식 커널의 문제는 "덩치가 너무 크다"였습니다. 하지만 리눅스는 Loadable Kernel Module (LKM)이라는 기법으로 이걸 해결했습니다.
USB 드라이버, 그래픽 카드 드라이버 같은 건 필요할 때만 커널에 동적으로 끼워넣습니다.
lsmod # 현재 로드된 커널 모듈 목록 보기
출력 예시:
Module Size Used by
nvidia_drm 102400 5
nvidia_modeset 1245184 12 nvidia_drm
nvidia 56385536 573 nvidia_modeset
NVIDIA 그래픽 카드를 쓰면, nvidia 모듈이 자동으로 로드됩니다.
필요 없으면 언로드할 수도 있습니다.
sudo rmmod nvidia # 모듈 제거
sudo insmod nvidia.ko # 모듈 추가
처음엔 "커널 모듈을 잘못 건드리면 시스템이 뻗는다"는 말이 무서웠는데, 직접 해보니 정말 뻗더군요. 그 후로는 함부로 건드리지 않습니다.
/proc 파일 시스템 - 커널 정보 엿보기
리눅스에는 신기한 디렉토리가 하나 있습니다. /proc.
cat /proc/cpuinfo # CPU 정보
cat /proc/meminfo # 메모리 정보
cat /proc/version # 커널 버전
이 디렉토리는 실제 디스크에 존재하지 않습니다. 커널이 실시간으로 생성하는 가상 파일 시스템입니다.
예를 들어, CPU 정보를 보려면:
cat /proc/cpuinfo
출력:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 142
model name : Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
이걸 알고 나서는 서버 모니터링 스크립트에서 /proc/meminfo를 파싱해서 메모리 사용량을 체크하는 이유를 이해했습니다.
커널 패닉 vs 블루스크린 - 커널이 죽는 순간
커널이 죽으면 컴퓨터가 멈춥니다. 왜냐하면 커널은 모든 걸 관리하니까요.
- 리눅스: Kernel Panic
- Windows: Blue Screen of Death (BSOD)
- macOS: Kernel Panic (재부팅 화면)
처음 서버에서 Kernel Panic을 봤을 때, 로그에 이런 게 찍혀 있었습니다.
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
대략 이런 의미였습니다: "루트 파일 시스템을 못 찾았어. 나 죽는다."
이 경험 이후로, "커널은 신"이라는 말을 받아들였습니다. 커널이 죽으면 그냥 끝입니다.
dmesg: 커널이 뭐라고 떠드는지 듣기
커널은 부팅할 때, 그리고 하드웨어가 연결될 때마다 뭔가를 로그로 남깁니다.
이걸 보는 명령어가 dmesg입니다.
dmesg | tail -20 # 최근 20줄 보기
출력 예시:
[ 1.234567] usb 1-1: New USB device found, idVendor=046d, idProduct=c52b
[ 1.234568] input: Logitech USB Receiver as /devices/pci0000:00/usb1/1-1/input0
[ 10.567890] EXT4-fs (sda1): mounted filesystem with ordered data mode
USB 마우스를 꽂으면 dmesg에 바로 뜹니다.
처음엔 이게 왜 필요한지 몰랐는데, 하드웨어 문제를 디버깅할 때 정말 유용하더군요.
Docker와 커널 공유 - 컨테이너의 비밀
Docker를 처음 쓸 때, "가상머신이랑 뭐가 다른가?"라는 질문이 있었습니다.
핵심 차이는 커널입니다.
- 가상머신 (VM): 게스트 OS가 자기만의 커널을 가짐.
- Docker 컨테이너: 호스트 OS의 커널을 공유함.
예를 들어, macOS에서 Linux Docker 컨테이너를 돌리면?
- macOS는 Linux 커널이 아님 (XNU 커널).
- Docker는 뒤에서 경량 Linux VM을 돌림.
이게 와닿았던 순간이, "왜 Docker에서 uname -r을 치면 호스트 커널 버전이 나오지?"라는 의문을 풀었을 때였습니다.
# 호스트에서
uname -r
# 5.15.0-56-generic
# Docker 컨테이너 안에서
docker run -it ubuntu bash
uname -r
# 5.15.0-56-generic (똑같음!)
컨테이너는 커널을 공유하기 때문에 가볍고 빠릅니다. 하지만 보안 측면에서는 VM보다 약합니다. (커널을 뚫으면 호스트도 뚫림)
eBPF: 커널을 건드리지 않고 확장하기
최근에 알게 된 신기술이 eBPF (extended Berkeley Packet Filter)입니다.
전통적으로 커널을 확장하려면 커널 모듈을 작성해야 했습니다. 하지만 커널 모듈은 위험합니다. 버그가 있으면 시스템 전체가 뻗으니까요.
eBPF는 커널 안에 안전한 샌드박스 프로그램을 삽입할 수 있게 해줍니다.
예를 들어:
- 네트워크 패킷을 필터링 (방화벽 역할)
- 시스템 콜 추적 (모니터링)
- 성능 프로파일링
# eBPF로 시스템 콜 추적하기 (bpftrace 사용)
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s opened %s\n", comm, str(args->filename)); }'
이걸 실행하면, 모든 프로그램이 어떤 파일을 여는지 실시간으로 볼 수 있습니다.
eBPF는 Kubernetes 네트워킹 (Cilium), 보안 도구 (Falco), 모니터링 (Pixie)에서 쓰입니다. "커널을 커널 모듈 없이 확장한다"는 발상이 너무 신박해서 깊게 파보고 싶습니다.
왜 리눅스가 서버를 지배할까?
리눅스는 모놀리식 커널입니다. 서버는 다음과 같은 특징이 있습니다.
- 하드웨어 스펙이 정해져 있음: 갑자기 USB를 꽂거나 빼지 않음.
- 최고 성능(속도)이 중요: 1ms의 레이턴시도 매출에 영향.
- 안정성은 모니터링으로 커버: 크래시 나면 자동 재시작.
그래서 좀 무겁고 관리하기 힘들더라도, 퍼포먼스가 깡패인 모놀리식 구조의 리눅스가 서버 시장을 장악한 것입니다.
AWS, Google Cloud, Azure의 99% 이상이 리눅스 커널 위에서 돌아갑니다.
정리해본다
처음엔 "OS랑 커널이랑 뭐가 다르냐?"는 질문에서 시작했습니다. 지금은 이렇게 정리해봅니다.
- 커널은 OS의 알맹이이자 하드웨어의 절대 권력자다.
- Ring 0 (커널 공간)과 Ring 3 (유저 공간)은 CPU가 나눈 신분제다.
- 시스템 콜은 유저 프로그램이 커널에게 부탁하는 유일한 방법이다.
- 모놀리식 커널은 빠르지만 불안정, 마이크로 커널은 안정적이지만 느림. 현대는 둘을 섞은 하이브리드.
- 리눅스가 서버를 지배하는 이유는 속도 때문이다.
- Docker는 호스트 커널을 공유해서 가볍고, eBPF는 커널을 안전하게 확장한다.
결국 이거였습니다: 커널은 컴퓨터의 엔진이다. 엔진이 멈추면 차는 고철이다.