
지난 포스트에서 쿠버네티스가 무엇이고 어떤 기능을 지원하는지 알아봤다. 이번 포스트에선 쿠버네티스의 구조와 무엇이 어떻게 동작하는지에 대해 알아보도록 하자!

먼저 Control Plane은 클러스터의 관제탑 역할을 한다. API Server, Scheduler, Controller-Manager, etcd 크게 네 가지 요소(Component)로 구성되어 있고, 운영자가 명세한 대로 서비스가 운영될 수 있도록 한다.

쿠버네티스 클러스터의 중심이자 유일한 진입점이다. 사용자(kubectl)뿐만 아니라 내부 컴포넌트들도 서로 직접 통신하지 않고 반드시 API Server를 거쳐 정보를 교환한다. 들어오는 요청에 대해 인증, 인가, 유효성 검사를 수행하며, etcd와 유일하게 통신하여 클러스터의 상태 데이터를 저장하고 조회하는 역할을 한다.

Pod가 새롭게 생성이 되면 누가 어떻게 배치할까? 이 기능을 담당하는 것이 Scheduler다. 아직 할당되지 않은 Pod를 최적의 위치(Worker Node)에 배치하는 역할을 수행한다. 이때 적절한 위치를 탐색하기 위해 클러스터 내 존재하는 Worker Node들에 대해 자원 상태를 파악하여 점수를 매기고 적절한 노드를 찾기 위해 필터링하여 Binding 프로세스를 통해 API Server에 알려 Pod를 배치한다.
앞서 쿠버네티스 시스템을 구성하는 모든 요소들은 API Server를 통해 통신한다고 했다. 해당 통신을 통해 클러스터(쿠버네티스 환경을 구성하는 단위)의 상태도 파악할 수 있는데, Controller Manager는 API Server를 통해 클러스터의 상태를 공유 받아 운영자가 명세한 상태와 현재 상태를 비교한다.
만약 상태가 다르다면 이를 일치시키기 위해 동작하는 제어 루프를 백그라운드 프로세스(데몬) 형태로 실행한다.
cf) CCM (Cloud Controller Manager)
Cloud Provider의 API와 Kubernetes 클러스터를 연결하는 Control Plane 구성 요소이다. 클러스터의 Node 상태 등록, Load Balancer 프로비저닝, Route 설정 등 클라우드 인프라에 종속적인 작업을 처리하여, 클라우드 환경에 맞게 Kubernetes 클러스터를 최적화하고 관리한다.
etcd는 고가용성을 보장하는 Key-Value 형태의 저장소로, 쿠버네티스의 모든 클러스터 데이터가 저장되는 유일한 곳이다. Pod가 어떤 노드에 있는지, 클러스터 설정은 어떤지 등 모든 상태 정보가 이곳에 저장된다.
사실상 쿠버네티스의 DB 역할을 수행하므로, etcd가 손상되면 클러스터를 복구할 수 없어 백업과 보안이 가장 중요한 요소다.
Control Plane(Master Node)가 관리자라면, Worker Node는 실제 작업을 수행하는 작업자다. 사용자가 요청한 애플리케이션(컨테이너)이 실제로 실행되는 곳이며, 마스터 노드의 명령을 받아 컨테이너의 생명주기를 관리하고 런타임 환경을 제공한다. 핵심 구성 요소로는 kubelet, kube-proxy, Container Runtime이 있다.
Worker Node마다 존재하는 에이전트로 API Server로부터 Pod 스펙을 전달받아, 실제 컨테이너가 스펙대로 정상 동작하는지 관리한다. 컨테이너 생성과 삭제를 컨테이너 런타임에 지시하고, 주기적으로 상태를 체크하여 그 결과를 다시 API Server에 보고하는 역할을 수행한다.
각 Worker Node에서 실행되는 네트워크 프록시이다. 클러스터 외부/내부의 트래픽을 적절한 Pod로 전달하기 위해 네트워크 규칙을 유지, 관리한다. Service(VIP)로 들어온 요청을 실제 작동중인 Pod IP로 연결 해주고, 이 과정에서 Load Balancing 기능도 수행한다.
cf) Add-ons (CNI & DNS)
사실 kubelet과 kube-proxy만으로는 Pod 간의 통신이 완벽하지 않아 CNI(Container Network Interface), DNS를 Add-on으로 사용한다.
- CNI
od들에게 고유한 IP를 할당하고 통신망을 구축하는 플러그인 (ex. Calico, Flannel)- DNS
IP 대신 도메인으로 통신할 수 있게 해주는 클러스터 전용 DNS 서버
실제 컨테이너 실행과 관리를 담당하는 소프트웨어다. kublet에 명령을 받아 컨테이너 이미지를 가져와 실행하거나 멈춰 컨테이너의 생명주기를 제어한다. docker, containerd, CRI-O(Container Runtime Interface - Open Container Initiative)를 사용한다.

k8s 오브젝트는 선언적으로 원하는 상태를 명세하여 시스템에서 클러스터 상태를 나타내기 위한 영속성을 가지는 객체를 의미한다. 어떤 애플리케이션이 동작 중인지, 어떤 노드에서 동작 중인지, 어떤 리소스를 사용할 수 있는지 등 운영과 관련된 요소가 집약된 형태이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
yaml 파일(Deployment)에 오브젝트 스펙을 기술하여 원하는 동작과 상태를 작성하여 적용한다.
yaml파일에는 다음 네 가지 필드를 필수적으로 포함한다.

기본적인 배포 단위로 하나의 worker 노드에만 속해 동작한다. pod는 하나 이상의 컨테이너로 구성되며, 이 컨테이너들은 네트워크(내부 컨테이너)와 스토리지를 공유한다.

Service는 Pod 집합에 고정적인 네트워크 접근 주소(IP, DNS)를 부여하여 Pod 디스커버리를 가능하게 하는 네트워크 추상화 단위다. Pod의 IP는 언제든 변할 수 있지만, Service의 IP는 유지되므로 안정적인 통신이 가능하다. Service는 Label Selector를 통해 관리할 Pod 대상을 식별하여 백엔드 Pod들의 End Point를 관리하고, 클라이언트로부터 들어오는 트래픽을 이 Pod들에게 로드 밸런싱하여 전달하는 역할을 수행한다.

컨테이너의 디스크 내 파일은 임시적이어서 컨테이너가 crash되고 다시 올라올 때 초기화 된 상태로 올라오는 문제가 있는데 Volume은 데이터 저장이 가능한 디렉토리를 제공하여 이러한 문제를 해결하고 디스크 영속성을 보장한다.
또한 Pod 내 컨테이너끼리 데이터를 공유하여 함께 사용할 수 있도록 해준다.

클러스터 내 논리적 공간 단위이다. 물리적으로 하나인 클러스터를 여러 개의 가상 클러스터처럼 나누어 사용하는 개념이다.
마치 학교에서 과 별로 사용하는 건물을 나누는거처럼 개발, 테스트, 운영 환경을 분리하여 사용할 수 있다. 이를통해 각 서비스 별 개별 접근 권한과 리소스 할당량을 제어한다.
단, Node, PV 등과 같이 여러 오브젝트가 공통으로 사용하는 요소들은 지정할 수 없다.
이번 포스트에서는 쿠버네티스의 구조와 구성 요소들에 대해 알아봤다.
다음 포스트에는 오브젝트들의 동작을 모니터링하고 원하는 상태로 동작하게 만드는 Controller에 대해 알아보도록 하자!