
WSL(Windows Subsystem for Linux): 윈도우의 역습
개발자는 무조건 맥(Mac)을 써야 한다? 그건 WSL2가 나오기 전 이야기입니다. 윈도우 안에 리눅스 커널 심기.

개발자는 무조건 맥(Mac)을 써야 한다? 그건 WSL2가 나오기 전 이야기입니다. 윈도우 안에 리눅스 커널 심기.
내 서버는 왜 걸핏하면 뻗을까? OS가 한정된 메모리를 쪼개 쓰는 처절한 사투. 단편화(Fragmentation)와의 전쟁.

미로를 탈출하는 두 가지 방법. 넓게 퍼져나갈 것인가(BFS), 한 우물만 팔 것인가(DFS). 최단 경로는 누가 찾을까?

이름부터 빠릅니다. 피벗(Pivot)을 기준으로 나누고 또 나누는 분할 정복 알고리즘. 왜 최악엔 느린데도 가장 많이 쓰일까요?

매번 3-Way Handshake 하느라 지쳤나요? 한 번 맺은 인연(TCP 연결)을 소중히 유지하는 법. HTTP 최적화의 기본.

제가 처음 프로그래밍을 배우던 2015년, 주변 선배들은 하나같이 맥북을 들고 다녔습니다. 저는 당시 대학 신입생이었고, 돈이 없어서 중고로 산 삼성 노트북을 썼습니다. 스타벅스에서 개발하고 싶었지만, 윈도우 노트북을 가지고 가면 뭔가 "진짜 개발자" 같지 않다는 느낌이 들었습니다. 왜 그랬을까요?
문제는 개발 환경이었습니다. 백엔드 개발을 배우려면 리눅스 환경이 필요했는데, 윈도우는 Unix 계열 운영체제가 아니었습니다. bash, curl, grep, ssh 같은 도구들이 기본적으로 없었고, 설치하려면 Cygwin이나 Git Bash 같은 반쪽짜리 솔루션을 써야 했습니다. 서버 배포는 Ubuntu에서 하는데, 로컬에서는 윈도우에서 개발하니까 "내 컴퓨터에선 되는데요?"라는 상황이 자주 발생했습니다.
그래서 저는 듀얼 부팅을 선택했습니다. 하드디스크를 반으로 나눠서 한쪽엔 윈도우, 다른 쪽엔 Ubuntu를 설치했습니다. 롤을 하거나 한글 문서를 쓸 때는 윈도우로 부팅하고, 코딩을 할 때는 Ubuntu로 재부팅했습니다. 불편함의 극치였습니다. 하루에 컴퓨터를 5번씩 껐다 켜는 날도 있었습니다.
나중엔 VMware Workstation을 써봤습니다. 가상머신으로 Ubuntu를 돌리면 재부팅 없이 리눅스를 쓸 수 있었지만, 너무 느렸습니다. 메모리 4GB짜리 노트북에서 2GB를 VM에 할당하니, 윈도우도 느리고 리눅스도 느렸습니다. 컴파일 한 번 돌리면 팬이 돌아가고 CPU가 불타는 소리가 들렸습니다.
"아, 돈 벌면 무조건 맥북 사야지."
이게 윈도우를 쓰는 개발 입문자들의 공통된 한탄이었습니다.
그런데 2016년, 마이크로소프트가 이상한 발표를 합니다. "Windows Subsystem for Linux"라는 걸 만들겠다고. 윈도우 안에서 네이티브로 리눅스 바이너리를 실행할 수 있게 하겠다는 겁니다. 당시엔 모두가 의심했습니다. "MS가 리눅스를 지원한다고? 무슨 함정이지?" Microsoft는 역사적으로 리눅스와 오픈소스를 적대시했던 회사였으니까요.
하지만 이건 함정이 아니라 전략 전환이었습니다. MS는 클라우드 시대에 Azure를 성장시키려면, 개발자들이 윈도우를 떠나지 않게 해야 한다는 걸 깨달았습니다. 서버는 대부분 리눅스인데, 로컬 개발 환경은 맥이나 리눅스로 가버리면 윈도우 생태계 자체가 죽습니다. Satya Nadella CEO는 "Microsoft loves Linux"라고 선언했고, 실제로 Azure에서 돌아가는 VM의 절반 이상이 리눅스였습니다.
그렇게 탄생한 것이 WSL(Windows Subsystem for Linux)입니다. 2016년에 나온 WSL 1은 흥미로운 시도였지만, 문제가 많았습니다.
WSL 1의 구조를 이해하려면 번역 레이어(Translation Layer)라는 개념을 알아야 합니다. 리눅스 프로그램들은 리눅스 시스템 콜(syscall)을 사용합니다. 예를 들어 open(), read(), write() 같은 함수들이죠. 그런데 윈도우는 전혀 다른 커널 구조를 가지고 있습니다.
WSL 1은 리눅스 syscall을 실시간으로 윈도우 API로 번역하는 방식이었습니다. 마치 통역사처럼요. 리눅스 프로그램이 "파일 열어줘"라고 하면, WSL이 이걸 받아서 "Windows NT 커널님, 파일 하나 열어주세요"라고 번역해서 전달하는 겁니다.
이 방식은 엄청난 엔지니어링 성과였지만, 근본적인 한계가 있었습니다:
저도 WSL 1을 설치해서 써봤는데, "이건 그냥 좀 나은 Git Bash 수준이네"라는 느낌이었습니다. 기대가 컸던 만큼 실망도 컸습니다.
2019년, MS가 WSL 2를 발표했을 때 제 반응은 "또 뭐가 달라졌다고?"였습니다. 하지만 실제로 써보고 충격을 받았습니다. 이건 완전히 다른 물건이었습니다.
WSL 2의 핵심은 간단합니다: 번역을 포기하고, 진짜 리눅스 커널을 돌리자.
마이크로소프트는 리눅스 커널 소스코드를 가져와서(리눅스는 오픈소스니까), 윈도우용으로 커스터마이징했습니다. 그리고 이 커널을 Hyper-V라는 MS의 하이퍼바이저 위에서 가벼운 가상머신으로 돌렸습니다. 이게 바로 Lightweight VM 전략입니다.
일반 가상머신과의 차이점은:
이건 마치 집 안에 작은 텐트를 치는 것과 같습니다. 텐트(리눅스) 안에서는 완전히 독립적인 공간이지만, 집(윈도우) 전체를 활용할 수도 있습니다. 화장실(파일 시스템)은 공유하고, Wi-Fi(네트워크)도 공유하는 거죠.
[Linux App]
↓ (syscall)
[WSL Translation Layer]
↓ (변환)
[Windows NT Kernel]
WSL 2 구조:
[Linux App]
↓ (syscall)
[Real Linux Kernel (in VM)]
↕ (Hyper-V)
[Windows NT Kernel]
차이가 보이시나요? WSL 2는 진짜 리눅스 커널입니다. 번역하지 않습니다.
이제 실제로 WSL 2를 설치하고 Node.js 개발 환경을 만들어보겠습니다. 제가 실제로 사용하는 설정입니다.
Windows 10 버전 2004 이상이면 한 줄로 설치됩니다:
wsl --install
이 명령어가 하는 일:
컴퓨터를 재부팅하면 Ubuntu 설치가 완료되고, 사용자명과 비밀번호를 입력하라고 합니다. 이건 리눅스 계정이고, 윈도우 계정과는 별개입니다.
특정 배포판을 선택하고 싶다면:
# 설치 가능한 배포판 목록
wsl --list --online
# Ubuntu 22.04 설치
wsl --install -d Ubuntu-22.04
Ubuntu에 처음 접속하면 패키지를 업데이트해야 합니다:
sudo apt update && sudo apt upgrade -y
# 필수 개발 도구 설치
sudo apt install -y \
build-essential \
curl \
wget \
git \
vim \
zsh
bash보다 강력한 zsh를 설치하고, Oh My Zsh로 꾸밉니다:
# zsh를 기본 셸로 설정
chsh -s $(which zsh)
# Oh My Zsh 설치
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
# 유용한 플러그인 추가
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
# .zshrc 편집해서 플러그인 활성화
vim ~/.zshrc
# plugins=(git zsh-autosuggestions zsh-syntax-highlighting)
터미널을 껐다 켜면 zsh가 적용됩니다. 이제 명령어 자동완성이 제대로 작동합니다.
NVM(Node Version Manager)으로 Node.js를 설치하는 게 베스트 프랙티스입니다:
# NVM 설치
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# 터미널 재시작 또는
source ~/.zshrc
# Node.js LTS 버전 설치
nvm install --lts
nvm use --lts
# 확인
node --version
npm --version
# 글로벌 패키지 설치
npm install -g yarn pnpm typescript ts-node nodemon
이제 실제 프로젝트를 만들어봅시다:
# WSL 내부의 홈 디렉토리에서 작업 (중요!)
cd ~
mkdir projects
cd projects
# Express.js 프로젝트 생성
mkdir my-api
cd my-api
npm init -y
npm install express
# server.js 작성
cat > server.js << 'EOF'
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.json({
message: 'Hello from WSL2!',
platform: process.platform,
hostname: require('os').hostname()
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
EOF
# 실행
node server.js
윈도우 브라우저에서 http://localhost:3000을 열면 응답이 옵니다. 리눅스에서 돌아가는 서버에 윈도우 브라우저가 접속하는 겁니다. 네트워크가 통합되어 있기 때문입니다.
WSL에서 가장 마법 같은 부분입니다:
# WSL 터미널에서
cd ~/projects/my-api
code .
이 명령어를 치면 윈도우의 VS Code가 열리면서, WSL 내부의 파일을 편집할 수 있습니다. VS Code는 "Remote - WSL" 확장을 자동으로 설치하고, 실제로는 WSL 안에서 VS Code Server를 돌립니다. GUI는 윈도우에서 보지만, 실제 코드 실행은 리눅스에서 합니다.
터미널도 VS Code 내부에서 통합됩니다. Ctrl+`를 누르면 WSL bash/zsh 터미널이 뜹니다. 디버거도 작동하고, 확장 프로그램도 설치됩니다. 이건 정말 네이티브 리눅스 개발 경험입니다.
WSL 2를 쓰면서 가장 많이 하는 실수가 파일을 어디에 두느냐입니다. 이게 성능을 10배 차이 나게 만듭니다.
WSL 2에는 두 개의 파일 시스템이 있습니다:
/home/username/ 같은 경로./mnt/c/Users/... 같은 경로로 마운트됩니다.WSL에서 윈도우 파일을 접근할 수 있고, 반대도 가능합니다:
�CB9�
여기서 엄청난 성능 차이가 발생합니다:
예를 들어 Node.js 프로젝트를 /mnt/c/Users/RATIA/projects/에 두고 WSL에서 npm install을 실행하면:
결과? 엄청나게 느립니다. npm install이 5분씩 걸리는 경우도 있습니다.
해결책: 프로젝트를 WSL 내부에 두세요.
�CB10�
파일을 ~/(리눅스 홈)에 두면 ext4를 직접 쓰니까 빠릅니다. npm install이 1분도 안 걸립니다.
WSL 파일은 윈도우 탐색기에서 \\wsl$\Ubuntu\home\username\로 접근할 수 있습니다. 여기에 바로가기를 만들어두면 편합니다. 파일을 복사해서 윈도우 쪽으로 백업할 수도 있습니다.
Docker는 WSL 2의 킬러 앱입니다. WSL 2 이전에는 윈도우에서 Docker를 쓰려면 Docker Desktop이 VirtualBox나 Hyper-V로 리눅스 VM을 따로 돌려야 했습니다. 무겁고 느렸죠.
WSL 2가 나온 후, Docker Desktop은 WSL 2를 백엔드로 사용할 수 있게 되었습니다. 이게 게임 체인저였습니다:
docker 명령어를 씁니다.�CB11�
Docker 컨테이너가 WSL 내부에서 실행되니까 네이티브 리눅스 속도가 나옵니다. Kubernetes(kind, k3s)도 WSL에서 잘 돌아갑니다.
제 경우, Docker Compose로 PostgreSQL + Redis + API 서버를 띄우는데 WSL 이전에는 5분 걸리던 게 이제는 30초도 안 걸립니다.
WSL 2는 내부적으로 가상머신이지만, 네트워크는 NAT 모드로 설정되어 있습니다. 이게 무슨 뜻이냐면:
localhost:3000으로 서버를 띄우면, 윈도우에서도 localhost:3000으로 접근 가능대부분의 경우 "그냥 작동합니다". 하지만 가끔 문제가 생깁니다:
WSL에서 윈도우 쪽에 떠 있는 서비스(예: PostgreSQL)에 접근하려면 localhost가 아니라 윈도우 IP를 써야 할 때가 있습니다.
�CB12�
또는 .bashrc/.zshrc에 alias를 만들어둡니다:
�CB13�
WSL 2는 NVIDIA GPU를 직접 접근할 수 있습니다. 이건 CUDA를 쓰는 딥러닝 개발자들에게 엄청난 기능입니다.
설치 방법:
�CB14�
TensorFlow, PyTorch 같은 프레임워크가 GPU를 그대로 활용합니다. 윈도우에서 게임도 하고, WSL에서 모델 학습도 하는 게 가능합니다.
과거 WSL은 systemd를 지원하지 않았습니다. 이게 문제였던 이유는, 많은 리눅스 서비스들(PostgreSQL, Redis, nginx 등)이 systemd로 관리되기 때문입니다.
2022년부터 WSL은 systemd를 공식 지원합니다:
�CB15�
이제 진짜 리눅스처럼 서비스를 관리할 수 있습니다:
�CB16�
2021년에 WSLg가 추가되면서, WSL에서 Linux GUI 애플리케이션을 실행할 수 있게 되었습니다. X11 서버 설치 없이, 그냥 작동합니다.
�CB17�
이건 Wayland 기반으로 작동하고, 윈도우 창 시스템과 통합됩니다. 심지어 소리도 나고, 클립보드도 공유됩니다.
실용적인 사례:
WSL 2가 완벽한 건 아닙니다. 제가 겪은 문제들:
WSL은 기본적으로 USB를 직접 접근할 수 없습니다. Arduino나 하드웨어 개발 시 문제가 됩니다.
해결책: usbipd-win 프로젝트를 사용하면 USB를 WSL에 포워딩할 수 있습니다.
일부 VPN(특히 회사 VPN)은 WSL 네트워크를 제대로 라우팅하지 못합니다. VPN 연결 시 WSL의 인터넷이 끊기는 경우가 있습니다.
해결책: DNS를 수동으로 설정하거나, VPN 설정을 조정해야 합니다.
윈도우와 리눅스의 파일 권한 모델이 달라서, /mnt/c/에서 chmod 명령이 이상하게 작동할 때가 있습니다.
해결책: 프로젝트를 WSL 내부(~/)에 두면 문제없습니다.
제가 WSL 2를 쓰기 시작한 지 3년이 넘었습니다. 지금은 맥북도 있지만, 주 개발 머신은 여전히 WSL이 설치된 윈도우 데스크탑입니다. 이유는 간단합니다:
WSL 2는 단순히 "윈도우에서 리눅스를 쓸 수 있게 해주는 도구"가 아닙니다. 이건 개발 환경의 패러다임을 바꾼 기술입니다. 마이크로소프트가 "개발자가 쓰고 싶은 플랫폼"을 만들기 위해 리눅스를 적으로 보는 대신 품었다는 게 놀랍습니다.
2015년의 저에게 말해주고 싶습니다. "5년만 기다려. 윈도우 노트북으로도 충분히 멋진 개발을 할 수 있게 될 거야."