11.docker
Episode 11: "도커: 컨테이너가 바꾼 세상"
"내 컴퓨터에서는 되는데"를 영원히 묻어버리다
프롤로그: "내 컴퓨터에서는 되는데요"
2010년, 전 세계 수백만 개발자들이 매일 같은 악몽을 겪고 있었습니다.
# 개발자의 노트북
$ python app.py
Starting server on port 3000...
✓ All tests passed!
# 프로덕션 서버
$ python app.py
Error: Module 'requests' version 2.25.0 required, found 2.18.4
Error: libssl.so.1.0.0: cannot open shared object file
Segmentation fault (core dumped)
# 개발자: "어? 내 컴퓨터에서는 되는데요??"
# DevOps: "😤"
"Works on my machine" (내 컴퓨터에서는 되는데)은 단순한 밈이 아니었습니다. 실존하는 재앙이었죠.
배포의 악몽들 (2000년대)
환경 불일치:
- 개발: macOS, 프로덕션: Linux
- 로컬: Python 3.7, 서버: Python 2.7
- 의존성 버전이 전부 다름
의존성 지옥:
- 시스템 라이브러리 버전 충돌
- 패키지 매니저 문제
- "어제까지 됐는데 오늘 안 돼요"
격리 부족:
- 같은 서버에 여러 앱
- 포트 충돌, 라이브러리 충돌
- 한 앱이 서버 전체를 다운시킴
배포 과정:
- 50페이지짜리 배포 문서
- 수동 설정 단계 수십 개
- 배포 시간: 4-8시간
- 성공률: 50%
2013년 3월, Solomon Hykes는 PyCon에서 5분짜리 라이트닝 토크를 합니다. 제목은 "The future of Linux Containers".
그는 시연합니다:
$ docker run ubuntu echo "Hello World"
Hello World
# 끝. 5초 걸렸습니다.
청중은 별로 관심이 없어 보였습니다. 하지만 세상은 곧 바뀌게 됩니다.
이 글에서 다룰 내용
- 가상머신의 무거운 유산
- 솔로몬 하이크스의 dotCloud 실험
- "Build once, Run anywhere"의 진정한 구현
- 쿠버네티스와 오케스트레이션 전쟁
Chapter 1: 가상머신의 무거운 유산
물리 서버 시대의 악몽 (1990년대-2000년대 초)
클라우드 이전 시대, 서버 관리는 물리적인 작업이었습니다:
# 새로운 애플리케이션 배포하려면...
1. 하드웨어 구매 (납기: 2-3개월)
2. 데이터센터 랙에 설치
3. 네트워크 케이블 연결
4. OS 설치 (수동)
5. 의존성 설치 (수동)
6. 애플리케이션 배포
# 소요 시간: 3-6개월
# 비용: 수천만 원
# 확장성: 거의 없음
물리 서버의 문제들
비효율의 시대
자원 낭비:
- 평균 CPU 사용률: 10-15%
- 대부분의 시간 동안 유휴 상태
- 하드웨어 비용 낭비
격리 부족:
- 하나의 OS에 모든 앱
- 충돌 위험
- 보안 문제
확장 불가:
- 트래픽 급증 시 대응 불가
- 새 서버 추가에 몇 달 소요
관리 복잡성:
- 수백 대의 서버 수동 관리
- 업데이트, 패치 적용에 주말 소요
VMware와 가상화 혁명 (1990년대 후반-2000년대)
VMware는 가상화 기술로 혁명을 일으켰습니다:
Physical Server
├─ Hypervisor (VMware ESXi)
│ ├─ VM 1 (Full OS + App 1)
│ ├─ VM 2 (Full OS + App 2)
│ └─ VM 3 (Full OS + App 3)
# 하나의 물리 서버에서 여러 OS 실행!
1998: VMware 설립
하드웨어 가상화 기술 개발
2001: VMware ESX Server
엔터프라이즈급 가상화 플랫폼
2006: AWS EC2 출시
클라우드 컴퓨팅의 시작 (Xen 기반 가상화)
2008: KVM, Xen 보편화
오픈소스 가상화 기술
가상화의 장점:
가상화가 가능하게 한 것들
- 자원 효율성: CPU 사용률 70-80%로 향상
- 격리: 각 VM이 독립적인 OS
- 빠른 프로비저닝: 몇 분 안에 새 서버
- 스냅샷/백업: 간편한 복구
- 클라우드 컴퓨팅: AWS, Azure, GCP의 기반
가상머신의 무거운 짐
하지만 가상머신에도 치명적인 단점이 있었습니다:
# 가상머신의 무게
VM 1: Ubuntu Server
├─ Full OS (1 GB)
├─ Init system (systemd)
├─ System services (ssh, cron, ...)
├─ Python runtime (300 MB)
└─ Your app (50 MB)
# Total: ~1.5 GB, Boot time: 30-60초
# 똑같은 앱을 3개 실행하면?
# Total: ~4.5 GB, 대부분이 중복!
가상머신의 한계
개발자에게는 여전히 무거움
무게:
- OS 전체를 포함: GB 단위
- 부팅 시간: 수십 초
- 메모리 오버헤드: 수백 MB
중복:
- 각 VM마다 동일한 OS 복사본
- 커널, 라이브러리 중복
- 자원 낭비
이식성 부족:
- VM 이미지는 거대함 (수십 GB)
- 네트워크로 전송하기 어려움
- 개발 환경과 프로덕션 동기화 어려움
여전히 "내 컴퓨터에서는 되는데":
- VM 설정이 달라질 수 있음
- 의존성 관리 여전히 수동
- 재현 가능성 낮음
개발자들에게 VM은 여전히 너무 무거웠습니다. 더 가벼운 해결책이 필요했습니다.
Chapter 2: 솔로몬 하이크스의 dotCloud 실험
2008년, PaaS 스타트업 dotCloud
Solomon Hykes는 프랑스의 젊은 엔지니어였습니다. 그는 PaaS (Platform as a Service) 스타트업 dotCloud를 공동 설립했습니다.
PaaS란?
개발자가 인프라를 관리하지 않고 코드만 배포하면 되는 플랫폼.
예: Heroku, Google App Engine, dotCloud
dotCloud의 문제: 효율적인 격리가 필요했습니다:
# dotCloud의 고민
Customer A: Python 2.7 + Django 1.4
Customer B: Python 3.6 + Flask
Customer C: Node.js 10
Customer D: Ruby on Rails
# 각 고객을 어떻게 격리하지?
# VM은 너무 무겁고 비쌈
# 직접 실행하면 충돌
Linux Containers (LXC): 숨겨진 보석
Solomon은 Linux 커널의 cgroups와 namespaces 기능을 발견합니다:
# Linux 커널 기능들 (2008년경)
# 1. namespaces (2002~)
# 프로세스 격리: PID, network, mount, user, ...
# 2. cgroups (2007)
# 자원 제한: CPU, memory, disk I/O
# 3. chroot (1979!)
# 파일시스템 격리
# → 이것들을 조합하면?
# → 가벼운 격리 환경!
Containers vs Virtual Machines
근본적인 차이
Virtual Machine:
Host OS
├─ Hypervisor
│ ├─ Guest OS 1 (Full OS)
│ │ └─ App 1
│ ├─ Guest OS 2 (Full OS)
│ │ └─ App 2
Container:
Host OS (Linux Kernel)
├─ Container Engine
│ ├─ Container 1 (App + 라이브러리만)
│ ├─ Container 2 (App + 라이브러리만)
│ └─ Container 3 (App + 라이브러리만)
# 커널을 공유! = 훨씬 가벼움
차이점:
- VM: 하드웨어 가상화, 각각 커널
- Container: OS 레벨 가상화, 커널 공유
- 결과: Container가 10배 이상 가벼움
2013년, Docker의 탄생
dotCloud는 고전했습니다. PaaS 시장은 Heroku가 장악했고, 자금은 바닥났습니다.
Solomon은 피봇을 결정합니다: 내부 컨테이너 기술을 오픈소스로 공개하자.
# Docker 0.1 (2013년 3월)
# Before Docker
$ lxc-create -n mycontainer -t ubuntu
$ lxc-start -n mycontainer
$ lxc-attach -n mycontainer
# ... 복잡한 설정들 ...
# With Docker
$ docker run ubuntu echo "Hello World"
Hello World
# 끝! 이게 전부!
"Docker는 배송 컨테이너의 아이디어를 소프트웨어에 적용한 것입니다. 컨테이너 안에 무엇이 있든, 어디로든 보낼 수 있습니다."
Docker가 혁신적이었던 이유:
단순한 API
복잡한 LXC를 간단한 명령어로 추상화
이미지 레이어링
효율적인 저장과 배포
Dockerfile
인프라를 코드로 (Infrastructure as Code)
Docker Hub
컨테이너 이미지 공유 플랫폼
Chapter 3: "Build Once, Run Anywhere"의 진정한 구현
Dockerfile: 인프라를 코드로
Docker의 가장 큰 혁신 중 하나는 Dockerfile입니다:
# Dockerfile - 환경을 코드로 정의
FROM ubuntu:20.04
# 의존성 설치
RUN apt-get update && apt-get install -y \
python3.8 \
python3-pip
# 애플리케이션 복사
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY app.py .
# 실행
CMD ["python3", "app.py"]
# 이 파일만 있으면 어디서든 동일한 환경!
Dockerfile의 혁명
Before Docker:
- 50페이지 배포 문서
- "Step 37: sudo apt-get install libssl-dev"
- 누군가 단계를 놓치면? 실패
With Docker:
- Dockerfile 하나
docker build로 빌드docker run으로 실행- 100% 재현 가능
이미지 레이어링: 효율성의 마법
Docker 이미지는 레이어로 구성됩니다:
FROM ubuntu:20.04 # Layer 1: 80MB
RUN apt-get update && \ # Layer 2: 120MB
apt-get install -y python3
COPY requirements.txt . # Layer 3: 1KB
RUN pip3 install -r requirements.txt # Layer 4: 150MB
COPY app.py . # Layer 5: 5KB
# 총 5개 레이어
# 변경된 레이어만 다시 빌드!
# 앱 코드(app.py)만 수정했을 때
$ docker build -t myapp .
Step 1/5 : FROM ubuntu:20.04
---> Using cache ✓
Step 2/5 : RUN apt-get update...
---> Using cache ✓
Step 3/5 : COPY requirements.txt
---> Using cache ✓
Step 4/5 : RUN pip3 install
---> Using cache ✓
Step 5/5 : COPY app.py
---> Running in abc123def (5KB만 빌드!)
# 빌드 시간: 1초 미만!
레이어링의 이점
변경사항만 빌드
효율성:
- 변경된 레이어만 재빌드
- 캐시 활용으로 빌드 시간 단축
- 네트워크 전송량 최소화
공유:
- 여러 이미지가 베이스 레이어 공유
- 디스크 공간 절약
속도:
- 빌드: 초 단위
- 배포: 변경분만 전송
- 시작: 1초 미만
Docker Hub: 컨테이너 이미지 생태계
Docker Hub는 컨테이너의 GitHub이 되었습니다:
# 공식 이미지 사용
$ docker run nginx
$ docker run postgres
$ docker run redis
# 이미지 검색
$ docker search python
# 자신의 이미지 공유
$ docker push myusername/myapp
# 전 세계에서 사용 가능
$ docker pull myusername/myapp
Docker Hub의 영향
2024년 기준:
- 1,300만+ 이미지
- 월 200억+ 다운로드
- 사실상 표준 레지스트리
영향:
- 개발 환경 공유 간편화
- CI/CD 파이프라인 표준화
- 마이크로서비스 배포 가능
"내 컴퓨터에서는 되는데"의 종말
Docker는 **진정한 "Build Once, Run Anywhere"**를 실현했습니다:
# 개발자의 맥북
$ docker build -t myapp .
$ docker run myapp
✓ Works!
# 동료의 윈도우
$ docker run myapp
✓ Works!
# CI 서버 (Linux)
$ docker run myapp
✓ Works!
# 프로덕션 서버 (AWS Linux)
$ docker run myapp
✓ Works!
# 컨테이너 안은 항상 동일한 환경!
"Docker는 '내 컴퓨터에서는 되는데' 문제를 해결한 것이 아닙니다. 그 문제를 영원히 묻어버렸습니다."
Chapter 4: 쿠버네티스와 오케스트레이션 전쟁
2014년, 컨테이너의 폭발적 성장
Docker가 성공하면서 새로운 문제가 생겼습니다:
# 컨테이너가 1개일 때
$ docker run myapp
# 쉽다!
# 컨테이너가 10개일 때
$ docker run app1
$ docker run app2
# ... (반복)
# 아직 관리 가능
# 컨테이너가 1000개일 때
# 어떤 서버에 어떤 컨테이너가?
# 컨테이너가 죽으면 누가 재시작?
# 로드 밸런싱은?
# 롤링 업데이트는?
# 🤯
컨테이너 오케스트레이션이 필요했습니다.
2014년, 쿠버네티스의 등장
Google은 내부에서 Borg라는 컨테이너 오케스트레이션 시스템을 10년 넘게 사용하고 있었습니다. Google의 모든 서비스(검색, Gmail, YouTube)는 컨테이너로 실행되고 있었죠.
Google은 Borg의 오픈소스 버전을 만들기로 결정합니다. 이름은 Kubernetes (그리스어로 "조타수", k8s로 줄여 씀).
Kubernetes의 핵심 개념
선언적 인프라 관리
Pod:
- 가장 작은 배포 단위
- 하나 이상의 컨테이너
Deployment:
- Pod의 복제본 관리
- 원하는 상태 선언
Service:
- Pod에 대한 네트워크 접근
- 로드 밸런싱
ConfigMap/Secret:
- 설정과 비밀 관리
# Kubernetes Deployment 예제
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3 # 3개의 복제본 실행
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
# 이 YAML 파일 하나로
# - 3개의 컨테이너 실행
# - 로드 밸런서 설정
# - 자동 복구
# - 롤링 업데이트
# 모두 자동!
선언적 관리의 힘
명령적 (Imperative):
docker run myapp
# 컨테이너가 죽으면? 수동으로 재시작
선언적 (Declarative):
replicas: 3
# 3개가 실행되어야 함
# 죽으면? 자동으로 재시작
# 너무 많으면? 자동으로 제거
Kubernetes는 원하는 상태를 선언하면, 그 상태를 유지하기 위해 끊임없이 노력합니다.
오케스트레이션 전쟁 (2014-2017)
Docker의 성공 이후, 여러 오케스트레이션 플랫폼이 등장했습니다:
Docker Swarm (2014)
Docker 공식 오케스트레이션. 간단하지만 기능 제한적
Kubernetes (2014)
Google 발, 강력하지만 복잡함
Apache Mesos (2009, 재조명 2014)
트위터, Airbnb 등에서 사용. 범용 클러스터 관리
Amazon ECS (2015)
AWS 전용 서비스
2017년경, Kubernetes가 사실상 표준이 되었습니다:
Kubernetes의 승리 요인
왜 k8s가 이겼나
기술적 우수성:
- 강력한 기능 (오토스케일링, 롤링 업데이트 등)
- 확장 가능한 아키텍처
- 플러그인 생태계
커뮤니티:
- Google의 10년 경험 (Borg)
- CNCF (Cloud Native Computing Foundation) 주도
- 오픈소스 거버넌스
산업 지지:
- AWS (EKS), Google (GKE), Azure (AKS)
- 모든 클라우드 벤더가 지원
생태계:
- Helm (패키지 관리)
- Istio (서비스 메시)
- Prometheus (모니터링)
- 수천 개의 도구와 통합
"Kubernetes는 배포된 애플리케이션을 위한 운영체제입니다. Linux가 프로세스를 관리하듯, Kubernetes는 컨테이너를 관리합니다."
클라우드 네이티브 시대
Docker와 Kubernetes는 클라우드 네이티브 시대를 열었습니다:
# 현대적인 애플리케이션 아키텍처
마이크로서비스 (각각 컨테이너)
├─ Frontend (React)
├─ API Gateway (Node.js)
├─ Auth Service (Go)
├─ User Service (Python)
├─ Payment Service (Java)
├─ Notification Service (Rust)
└─ Analytics Service (Python)
# Kubernetes가 모두 관리
# 각 서비스는 독립적으로 배포
# 자동 스케일링
# 자가 치유
클라우드 네이티브의 특징
마이크로서비스:
- 작은 독립적인 서비스들
- 각각 컨테이너로 배포
동적 오케스트레이션:
- Kubernetes가 자동 관리
- 선언적 설정
DevOps/CI/CD:
- 자동 빌드, 테스트, 배포
- GitOps 패턴
관찰 가능성:
- 로깅, 모니터링, 추적
- Prometheus, Grafana, Jaeger
에필로그: 컨테이너가 바꾼 세상
2013년 → 2024년: 11년의 변화
2013년, Solomon Hykes의 5분 데모는 세상을 바꿨습니다.
Docker가 바꾼 것들
소프트웨어 산업의 혁명
개발 환경:
- Before: "내 컴퓨터에서는 되는데"
- After: "컨테이너에서는 항상 됨"
배포:
- Before: 50페이지 문서, 4-8시간
- After:
kubectl apply, 30초
확장성:
- Before: 서버 구매 (몇 달)
- After:
kubectl scale(몇 초)
마이크로서비스:
- Before: 불가능에 가까움
- After: 표준 아키텍처
클라우드:
- Before: VM 기반 IaaS
- After: 컨테이너 기반 CaaS/PaaS
숫자로 보는 영향
Docker & Kubernetes의 현황 (2024)
Docker:
- 1,300만+ 개발자
- 월 200억+ 다운로드
- 산업 표준 컨테이너 런타임
Kubernetes:
- 5,600+ 기여자
- 110,000+ 커밋
- 94% 기업이 사용 (CNCF 설문)
- 사실상 표준 오케스트레이션
영향:
- 배포 시간: 주 → 분
- 확장 시간: 시간 → 초
- 서버 활용률: 15% → 70%+
- 개발자 생산성: 5-10배 향상
새로운 패러다임의 탄생
Docker와 Kubernetes는 단순한 도구가 아니었습니다. 새로운 패러다임이었습니다:
# Pre-Container 시대
"이 서버에 Python 3.7이 설치되어 있나요?"
"libssl 버전이 맞나요?"
"포트 8080이 비어 있나요?"
# Container 시대
"Docker만 있으면 됩니다"
"컨테이너는 클라우드 컴퓨팅의 완성입니다. 진정한 'Write Once, Run Anywhere'를 실현했습니다."
dotCloud에서 Docker, Inc.까지
Solomon Hykes의 여정은 극적이었습니다:
2008: dotCloud 설립
PaaS 스타트업, 고전
2013: Docker 오픈소스 공개
마지막 시도, 대박
2013: 회사명 Docker, Inc.로 변경
제품이 회사가 됨
2014-2019: 기업가치 급상승
최고 $1.3B (약 1.5조원)
2019: Solomon Hykes 퇴임
"내 역할은 끝났다"
"Docker를 만들 때, 우리는 단지 배포를 쉽게 만들고 싶었습니다. 그것이 전체 산업을 바꿀 줄은 몰랐습니다."
"Works on my machine"은 이제 농담
2010년, "Works on my machine"은 현실이었습니다. 2024년, "Works on my machine"은 농담입니다.
# 이 한 파일로 모든 문제 해결
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# 어디서든 똑같이 작동함
# 개발자 노트북
# CI/CD 파이프라인
# 스테이징 서버
# 프로덕션 클러스터
# "It works in the container"
# 그리고 컨테이너는 어디서나 같음
컨테이너는 소프트웨어 배송의 표준 단위가 되었습니다. 물리적 배송 컨테이너가 글로벌 무역을 혁명적으로 바꿨듯이, Docker 컨테이너는 소프트웨어 배포를 혁명적으로 바꿨습니다.
그리고 그 혁명은 2013년 3월, 5분짜리 라이트닝 토크에서 시작되었습니다.
참고자료
Docker Documentation
Docker 공식 문서
Kubernetes Documentation
Kubernetes 공식 문서
The Future of Linux Containers (PyCon 2013)
Docker의 첫 공개 발표
Borg, Omega, and Kubernetes
Google의 컨테이너 오케스트레이션 역사
The 10 Billion Dollar Container
Docker의 성장 이야기
CNCF Survey 2023
클라우드 네이티브 현황
다음 에피소드에서는 "클라우드 네이티브: 서버리스의 등장"을 다룰 예정입니다. 서버를 관리하지 않고 코드만 배포하는 꿈이 어떻게 실현되었는지 살펴보겠습니다.