🚀 Kubernetes 발전사: 문제 해결 중심
컨테이너 기술과 Kubernetes의 발전을 문제 해결 관점에서 살펴보면, 각 기술이 어떤 필요에 의해 등장했는지 자연스럽게 이해할 수 있습니다. 실제 발생한 문제들과 그 해결 과정을 중심으로 정리해보겠습니다.
1단계: 서버 자원 활용의 딜레마 (2000년대 초반)
🔴 문제상황
가상 머신의 한계
각 VM마다 전체 운영체제 필요 → 메모리, CPU 낭비 심각
하나의 물리 서버에 몇 개 안 되는 VM만 실행 가능
부팅 시간도 오래 걸리고 관리 복잡
물리 서버 직접 사용의 문제
여러 애플리케이션이 같은 서버에서 실행되면 서로 간섭
라이브러리 버전 충돌, 포트 충돌 등 문제 빈발
장애 발생 시 다른 애플리케이션까지 영향
🟢 해결책: 리눅스 커널 격리 기술 발전
핵심 기술들의 등장
chroot (1982년): 파일 시스템 격리 - "애플리케이션별로 보이는 파일 시스템 분리"
namespace (2002년): 프로세스, 네트워크, 사용자 등 시스템 리소스 격리
cgroup (2006년): CPU, 메모리, 디스크 I/O 등 하드웨어 자원 제어 및 모니터링
이 기술들이 현대 컨테이너의 토대가 되었지만, 직접 사용하기엔 너무 복잡했습니다.
2단계: 커널 기술의 복잡성 문제 (2008년)
🔴 문제상황
개발자에게는 너무 어려운 기술
chroot, namespace, cgroup을 조합해서 사용하려면 리눅스 커널 전문 지식 필요
매번 복잡한 설정 과정 반복
같은 환경을 다른 서버에 재현하기 어려움
실수로 잘못 설정하면 보안 취약점 발생 가능
🟢 해결책: LXC (Linux Containers) 등장
"쉬운 컨테이너"의 시작
복잡한 커널 기술들을 묶어서 간단한 명령어로 제공
설정 파일을 통한 일관된 환경 구성
가상 머신보다 가볍고, 물리 서버보다 안전한 중간 지점 제공
하지만 여전히 시스템 관리자 수준의 기술 지식이 필요했습니다.
3단계: 개발자 친화성 부족 (2013년)
🔴 문제상황
LXC의 한계
여전히 시스템 관리자 중심의 도구 → 개발자가 사용하기 복잡
컨테이너 이미지 관리 기능 없음 → "내가 만든 환경을 어떻게 공유하지?"
네트워킹, 로깅, 스토리지 관리 등 실제 서비스 운영에 필요한 기능 부족
각 배포판마다 다른 설정 방식
🟢 해결책: Docker의 혁신적 등장
개발자 경험(DX) 혁신
초기(2013년): LXC를 백엔드로 사용하되 사용자 친화적 인터페이스 제공
2014년 Docker 0.9: libcontainer 도입으로 LXC 의존성 제거
통합 관리 플랫폼:
직관적인 CLI (
docker run
,docker build
)Docker Hub를 통한 이미지 공유
자동 로그 관리, 네트워크 설정
Dockerfile을 통한 재현 가능한 환경 구성
Docker의 성공 비결은 복잡한 기술을 개발자가 쉽게 사용할 수 있게 만든 것이었습니다.
4단계: 컨테이너 관리의 복잡성 (2014년)
🔴 문제상황
운영 환경의 현실
수십, 수백 개의 컨테이너를 어떻게 관리할 것인가?
컨테이너가 죽으면 누가 다시 실행시켜 주나?
트래픽 증가 시 컨테이너를 자동으로 늘리려면?
여러 컨테이너 간 네트워크 통신은 어떻게?
로드밸런싱, 서비스 디스커버리는?
🟢 해결책: Kubernetes 등장
컨테이너 오케스트레이션의 시작
Google의 내부 시스템 Borg 경험을 바탕으로 개발
초기 아키텍처 (단순함):
kube-apiserver: 사용자 요청 처리
kubelet: 각 노드에서 컨테이너 관리
직접 통합: kubelet → Docker API 직접 호출
당시에는 Docker가 거의 유일한 컨테이너 런타임이었기 때문에 이런 단순한 구조로도 충분했습니다.
5단계: 런타임 생태계의 다양화 (2016년)
🔴 문제상황
단일 런타임 의존의 위험성
Docker에만 의존하는 구조의 리스크
CoreOS rkt, Intel Clear Containers 등 대안 런타임 등장
각 런타임마다 장단점이 다름 (보안, 성능, 기능 등)
하지만 Kubernetes는 Docker에만 연결 가능 → 새로운 런타임 추가할 때마다 kubelet 코드 수정 필요
🟢 해결책 1: Docker 내부 구조 개선
containerd 프로젝트 시작
2016년 4월 Docker 1.11: 내부적으로 containerd 사용 시작
2016년 12월: containerd를 독립 오픈소스 프로젝트로 공개
구조 변경: Docker Engine = dockerd → containerd → runc
containerd가 실제 컨테이너 라이프사이클 관리 담당
🟢 해결책 2: CRI(Container Runtime Interface) 도입
Kubernetes 1.5 (2016년 12월)
표준 인터페이스 정의: kubelet과 런타임 간의 통신 규약 표준화
플러그인 아키텍처: 새로운 런타임 추가 시 kubelet 코드 수정 불필요
확장성 확보: 런타임 벤더가 CRI 구현체만 제공하면 됨
하지만 문제 발생: Docker는 CRI를 직접 지원하지 않음 → Kubernetes가 dockershim 임시 어댑터 개발
6단계: 표준화의 필요성 (2015-2017년)
🔴 문제상황
런타임 간 호환성 부재
Docker, rkt, containerd 등 각각 다른 방식으로 동작
컨테이너 이미지 포맷이 런타임마다 다름
A 런타임에서 만든 이미지가 B 런타임에서 실행 안 되는 경우 발생
벤더 락인(vendor lock-in) 위험성
🟢 해결책: OCI(Open Container Initiative) 표준 제정
2015년 6월 OCI 설립
Docker와 CoreOS(rkt 개발사)가 주도
목표: 컨테이너 런타임과 이미지 포맷 표준화
결과: 런타임 간 상호 호환성 보장
runc 개발 (2015년)
OCI 표준을 구현한 로우레벨 런타임
Docker의 libcontainer를 OCI 표준에 맞게 재작성
containerd가 libcontainer 대신 runc 사용으로 변경
7단계: dockershim의 관리 부담 (2018-2020년)
🔴 문제상황
임시방편의 한계
dockershim은 원래 "임시" 해결책이었는데 계속 사용됨
Docker가 CRI를 직접 지원하지 않아서 Kubernetes 팀이 어쩔 수 없이 유지보수
복잡한 호출 체인: kubelet → dockershim → Docker API → containerd → runc
Kubernetes 팀에게 Docker 관련 버그까지 떠안기는 부담
성능 오버헤드와 아키텍처 복잡성
🟢 해결책: Docker 지원 중단 결정
2020년 12월 Kubernetes 1.20에서 dockershim deprecated 선언
"Kubernetes 1.24에서 dockershim 제거 예정"
2년간의 마이그레이션 기간 제공
containerd, CRI-O 등 대안 런타임 권장
하지만 사용자 커뮤니티에서 큰 우려 표출 - 많은 기업이 Docker 기반으로 시스템 구축했기 때문
8단계: 커뮤니티의 대안 제시 (2021-2022년)
🔴 문제상황
현실적인 마이그레이션 어려움
수많은 기업들이 Docker 기반으로 운영 중
containerd로 전환하는 데 시간과 비용 필요
개발자들의 Docker 도구 친숙도
기존 CI/CD 파이프라인의 Docker 의존성
🟢 해결책: cri-dockerd 프로젝트
Mirantis와 커뮤니티 협력
dockershim을 Kubernetes에서 분리하여 독립 프로젝트로 개발
cri-dockerd: Docker를 CRI 호환으로 만들어주는 어댑터
오픈소스로 제공하여 Docker 사용 지속 가능
결과: 사용자들이 자신의 일정에 맞춰 점진적으로 전환할 수 있게 됨
9단계: 최적화된 구조로의 진화 (2019-현재)
🔴 문제상황
여전히 비효율적인 구조
Docker 사용 시: kubelet → cri-dockerd → Docker → containerd → runc
불필요한 중간 계층들로 인한 성능 오버헤드
복잡한 의존성 체인
실제로는 containerd만 있으면 충분한 상황
🟢 해결책: 직접 연결 아키텍처
containerd의 CRI 플러그인 개발
containerd에서 CRI 인터페이스 직접 지원
단순화된 구조: kubelet → containerd → runc
중간 계층 제거로 성능 향상 및 안정성 개선
현재 권장 아키텍처
Kubernetes 1.24부터 dockershim 완전 제거
containerd가 가장 널리 사용되는 런타임
CRI-O, Firecracker 등 다양한 선택지 제공
🎯 현재 상황 정리 (2025년)
📊 런타임 선택지
런타임특징주 사용처containerd가장 일반적, 안정적대부분의 Kubernetes 클러스터CRI-ORed Hat 주도, OCI 호환OpenShift, 엔터프라이즈 환경Docker + cri-dockerd레거시 지원기존 Docker 기반 시스템
🏗 현재 아키텍처 계층
Kubernetes (kubelet)
↓ CRI
High-level Runtime (containerd, CRI-O)
↓ OCI
Low-level Runtime (runc, firecracker)
↓
Linux Kernel (cgroup, namespace, chroot)
🔄 발전 과정의 패턴
전체 발전 과정을 보면 다음과 같은 패턴을 발견할 수 있습니다:
복잡함 → 단순함: 어려운 기술을 쉽게 사용할 수 있게 개선
단일 선택 → 다양한 선택: 한 가지 솔루션에서 여러 대안으로 확장
표준화: 혼재된 기술들을 통일된 규약으로 정리
최적화: 불필요한 복잡성 제거하고 성능 개선
각 단계의 변화는 모두 실제 사용자들이 겪은 구체적인 문제를 해결하기 위한 필연적 진화였습니다. 기술적 완벽함보다는 실용성과 사용자 경험을 우선시한 결과가 현재의 성숙한 컨테이너 생태계를 만들어냈습니다.
현재의 아키텍처는 이러한 시행착오를 통해 완성된 안정적인 구조로, 앞으로도 컨테이너 기술 발전의 견고한 기반이 될 것입니다.
댓글을 작성해보세요.