🚀 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 → runccontainerd가 실제 컨테이너 라이프사이클 관리 담당🟢 해결책 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 → runcKubernetes 팀에게 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)🔄 발전 과정의 패턴전체 발전 과정을 보면 다음과 같은 패턴을 발견할 수 있습니다:복잡함 → 단순함: 어려운 기술을 쉽게 사용할 수 있게 개선단일 선택 → 다양한 선택: 한 가지 솔루션에서 여러 대안으로 확장표준화: 혼재된 기술들을 통일된 규약으로 정리최적화: 불필요한 복잡성 제거하고 성능 개선각 단계의 변화는 모두 실제 사용자들이 겪은 구체적인 문제를 해결하기 위한 필연적 진화였습니다. 기술적 완벽함보다는 실용성과 사용자 경험을 우선시한 결과가 현재의 성숙한 컨테이너 생태계를 만들어냈습니다.현재의 아키텍처는 이러한 시행착오를 통해 완성된 안정적인 구조로, 앞으로도 컨테이너 기술 발전의 견고한 기반이 될 것입니다.