1.1. 정의
컨테이너화된 애플리케이션의 자동 디플로이, 스케일링 등을 제공하는 관리시스템으로, 오픈 소스 기반이다. 원래 구글에 의해 설계되었고 현재 리눅스 재단에 의해 관리되고 있다. 도커를 포함하여 일련의 컨테이너 도구들과 함께 동작한다.
1.2. History
1) 역사를 거슬러 올라간다면 제일 처음 chroot가 등장한다. chroot는 프로세스의 루트 디렉토리를 변경하는 리눅스 시스템콜/명령어로, 1979년 UNIX V7에서 추가되어 원격 유저(FTP, SSH 등)를 특정 디렉터리에 가두기 위한 용도로 사용되었다. chroot는 Change Root Directory의 줄임말로 특정 디렉토리를 ‘루트 디렉토리로 지정할 수 있으며, 루트 디렉터리 밖으로는 못 나가기 때문에 해당 경로에 프로세스를 가둘 수 있다는 점에 착안하였다.
2) 시간이 흘러 지난 2000년 Unix OS인 FreeBSD에서 OS 가상화 기능인 FreeBSD Jail을 발표했다. FreeBSD Jail는 chroot처럼 파일 액세스를 제어하는 것이 아니라 호스트 OS와 Jail라는 OS 가상화 환경에서 파일 시스템 , 프로세스, 네트워크를 분리 할 수있는 획기적인 기술을 제공했다.
3) 2002년 mount ns가 개발되었다. 하나의 시스템에서 수행되지만, 각각 별개의 독립된 공간인 것처럼 격리된 환경을 제공하는 경량 프로세스 가상화 기술인 mount ns는 6개의 종류(mount, UTS, IPC, PID, 사용자, 네트워크)와 플래그가 있다.
4) UTS, IPS NS는 1970년~1990년대에 개발되었지만, 기술의 발전으로 2000년대부터 네트워크관련 기술에 엄청난 성과가 이루어져 초기 컨테이너 기술에도 많은 영향을 끼쳤다.
5) 2008년 PID NS, Cgroup은 Linux kernel 2.6.24에 처음 도입되었다. PID NS는 각 프로세스가 별도의 PID공간을 갖도록 하여 각 프로세스가 다른 프로세스와 독립적으로 프로세스ID를 생성하고 관리할 수 있도록 하며, Cgroup은 각 프로세스 그룹이 별도의 리소스 할당량을 갖도록 하여 각 프로세스 그룹이 다른 프로세스 그룹과 독립적으로 리소스를 사용하고 관리할 수 있도록 하는 역할이다. 이들로 인해 초기 컨테이너 기술에 많은 영향을 끼쳤다.
6) 같은 해에 상기에 놓여진 기술들을 응용하여 IBM에서 LXC(Linux Container)를 처음 발표하였다.
7) 2009년, 2012년에는 Net ns, User ns 각각이 개발되어 컨테이너간의 간섭 방지 및 통신제어로 인한 성능이 보완되었다. 이들의 등장으로 컨테이너 기술은 한층 더 높아졌다.
8) 2013년, Solomon Hykes는 Docker라는 OSS를 출시하였다. Docker는 리눅스의 응용 프로그램들을 소프트웨어 컨테이너 안에 배치시키는 일을 자동화하기 위해 시작된 OSS이며, 컨테이너들을 쉽게 관리하고 신속하게 배포 및 확장할 수 있게 해주는 역할이다.
9) 2014년 9월 9일 Kubernetes가 Google을 통해 개발되어 OSS가 공개되었다. 2015년 1월에 첫 정식 버전인 Kubernetes v1.0이 출시 되었으며, 현재도 지속적으로 업데이트가 진행되고 있다.
1.3. 개발 배경
1.3.1. Traditional Deployment
초기 조직은 애플리케이션을 물리 서버에서 실행했다. 한 물리 서버에서 여러 애플리케이션의 리소스 한계를 정의할 방법이 없었기에, 리소스 할당의 문제가 발생했다. 예를 들어 물리 서버 하나에서 여러 애플리케이션을 실행하면, 리소스 전부를 차지하는 애플리케이션 인스턴스가 있을 수 있고, 결과적으로는 다른 애플리케이션의 성능이 저하될 수 있었다. 이에 대한 해결책으로 서로 다른 여러 물리 서버에서 각 애플리케이션을 실행할 수도 있다. 그러나 이는 리소스가 충분히 활용되지 않는다는 점에서 확장 가능하지 않았으며, 조직이 많은 물리 서버를 유지하는데 높은 비용이 들었다.
1.3.2. Virtualized Deployment
그 해결책으로 가상화가 도입되었다. 이는 단일 물리 서버의 CPU에서 여러 가상 시스템 (VM)을 실행할 수 있게 한다. 가상화를 사용하면 VM간에 애플리케이션을 격리하고 애플리케이션의 정보를 다른 애플리케이션에서 자유롭게 액세스할 수 없으므로, 일정 수준의 보안성을 제공할 수 있다.
가상화를 사용하면 물리 서버에서 리소스를 보다 효율적으로 활용할 수 있으며, 쉽게 애플리케이션을 추가하거나 업데이트할 수 있고 하드웨어 비용을 절감할 수 있어 더 나은 확장성을 제공한다. 가상화를 통해 일련의 물리 리소스를 폐기 가능한(disposable) 가상 머신으로 구성된 클러스터로 만들 수 있다.
각 VM은 가상화된 하드웨어 상에서 자체 운영체제를 포함한 모든 구성 요소를 실행하는 하나의 완전한 머신이다.
1.3.3. Container Deployment
컨테이너는 VM과 유사하지만 격리 속성을 완화하여 애플리케이션 간에 운영체제(OS)를 공유한다. 그러므로 컨테이너는 가볍다고 여겨진다. VM과 마찬가지로 컨테이너에는 자체 파일 시스템, CPU 점유율, 메모리, 프로세스 공간 등이 있다. 기본 인프라와의 종속성을 끊었기 때문에, 클라우드나 OS 배포본에 모두 이식할 수 있다.
컨테이너는 다음과 같은 장점을 갖는다.
● 기민한 애플리케이션 생성과 배포
● 지속적인 개발, 통합 및 배포
● 개발과 운영의 관심사 분리
● 가시성(observability)
● 개발, 테스팅 및 운영 환경에 걸친 일관성
● 클라우드 및 OS 배포판 간 이식성
● 애플리케이션 중심 관리
● 느슨한 결합, 분산, 탄성, 자유로운 마이크로 서비스
1.4. 사용 목적
프로덕션 환경에서는 애플리케이션을 실행하는 컨테이너를 관리하고 가동 중지
시간이 없는지 확인해야 한다. 예를 들어 컨테이너가 다운되면 다른 컨테이너를
다시 시작해야 한다. 이 문제를 시스템에 의해 처리하기 위해 쿠버네티스는 분산
시스템을 탄력적으로 실행하기 위한 프레임 워크를 제공한다. 애플리케이션의
확장과 장애 조치를 처리하고, 배포 패턴 등을 제공한다. 예를 들어, 쿠버네티스는
시스템의 카나리아 배포를 쉽게 관리할 수 있다.
● 서비스 디스커버리와 로드 밸런싱
쿠버네티스는 DNS 이름을 사용하거나 자체 IP 주소를 사용하여 컨테이너를 노출할 수 있다. 컨테이너에 대한 트래픽이 많으면, 쿠버네티스는 네트워크 트래픽을 로드밸런싱하고 배포하여 배포가 안정적으로 이루어질 수 있다.
● 스토리지 오케스트레이션
쿠버네티스를 사용하면 로컬 저장소, 공용 클라우드 공급자 등과 같이
원하는 저장소 시스템을 자동으로 탑재할 수 있다
● 자동화된 롤아웃과 롤백
쿠버네티스를 사용하여 배포된 컨테이너의 원하는 상태를 서술할 수 있으며 현재 상태를 원하는 상태로 설정한 속도에 따라 변경할 수 있다. 예를 들어 쿠버네티스를 자동화해서 배포용 새 컨테이너를 만들고, 기존 컨테이너를 제거하고, 모든 리소스를 새 컨테이너에 적용할 수 있다.
● 자동화된 빈 패킹(bin packing)
컨테이너화된 작업을 실행하는 데 사용할 수 있는 쿠버네티스 클러스터 노드를 제공한다. 각 컨테이너가 필요로 하는 CPU와 메모리(RAM)를 쿠버네티스에게 지시한다. 쿠버네티스는 컨테이너를 노드에 맞추어서 리소스를 가장 잘 사용할 수 있도록 해준다.
● 자동화된 복구(self-healing)
쿠버네티스는 실패한 컨테이너를 다시 시작하고, 컨테이너를 교체하며,
'사용자 정의 상태 검사'에 응답하지 않는 컨테이너를 죽이고, 서비스 준비가
끝날 때까지 그러한 과정을 클라이언트에 보여주지 않는다.
● 시크릿과 구성 관리
쿠버네티스를 사용하면 암호, OAuth 토큰 및 SSH 키와 같은 중요한 정보를
저장하고 관리할 수 있다. 컨테이너 이미지를 재구성하지 않고 스택 구성에
시크릿을 노출하지 않고도 시크릿 및 애플리케이션 구성을 배포 및
업데이트할 수 있다.
1.5. 구성 요소
1.5.1. 컨트롤 플레인 컴포넌트
쿠버네티스 클러스터의 전반적인 제어와 결정을 담당하며 클러스터의 모든 컴포넌트를 관리한다.
● kube-apiserver
kubernetes 컨트롤 플레인의 프론트 엔드로 kubernetes 클러스터로 들어오는 요청을 가장 앞에서 접수하는 역할이다. 클러스터 API를 노출하는 컴포넌트로, 외부와의 주요 인터페이스 역할을 한다.
● etcd
kubernetes 클러스터가 동작하기 위해 클러스터 및 리소스의 구성 정보, 상태 정보 및 명세 정보 등이 필요하다. etcd는 이 모든 정보를 키 값(key-value) 형태로 저장하고 안정적인 동작을 위해 자료를 분산해 저장하는 구조를 채택하여 높은 신뢰성을 가진 분산 데이터 저장소이다.
● kube-scheduler
새로 생성된 피드를 감지하여 어떤 노드에 배치할지 결정하는 작업을 스케줄링이라 하고 이를 담당하는 컴포넌트이다.
● kube-controller-manager
다운된 노드가 없는지, pod가 replicas 숫자를 유지하고있는지, 서비스와
pod가 적절하게 연결이 되어있는지, 네임스페이스에 대한 기본 계정과
토큰이 생성되어 있는지를 확인하고 적절하지 않는 다면 적절한 수준을
유지시키는 클러스터 내의 모든 컨트롤러를 관리하는 컴포넌트이다. 예를
들어 노드 컨트롤러, 레플리케이션 컨트롤러 등이 있다.
● cloud-controller-manager
클라우드별 컨트롤 로직을 포함하는 kubernetes 컨트롤 플레인
컴포넌트이다. 클라우드 공급자와의 상호작용을 처리하는 컨트롤러를 관리한다.
1.5.2. 노드 컴포넌트
노드 컴포넌트는 각 노드에서 실행되며, 실행중인 피드를 유지 및 관리한다.
● kubelet
각 노드에서 실행되는 에이전트로, pod에서 컨테이너가 확실하게 동작하도록 관리한다.
● kube-proxy
각 노드에서 실행되며, 쿠버네티스 서비스 개념을 구현하는 네트워크 프록시이다.
● Container runtime
컨테이너를 실행하기 위한 소프트웨어로, Docker나 Containerd 같은 도구들이 포함된다. kubernetes는 containerd, CRI-O 와 같은 컨테이너 런타임 및 모든 Kubernetes CRI(Container Runtime Interface) 를 지원한다.
1.5.3. 애드온
애드온은 쿠버네티스의 리소스를 이용하여 기능을 확장하고 지원하는 컴포넌트이다.
● DNS
클러스터 내의 DNS 서버로, 기본적으로 파드와 서비스에 대한 DNS 이름 제공을 담당한다.
● 웹 UI (대시보드)
쿠버네티스 클러스터를 위한 범용 웹 기반 UI로,
● 컨테이너 리소스 모니터링
중앙 데이터베이스에 파드와 컨테이너의 메트릭을 기록하고 그 데이터를
열람하기 위한 UI를 제공한다.
● 클러스터 수준 로깅
로그를 중앙 로깅 백엔드에 저장하는 메커니즘을 제공한다.
1.6. 클러스터 아키텍처
1.6.1. 노드
쿠버네티스 클러스터 내에서 컨테이너가 배치되어 실행되는 워커 머신을 의미한다. 각 노드는 컨트롤 플레인에 의해 관리되며, 포드(Pods)를 실행하기 위해 필요한 서비스를 포함하고 있다. 노드에는 주요 컴포넌트로 kubelet, 컨테이너 런타임, 그리고 kube-proxy가 포함된다. 일반적으로 클러스터에는 여러 노드가 있지만 학습 환경이나 리소스가 제한된 환경에서는 하나의 노드만 있을 수 있다.
1.6.2. 컨트롤 플레인-노드 간 통신
쿠버네티스 클러스터에서 API 서버와 노드 간의 통신 경로는 다양하다. 이러한 통신의 주된 목적은 사용자가 네트워크 구성을 강화하여 신뢰할 수 없는 네트워크나 클라우드 제공자의 완전히 공개된 IP에서도 클러스터를 안전하게 운영할 수 있게 하는 것이다.
● 노드에서 컨트롤 플레인까지
○ 쿠버네티스는 "hub-and-spoke" API 패턴을 가지고 있다. 노드(또는 그 위에서 실행되는 포드)에서의 모든 API 사용은 API 서버에서 종료된다.
○ 노드는 API 서버에 안전하게 연결하기 위해 클러스터의 공용 루트 인증서와 유효한 클라이언트 자격 증명을 갖춰야 한다.
○ 포드가 API 서버에 연결하려면 서비스 계정을 활용하여 쿠버네티스가 포드에 공용 루트 인증서와 유효한 bearer 토큰을 자동으로 주입할 수 있다.
● 컨트롤 플레인에서 노드까지
○ 컨트롤 플레인(특히 API 서버)에서 노드까지의 주된 통신 경로는 두 가지로 API 서버에서 각 노드의 kubelet 프로세스까지, 그리고 API 서버의 프록시 기능을 통해 노드, 포드, 또는 서비스까지이다.
○ API 서버에서 kubelet으로의 연결은 포드의 로그를 가져오거나 실행 중인 포드에 연결하는 등의 작업을 위해 사용된다.
○ API 서버에서 노드, 포드, 서비스로의 연결은 기본적으로 평문 HTTP 연결을 사용하므로 인증되지 않았으며 암호화되지 않는다.
1.6.3. 리스 (Lease)
분산 시스템에서 리소스의 독점적 사용 권한을 확보하기 위해 사용하는 메커니즘이다.
● 쿠버네티스는 노드의 상태를 실시간으로 확인하기 위해 Lease API를 사용한다. 이를 통해 노드의 실시간 상태와 가용성을 확인하며 ‘Kube-node-lease’ 네임스페이스에 해당 정보를 저장한다.
● 쿠버네티스에서 여러 컴포넌트 인스턴스 중 하나만 활동 상태로 유지해야 할 때 리스를 사용한다.
1.6.4. 컨트롤러
비종료 제어 루프로, 클러스터의 상태를 지켜보며 현재 상태를 원하는 상태에 가깝게 만들기 위한 변화를 자동으로 요청하거나 직접 수행하는 역할을 한다. 이는 클러스터 내외부의 리소스를 관리하며, 각 컨트롤러는 특정 리소스 유형의 원하는 상태를 추적하고 해당 상태를 달성하기 위해 동작한다.
1.6.5. 클라우드 컨트롤러 매니저
쿠버네티스의 컨트롤 플레인 구성 요소로 특정 클라우드 제공자의 제어 로직을 내장하고 있다. 이 컴포넌트는 사용자의 쿠버네티스 클러스터를 해당 클라우드 제공자의 API와 연결하며, 클라우드 플랫폼과 상호 작용하는 컴포넌트와 클러스터 내부에서만 상호 작용하는 컴포넌트를 분리한다.
1.6.6. CRI(컨테이너 런타임 인터페이스)
CRI는 클러스터 구성 요소를 다시 컴파일할 필요 없이 kubelet이 다양한 컨테이너 런타임을 사용할 수 있게 하는 플러그인 인터페이스이다. 이 인터페이스는 kubelet과 컨테이너 런타임 간의 주요 gRPC 통신 프로토콜을 정의하며, 각 노드에서 kubelet이 Pod와 그 안의 컨테이너를 시작할 수 있도록 작동하는 컨테이너 런타임이 필요하다.
1.6.7. Garbage 수집
쿠버네티스가 클러스터 자원을 정리하기 위해 사용되는 다양한 방법을 종합한 용어이다. 다음과 같은 리소스를 정리한다.
● 종료된 job
● 소유자 참조가 없는 object
● 사용되지 않은 container와 container image
● 반환 정책이 삭제인 storage class에 의해 동적으로 생성된 persistence volume
● stale 또는 만료된 CSRs(CertificateSigningRequests)
● 노드 삭제 조건
○ 클러스터가 클라우드 컨트롤러 매니저를 사용하는 클라우드
○ 클러스터가 클라우드 컨트롤러 매니저와 유사한 애드온을 사용하는 온프레미스
● 노드 리스(lease) object
1.7. 장점
● 기민한 애플리케이션 생성과 배포
VM 이미지를 사용하는 것에 비해 컨테이너 이미지 생성이 보다 쉽고 효율적이다.
● 지속적인 개발, 통합 및 배포
안정적이고 주기적으로 컨테이너 이미지를 빌드해서 배포할 수 있고 (이미지의
불변성 덕에), 빠르고 효율적으로 롤백할 수 있다.
● 개발과 운영의 관심사 분리
배포 시점이 아닌 빌드/릴리스 시점에 애플리케이션 컨테이너 이미지를 만들기
때문에, 애플리케이션이 인프라스트럭처에서 분리된다.
● 가시성(observability)
OS 수준의 정보와 메트릭에 머무르지 않고, 애플리케이션의 헬스와 그 밖의
시그널을 볼 수 있다. 가시성 -> 그라파나
● 개발, 테스팅 및 운영 환경에 걸친 일관성
랩탑에서도 클라우드에서와 동일하게 구동된다.
● 클라우드 및 OS 배포판 간 이식성
Ubuntu, RHEL, CoreOS, 온-프레미스, 주요 퍼블릭 클라우드와 어디에서든
구동된다 런타임이 표준화 되어있다.
● 애플리케이션 중심 관리
가상 하드웨어 상에서 OS를 실행하는 수준에서 논리적인 리소스를 사용하는 OS
상에서 애플리케이션을 실행하는 수준으로 추상화 수준이 높아진다.
○ 네트워크 관리툴
● 느슨하게 커플되고, 분산되고, 유연하며, 자유로운 마이크로서비스
애플리케이션은 단일 목적의 머신에서 모놀리식 스택으로 구동되지 않고 보다 작고 독립적인 단위로 쪼개져서 동적으로 배포되고 관리될 수 있다.
○ 리소스 격리: 애플리케이션 성능을 예측할 수 있다.