커널(kernel)은 가장 안쪽에서 하드웨어를 직접 통제하는 핵심 코드다. CPU 시간 배분(스케줄링), 메모리 할당, 파일 시스템·네트워크·장치 관리를 맡는다.
셸·명령·응용 프로그램은 모두 커널 위에서 돌며, 시스템 콜로 요청을 보내 하드웨어와 간접적으로 대화한다.
새 USB 장치를 꽂으면 해당 드라이버 모듈이 자동 적재되고 안 쓰면 내릴 수 있다 → 커널 전체를 다시 컴파일하지 않고 기능을 동적으로 확장한다.
커널 자체는 부팅 시 메모리로 올라오는 압축된 단일 이미지 파일이며 보통 /boot 아래에 있다.
uname -r # 현재 실행 중인 커널 버전(예: 5.14.0-70.el9.x86_64)uname -a # 커널·호스트명·아키텍처 전체 정보ls /boot # vmlinuz-*, initramfs-*, config-* 등
파일/경로
의미
/boot/vmlinuz-버전
압축된 커널 이미지(부팅 시 적재)
/boot/initramfs-버전.img
초기 램디스크(부팅 초반 드라이버)
/boot/config-버전
그 커널을 만들 때의 빌드 설정
/lib/modules/버전/
그 커널용 모듈(.ko)들이 사는 곳
/proc/sys/
커널 파라미터를 실시간 조회·수정
vmlinuz의 z는 압축(zipped)을 뜻한다 — 부팅 시 메모리로 풀리는 압축 커널 이미지다. 모듈은 /lib/modules/$(uname -r)/ 아래에 커널 버전별로 분리 보관된다. 이 디렉터리 구조 때문에 여러 커널 버전을 동시에 설치해도 모듈이 섞이지 않는다. uname -r이 가리키는 버전이 곧 현재 모듈 디렉터리 이름이다.
커널 파라미터는 /proc/sys/(읽기·쓰기 가능한 가상 파일)와 sysctl 명령으로 실시간 조정된다. 예컨대 sysctl net.ipv4.ip_forward로 IP 포워딩 상태를 보고 sysctl -w net.ipv4.ip_forward=1로 켤 수 있다. 영구 적용은 /etc/sysctl.conf에 적는다. 이는 "커널을 다시 빌드하지 않고 동작을 바꾸는" 또 다른 방법이다.
lsmod # 현재 적재된 모든 모듈 목록(+사용 횟수, 의존 모듈)modinfo e1000 # 특정 모듈의 상세 정보(설명, 의존성, 파라미터)modinfo -d e1000 # 모듈 설명만
lsmod의 출력은 세 열이다.
Module Size Used by
e1000 159744 0
bluetooth 806912 9 btusb,...
열
의미
Module
모듈 이름
Size
메모리 점유 크기
Used by
사용 횟수 + 이 모듈에 의존하는 다른 모듈
lsmod의 "Used by" 숫자가 0보다 크면 다른 무언가가 그 모듈을 쓰고 있다는 뜻이라 함부로 내릴 수 없다. 옆에 의존 모듈 이름까지 적혀 있다. lsmod는 사실 /proc/modules를 보기 좋게 정리해 보여주는 것이다. modinfo는 모듈 파일 자체에서 메타데이터(저자, 라이선스, 파라미터, 의존성)를 읽어온다.
modinfo로 보면 그 모듈이 받는 파라미터를 알 수 있다(parm: 줄). 모듈을 올릴 때 modprobe 모듈 파라미터=값으로 동작을 조정할 수 있고, 부팅 시 자동 적용하려면 /etc/modprobe.d/*.conf에 options 모듈 파라미터=값을 적는다. 또 특정 모듈이 자동 적재되지 않게 막으려면 같은 디렉터리에 blacklist 모듈명을 쓴다.
insmod와 modprobe의 가장 큰 차이는 의존성 자동 해결이다. insmod는 지정한 .ko 하나만 올리므로, 그 모듈이 다른 모듈을 필요로 하면 "Unknown symbol" 같은 오류로 실패한다. modprobe는 /lib/modules/.../modules.dep(의존성 지도)를 참고해 필요한 모듈을 먼저 올린 뒤 대상을 적재한다. 게다가 insmod는 전체 경로를 줘야 하지만 modprobe는 이름만 주면 된다. 그래서 실무·시험 모두 modprobe가 정답인 경우가 대부분이다.
modprobe가 참고하는 modules.dep는 depmod 명령이 생성한다. 새 모듈을 /lib/modules/.../에 넣은 뒤 depmod -a를 실행해야 의존성 지도가 갱신되어 modprobe가 그 모듈을 찾을 수 있다. 커널 모듈을 직접 빌드해 추가할 때 이 단계를 빠뜨리면 modprobe가 "module not found"를 낸다.
⚠️ 함정: rmmod로 모듈을 내리려는데 "Module is in use"로 실패하는 일이 잦다. lsmod의 "Used by"가 0이 아니기 때문이다. 강제로 내리려는 rmmod -f는 위험해 권장되지 않는다. 정석은 그 모듈에 의존하는 상위 모듈을 먼저 내리거나, modprobe -r로 의존성을 고려해 한꺼번에 제거하는 것이다.
# 직접 쳐보기 — 모듈 관찰 (안전: 조회 위주)lsmod | head # 적재된 모듈들lsmod | wc -l # 모듈 개수modinfo loop # loop 모듈 정보cat /proc/modules | head # lsmod의 원본ls /lib/modules/$(uname -r)/kernel | head # 모듈 트리
새 하드웨어 지원, 기능 최적화, 패치 적용 등을 위해 커널 소스를 직접 컴파일하기도 한다.
어제 배운 소스 컴파일과 닮았지만 설정(config) 단계가 핵심이라는 점이 다르다.
cd /usr/src/linux-버전 # 커널 소스 디렉터리make menuconfig # 메뉴 기반 커널 설정(.config 생성)make # 커널 이미지 + 모듈 컴파일make modules_install # 컴파일된 모듈을 /lib/modules/로 설치make install # 커널 이미지를 /boot에 설치 + 부트로더 갱신
단계
명령
하는 일
1. 설정
make menuconfig
어떤 기능·드라이버를 포함/모듈화/제외할지 선택 → .config
2. 빌드
make
커널 이미지(vmlinuz)와 모듈(.ko) 컴파일
3. 모듈 설치
make modules_install
모듈을 /lib/modules/버전/에 복사
4. 커널 설치
make install
vmlinuz·initramfs를 /boot에 두고 부트로더(GRUB) 갱신
커널 설정 단계에서 각 기능은 세 상태 중 하나로 정해진다 — *(내장: 커널에 포함), M(모듈: 별도 .ko로 빌드해 필요 시 적재), 빈칸(제외). 자주 쓰는 핵심 기능은 내장(*)으로, 가끔 쓰는 장치 드라이버는 모듈(M)로 두는 것이 정석이다. 모듈로 두면 커널 이미지가 작아지고 메모리도 아낀다. 이 선택이 곧 make modules_install로 설치될 모듈 목록을 결정한다.
설정 도구는 여러 가지다. make config(질문을 순서대로 묻는 원시적 방식), make menuconfig(텍스트 메뉴, ncurses 기반, 가장 흔함), make xconfig(X 윈도 GUI), make oldconfig(기존 .config를 새 커널에 맞춰 바뀐 항목만 질문). 보통 현재 커널의 /boot/config-$(uname -r)를 .config로 복사한 뒤 make oldconfig로 시작하면 안전하다.
⚠️ 함정: 단계 순서를 바꾸면 안 된다. make(빌드)가 끝나야 모듈과 이미지가 생기므로 make modules_install·make install은 그 뒤에 온다. 또 make modules_install(모듈을 /lib/modules로)과 make install(커널을 /boot로 + GRUB 갱신)은 목적지가 다른 별개 단계다. 둘을 하나로 혼동하는 보기가 시험에 나온다. 새 커널 설치 후에는 부트로더 메뉴에서 새 커널을 선택해 부팅해야 적용된다.
리누스 토르발스가 1991년 처음 공개한 커널은 모듈 개념이 없는 순수 모놀리식이었다 — 새 장치를 지원하려면 커널 전체를 다시 컴파일해야 했다. 1995년경 적재 가능 커널 모듈(LKM)이 도입되면서, 부팅된 커널에 드라이버를 동적으로 끼우고 빼는 일이 가능해졌다. 오늘날 USB를 꽂으면 즉시 인식되는 것, 배포판이 수천 종의 하드웨어를 하나의 커널로 지원하는 것 모두 이 모듈 구조 덕분이다. 모놀리식의 성능과 마이크로커널의 유연성을 절충한 "모듈식 모놀리식"이 리눅스의 설계 철학이다.