리눅스를 배우기 전에 반드시 짚고 넘어가야 할 질문이 있다. "운영체제(OS)란 도대체 무엇인가?" 우리는 매일 컴퓨터를 켜고 프로그램을 실행하지만, 그 프로그램이 CPU 위에서 어떻게 돌아가고, 메모리는 누가 나눠주며, 디스크에 파일이 어떻게 저장되는지는 거의 의식하지 않는다. 그 모든 보이지 않는 조율을 담당하는 것이 운영체제이고, 리눅스는 그중에서도 서버·임베디드·클라우드의 표준이 된 운영체제다. 리눅스마스터 1급은 단순히 명령어 암기를 요구하지 않는다. "왜 이 명령어가 이렇게 동작하는가"를 커널 수준에서 이해해야 시나리오 문제와 실기를 통과할 수 있다. 오늘은 그 토대인 운영체제의 개념, 커널과 셸의 구조, 그리고 리눅스가 탄생하기까지의 유닉스 계보를 깊이 있게 다룬다.
운영체제를 한 문장으로 정의하면 "하드웨어 자원을 관리하고, 응용 프로그램에게 그 자원을 추상화하여 제공하는 소프트웨어"다. 여기서 핵심 단어는 두 개다. **자원 관리(resource management)**와 추상화(abstraction).
컴퓨터에는 한정된 자원이 있다. CPU는 한 번에 하나의 명령만 실행할 수 있고(코어 단위로), 메모리(RAM)의 용량은 정해져 있으며, 디스크 입출력 속도에도 한계가 있다. 만약 수백 개의 프로그램이 동시에 이 자원을 마구잡이로 요구한다면 시스템은 즉시 마비된다. 운영체제는 이 자원을 시간적·공간적으로 나누어 각 프로그램에 공평하고 효율적으로 배분한다. 이것이 자원 관리다.
운영체제가 관리하는 주요 자원은 다음과 같이 분류된다.
| 자원 | 관리 주체(커널 서브시스템) | 핵심 기능 |
|---|---|---|
| CPU | 프로세스 스케줄러 | 어느 프로세스를 언제 얼마나 실행할지 결정 |
| 메모리 | 메모리 관리자(MMU 활용) | 가상 메모리, 페이징, 스왑 |
| 저장장치 | 파일시스템 / 블록 I/O 계층 | 파일·디렉터리 추상화, 디스크 스케줄링 |
| 입출력 장치 | 디바이스 드라이버 | 키보드·네트워크·디스크 등 하드웨어 제어 |
| 네트워크 | 네트워크 스택(TCP/IP) | 패킷 송수신, 소켓 인터페이스 |
추상화는 더 흥미롭다. 응용 프로그래머는 SSD가 SATA인지 NVMe인지, RAM이 DDR4인지 DDR5인지 알 필요가 없다. 그저 open(), read(), write()라는 표준 인터페이스만 호출하면 운영체제가 알아서 실제 하드웨어를 다룬다. 이렇게 복잡한 하드웨어를 단순한 인터페이스 뒤에 숨기는 것이 추상화의 힘이다.
💡 개념: 운영체제의 4대 핵심 기능은 프로세스 관리, 메모리 관리, 파일 관리, 장치(I/O) 관리다. 여기에 사용자 인터페이스(셸/GUI)와 보안·권한 관리를 더해 6대 기능으로 보기도 한다. 1급 시험에서는 각 기능을 담당하는 커널 서브시스템과 묶어서 묻는 경우가 많다.
운영체제의 심장은 **커널(kernel)**이다. 커널은 하드웨어에 가장 가까이 있으면서 모든 자원에 대한 최종 권한을 갖는 핵심 코드다. 그런데 모든 프로그램이 하드웨어를 직접 건드릴 수 있다면 어떻게 될까? 악의적이거나 버그가 있는 프로그램 하나가 디스크를 통째로 지우거나 다른 프로그램의 메모리를 망가뜨릴 수 있다. 이를 막기 위해 현대 CPU는 **특권 수준(privilege level)**을 하드웨어 차원에서 제공한다.
x86 아키텍처에는 Ring 0부터 Ring 3까지의 보호 링이 있고, 리눅스는 그중 두 개만 사용한다.
사용자 모드의 프로그램이 디스크에 파일을 쓰거나 네트워크로 데이터를 보내려면, 직접 하드웨어를 만질 수 없으므로 커널에게 "대신 해달라"고 요청해야 한다. 이 요청이 바로 **시스템 콜(system call)**이다.
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
운영체제에서 사용자 모드의 프로그램이 디스크 입출력이나 네트워크 통신 같은 특권 작업을 수행하기 위해 커널에 요청하는 메커니즘은 무엇인가?
문제 2
리눅스 커널의 설계 방식과 그 특징에 대한 설명으로 가장 옳은 것은?
문제 3
셸이 사용자가 입력한 명령어 `ls`를 실행할 때 거치는 유닉스의 표준 프로세스 생성 모델 순서로 옳은 것은?
문제 4
다음 중 리눅스의 기본 로그인 셸이며 그 이름이 "Bourne Again Shell"의 약자인 것은?
문제 5
"모든 것은 파일이다(Everything is a file)"라는 유닉스 철학에 대한 설명으로 옳지 않은 것은?
문제 6
리눅스의 역사에 대한 설명으로 옳은 것은?
# strace로 프로그램이 호출하는 시스템 콜을 직접 관찰해보자
strace -c ls /tmp
# write, read, openat, close, mmap 등 시스템 콜 통계가 출력된다위 명령을 실행하면 ls 같은 단순한 명령어조차 수십 개의 시스템 콜(openat, read, write, close, stat 등)을 호출한다는 것을 확인할 수 있다. 사용자 모드에서 커널 모드로 전환되는 이 순간을 모드 전환(mode switch) 또는 컨텍스트 전환의 일종으로 부르며, 약간의 오버헤드가 발생한다.
🔍 더 깊이: 시스템 콜은 단순한 함수 호출이 아니다. CPU가 특권 수준을 Ring 3에서 Ring 0으로 올리는 하드웨어 이벤트다. 과거에는
int 0x80소프트웨어 인터럽트를 사용했지만, 현대 x86-64 리눅스는 더 빠른syscall명령어를 사용한다. 이 전환 비용 때문에 고성능 프로그램은 시스템 콜 횟수를 줄이려고 버퍼링을 활용한다.
커널을 설계하는 방식에는 크게 두 철학이 있고, 이는 1급 시험에 자주 출제된다.
**모놀리식 커널(Monolithic Kernel)**은 파일시스템, 디바이스 드라이버, 네트워크 스택, 스케줄러 등 거의 모든 핵심 기능을 하나의 커널 공간(단일 주소 공간)에 넣는다. 함수 호출만으로 서브시스템 간 통신이 이루어지므로 빠르지만, 한 부분의 버그가 전체 커널을 죽일 수 있고 코드가 거대해진다. 리눅스는 모놀리식 커널이다.
**마이크로커널(Microkernel)**은 커널을 최소한(프로세스 간 통신, 기본 스케줄링, 메모리 관리)으로 줄이고, 파일시스템·드라이버 등은 사용자 공간의 별도 서비스로 분리한다. 안정성·모듈성은 높지만 서비스 간 메시지 전달(IPC) 오버헤드로 느릴 수 있다. 대표 예가 미닉스(MINIX)와 GNU Hurd다.
리눅스는 모놀리식이지만 **적재 가능한 커널 모듈(LKM, Loadable Kernel Module)**을 지원해 마이크로커널의 장점인 모듈성을 일부 흡수했다. 드라이버를 커널을 재컴파일하지 않고도 동적으로 넣고 뺄 수 있다.
lsmod # 현재 적재된 커널 모듈 목록
modinfo e1000 # 특정 모듈의 정보 확인
sudo modprobe vfat # 모듈 적재(의존성 자동 해결)
sudo rmmod vfat # 모듈 제거
uname -r # 실행 중인 커널 버전 확인📚 유래/사례: 1992년, 미닉스의 저자 앤드루 타넨바움 교수와 리누스 토르발스 사이에 "모놀리식 커널은 구식이다 vs 마이크로커널은 너무 느리다"를 둘러싼 유명한 논쟁(Tanenbaum–Torvalds debate)이 Usenet에서 벌어졌다. 타넨바움은 "리눅스는 구식 설계"라고 비판했지만, 결과적으로 모놀리식 리눅스가 세상을 지배했다. 실용성이 학문적 우아함을 이긴 사례로 자주 인용된다.
커널이 시스템의 심장이라면, **셸(shell)**은 사용자가 커널과 대화하는 통역사이자 명령어 해석기(command interpreter)다. 사용자가 ls -l이라고 입력하면, 셸이 이를 해석하여 적절한 프로그램을 찾아 실행하고, 결과를 다시 사용자에게 보여준다. 셸이라는 이름은 커널을 "껍질(shell)"처럼 감싸고 있다는 데서 유래했다.
리눅스에는 여러 셸이 있으며, 각각의 계보와 특징을 아는 것이 중요하다.
| 셸 | 개발자/유래 | 특징 |
|---|---|---|
| sh (Bourne Shell) | Stephen Bourne (1977) | 최초의 유닉스 표준 셸, 스크립트의 원형 |
| csh (C Shell) | Bill Joy | C 언어 문법 차용, 히스토리·별칭 도입 |
| ksh (Korn Shell) | David Korn | sh 호환 + csh 기능 통합 |
| bash (Bourne Again Shell) | Brian Fox (GNU) | sh의 확장판, 리눅스 기본 셸 |
| zsh | Paul Falstad | bash 호환 + 강력한 자동완성 |
| tcsh | csh 확장 | csh + 명령행 편집 |
리눅스의 기본 셸은 거의 항상 bash다. 이름이 "Bourne Again Shell"인 것은 원조 Bourne Shell을 "다시 태어나게" 했다는 GNU 특유의 말장난이다.
echo $SHELL # 현재 로그인 셸 확인
cat /etc/shells # 시스템에 등록된 사용 가능한 셸 목록
chsh -s /bin/zsh # 로그인 셸을 zsh로 변경 (/etc/passwd 갱신)
echo $0 # 현재 실행 중인 셸 이름사용자별 기본 셸은 /etc/passwd 파일의 마지막 필드에 기록된다. 예를 들어 user:x:1000:1000:User:/home/user:/bin/bash에서 맨 끝의 /bin/bash가 그 사용자의 로그인 셸이다.
⚠️ 함정: 시험에서 "기본 셸을 변경하는 명령"으로
chsh를 묻는데, 이때 변경된 셸은/etc/shells에 등록된 셸이어야 한다. 또한chsh는 즉시 적용되지 않고 다음 로그인부터 반영된다. 현재 세션에서 즉시 다른 셸을 쓰려면 그냥 셸 이름(zsh)을 입력해 하위 셸을 실행하면 된다.
셸이 명령어를 실행하는 내부 과정은 운영체제의 프로세스 생성 메커니즘을 그대로 보여준다. 사용자가 ls를 입력하면 셸은 다음 단계를 거친다.
*)·변수($HOME)·따옴표를 확장한다.execve() 시스템 콜로 자신의 메모리 이미지를 ls 프로그램으로 교체한다.이 fork-exec-wait 모델은 유닉스의 가장 우아한 설계 중 하나다. "복제 후 교체"라는 단순한 두 단계로 모든 프로그램 실행이 이루어진다.
🔍 더 깊이: 명령어 뒤에
&를 붙이면(sleep 100 &) 셸이wait()를 하지 않고 즉시 프롬프트를 돌려준다. 이것이 백그라운드 실행이다. 반대로wait를 하는 동안 부모가 죽으면 자식은 **고아 프로세스(orphan)**가 되어 init(PID 1)에게 입양된다. 자식이 죽었는데 부모가 종료 상태를 회수하지 않으면 **좀비 프로세스(zombie)**가 된다.
리눅스를 이해하려면 그 조상인 유닉스를 알아야 한다. 1969년 미국 벨 연구소(Bell Labs)에서 켄 톰슨(Ken Thompson)과 데니스 리치(Dennis Ritchie)가 PDP-7이라는 미니컴퓨터에서 유닉스를 만들었다. 처음에는 어셈블리로 작성되었지만, 1973년 데니스 리치가 만든 C 언어로 유닉스를 다시 작성하면서 혁명이 일어났다. 운영체제를 고급 언어로 작성하니 다른 하드웨어로 이식(porting)이 쉬워졌고, 유닉스는 빠르게 여러 기종으로 퍼졌다.
유닉스가 후대에 남긴 가장 큰 유산은 코드가 아니라 철학이다.
이 철학은 명령행에서 그대로 드러난다.
# 작은 도구들을 파이프(|)로 연결해 복잡한 작업을 수행
cat /etc/passwd | grep "/bin/bash" | wc -l
# passwd 출력 → bash 셸 사용자만 필터 → 줄 수 세기각 도구(cat, grep, wc)는 한 가지 일만 하지만, 파이프로 엮으면 "bash 셸을 쓰는 사용자 수 세기"라는 새로운 작업이 만들어진다. 이것이 유닉스 철학의 정수다.
📚 유래/사례: 유닉스(UNIX)라는 이름은 그 전신인 MULTICS(Multiplexed Information and Computing Service)를 비꼰 말장난이다. MULTICS가 너무 복잡하고 거대했던 데 대한 반작용으로, 단순함을 추구한다는 의미에서 "UNICS(Uniplexed)"라 불렀고 이것이 UNIX가 되었다. 단순함을 향한 의지가 이름에 새겨진 것이다.
1980년대, 유닉스는 상업화되어 비싸졌고 소스 코드는 닫혔다. 이에 리처드 스톨먼(Richard Stallman)은 1983년 GNU 프로젝트를 시작해 자유로운 유닉스 호환 운영체제를 만들고자 했다. GNU는 컴파일러(gcc), 셸(bash), 핵심 유틸리티(coreutils) 등 운영체제의 거의 모든 부품을 완성했지만, 정작 심장인 **커널(GNU Hurd)**은 마이크로커널 설계의 복잡함 때문에 좀처럼 완성되지 못했다.
바로 이 빈자리를 채운 것이 리누스 토르발스(Linus Torvalds)였다. 1991년, 핀란드 헬싱키 대학의 21세 학생이던 그는 학습용 운영체제 미닉스에 만족하지 못하고 자신만의 커널을 취미로 만들기 시작했다. 그가 8월 25일 comp.os.minix 뉴스그룹에 올린 글은 전설이 되었다.
"Hello everybody out there ... I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu) ..."
"거대하거나 전문적이지 않을 것"이라던 이 취미 프로젝트가 결국 세상에서 가장 널리 쓰이는 운영체제 커널이 되었다. 리누스의 커널과 GNU의 도구들이 결합하여 GNU/Linux가 탄생했다. 이 때문에 스톨먼은 "리눅스"가 아니라 "GNU/Linux"라 불러야 한다고 주장한다. 커널만 리누스의 것이고 나머지 시스템 도구 대부분은 GNU의 산물이기 때문이다.
💡 개념: 엄밀히 말하면 "리눅스"는 커널만을 가리킨다. 우리가 설치해서 쓰는 우분투·CentOS 같은 것은 리눅스 커널 + GNU 도구 + 패키지 관리자 + 응용 프로그램을 묶은 **배포판(distribution)**이다. 시험에서 "리눅스는 ( )이다"라는 빈칸에는 "커널"이 정답인 경우가 많다.
리누스가 1991년 리눅스를 처음 GPL이 아닌 자체 라이선스로 배포했다가, 1992년 버전 0.99부터 **GPL(GNU General Public License)**로 전환한 것도 중요한 역사적 사실이다. 이 GPL 채택이 전 세계 개발자들의 참여를 폭발적으로 끌어냈고, 오늘날의 리눅스를 만들었다. 라이선스에 대한 자세한 내용은 Day 2에서 다룬다.
오늘 우리는 리눅스를 떠받치는 가장 근본적인 토대를 살펴봤다. 운영체제는 하드웨어 자원을 관리하고 추상화하는 소프트웨어이며, 그 심장인 커널은 특권 모드에서 동작하고, 사용자 프로그램은 시스템 콜을 통해서만 커널에 자원을 요청한다. 리눅스는 모놀리식 커널이면서도 모듈을 동적으로 적재할 수 있고, 셸은 fork-exec-wait 모델로 명령어를 실행한다. 그리고 이 모든 것의 뿌리에는 단순함을 추구한 유닉스 철학과, GNU의 도구들 위에 리누스의 커널이 결합한 역사가 있다. 다음 시간에는 리눅스를 자유롭게 만든 라이선스와, 그 결과 갈라진 배포판 계열들을 살펴본다.