[Kubernetes] 쿠버네티스 작동 방식 헷갈려서 정리하는 페이지
쿠버네티스 작동 방식이 헷갈려서 정리하는 과정에서 기록을 하고 싶어서 작성하는 페이지다.
일단 쿠버네티스를 수행하기 위해 minikube, kubectl를 설치했다.
간단히 말하면 minikube는 클러스터이고, kubectl는 쿠버네티스 클러스터를 관리하고 조작하는 CLI(명령어 도구)이다.
쿠버네티스 클러스터 구성 요소는 크게 두가지이다.
Control Plane Node (Master)와 Worker Nodes(Node)이다.
Control Plane Node (Master)
- Master는 설정 환경을 저장하고 전체 클러스터를 관리하는 역할이다.
- Node 클러스터에 존재하는 하나의 머신(컴퓨터)를 의미한다.
- 운영 환경에서 Node는 물리적인 머신이나 클라우드에서 호스트 되는 가상 머신이다.
- 사용자는 kubectl를 사용하여 쿠버네티스 클러스터와 통신을 하게 된다.
Control Plane Node (Master)의 구성요소
Master 내부에는 Api Server, Controller, Scheduler, etcd 가 있다.
1) Api Server
Kubernetes의 API 인터페이스를 제공하는 Frontend 구성 요소이다.
즉, Kubernetes에 생성, 변경, 삭제 및 조회와 같은 모든 API 요청은 ApiServer를 통하게 된다.
2) etcd
etcd는 쿠버네티스의 기본 데이터 저장소이다. etcd는 Key-Value 저장소이다. (ex "pod-a": "Running")
etcd는 클러스터 안의 모든 상태 정보(ex 파드 개수, 어떤 노드에 있는지, 서비스 IP 등)를 저장한다.
etcd는 쿠버네티스의 Control Plane이 읽고 쓰면서 전체 시스템 상태를 파악하고 유지한다.
분산 시스템에서도 데이터 일관성을 보장하여 믿을 수 있으며, 빠르고 가볍다.
1.1 ) 애플리케이션을 실행할 수 있도록 해주는 yaml 파일을 작성하여 kubectl를 이용하여 쿠버네티스 클러스터에 요청을 하게 된다.
1.2 ) 보낸 요청을 Api Server가 받게 되고 etcd에 어떤 상태가 되어야 하는지를 저장한다.
3) Controller
Controller는 Desired State (ex. Pod 개수, 상태) 를 유지하기 위해 지속적으로 클러스터 상태를 감시해 변경 사항이 있는지 확인한다.
Desired State란?
Desired State(원하는 상태)는 관리자가 원하는 환경을 의미한다.
어떤 서비스가 얼마나 많이 서버에 실행하면 좋을지? 몇 번 포트로 서비스 하기를 원하는지 등을 나타낸다.
기본적으로 쿠버네티스는 원하는 상태(Desired State)와 현재 상태(Current State)를 비교한다.
만약 원하는 상태와 현재 상태가 다르다면 현재 상태를 원하는 상태로 변경하는 기능을 수행한다.
즉, 쿠버네티스는 Controller 감시를 통해 항상 우리가 원하는 상태로 현재 상태를 유지할 수 있다.
4) Scheduler
Scheduler는 Controller에서 새로운 워크로드(Pod)를 띄워야 한다고 했을 때, 어느 Node에 배치할지 결정하는 역할을 한다.
Worker Nodes (Node)의 구성요소
각 Node들에는 기본적으로 Kube-Proxy와 Kubelet, Container Runtime이 존재한다.
컨테이너 런타임은 컨테이너 실행을 담당하는 소프트웨어입니다. 일단 여기서는 컨테이너 런타임을 도커로 설정했다.
1) Kubelet
Kubelet은 파드에서 컨테이너가 확실하게 동작하도록 관리한다.
컨트롤 플레인(Master)에서 노드에 작업을 요청하는 경우, Kubelet이 이 작업을 실행합니다.
만약 pod 생성을 요청하게 되면 Kubelet에서 각 노드에 pod를 생성할 수 있도록 Container Runtime에게 요청한다.
Container Runtime이 컨테이너를 성공적으로 생성하고 실행되면 Kubelet은 감시를 시작하게 된다.
이때 Kubelet은 API Server와 컨테이너 런타임을 감시한다.
API Server에 등록된 자신이 맡은 노드의 pod 목록을 주기적으로 조회하거나, 감시한다.
또한, 컨테이너 런타임(Docker, containerd 등)과 통신하여 현재 실행 중인 컨테이너 상태(실행 중, 실패, 준비 완료)를 주기적으로 확인한다.
2) Kube-Proxy
Kube-Proxy는 노드로 들어 오는 네트워크 트래픽을 적절한 컨테이너로 라우팅 한다.
즉, Kube-Proxy는 트래픽을 알맞은 파드로 전달해주는 트래픽 분산기이다.
또한, 로드밸런싱등 노드로 들어오고 나가는 네트워크 트래픽을 프록시 하고, 노드와 마스터 간의 네트워크 통신을 관리합니다.
나는 이게 가장 헷갈려서 더 길게 정리해보았다.
Pod는 생성될 때마다 IP가 바뀐다.
Pod는 언제든지 오류가 발생해 죽을 수 있고, desired state를 유지하기위해 다시 만들어질 수 있다.
이때클라이언트는 매번 pod ip 주소를 알 수 없다. 왜냐하면 언제 이 pod가 죽어서 다시 만들어졌는지 모르니까
그래서 쿠버네티스는 service를 통해 고정된IP 주소를 가지게 된다. (이때 가지는 고정된 IP주소는 ClusterIP이다.)
이 고정된 IP주소를 Pod와 연결이 필요한데, 이 연결을 Kube-Proxy가 한다.
하나의 예를 더 들어보자.
만약 Deployment로 같은 앱 3개를 띄운다고 하자. 그러면 3개의 Pod가 생긴다.
클라이언트는 Service IP에 요청을 보낸다.
Kube proxy는 Service IP를 통해 Pod IP로 라우팅한다. (부하 분산)
이때 같은 앱 3개를 띄워 같은 일을 수행하는 Pod가 3개이니, Kube proxy가 알아서 판단해서 Pod를 정해주기 때문에 부하 분산이라고 하는 것이다. (보통 Round Robin 방식을 사용한다.)
HOW 그렇다면 어떻게 연결을 하는 것일까? 궁금해서 더 찾아보았다.
Kube proxy는 트래픽을 전달할 때, 커널 레벨의 네트워크 기술("패킷 전달 방식" 또는 "트래픽 분산 방식")을 사용한다.
kube-proxy는 iptables 또는 ipvs를 사용해서 서비스 IP → 파드 IP로 트래픽을 보내는 라우팅 테이블을 커널 수준에서 구성한다.
그래서 사용자 애플리케이션이 신경 안 써도 트래픽이 자동으로 전달된다.
두 가지 주요 방식이 있다.
- iptables 모드 (기본)
- iptables 룰을 만들어 놓고, 커널이 해당 룰에 따라 트래픽을 바로 전달하게 한다.
- 사용자는 요청만 보내면, 커널이 알아서 패킷을 파드로 전달한다. (사용자 공간 거치지 않음)
- ipvs 모드 (좀 더 고성능)
- Linux 커널의 IPVS(IP Virtual Server) 기능을 활용한다.
- iptables보다 더 많은 연결을 효율적으로 처리 가능하다.
- 대규모 트래픽 처리에 적합하다.
커널 레벨의 네트워크 기술 외에도 Proxy 방식(사용자 레벨)이 존재한다.
Proxy 방식은 커널 레벨 방식보다 비효율적이다.
커널 레벨 방식은 클라이언트 - service ip - iptables (리눅스 커널이 자동으로 라우팅)- pod a/b/c 이라면,
사용자 레벨 방식은 클라이언트 - proxy 서버 (판단) - 대상 서버로 거쳐 라우팅되기 때문에 proxy 서버를 직접적으로 거치는 방식이다. 이러한 방법은 느리고 성능에 부담을 줄 수 있다.
Pod 하나를 띄우는 과정
쿠버네티스 내부의 여러 개의 마이크로 서비스들이 각자의 역할을 수행하여 동작 한다는 것을 확인할 수 있다.
말로 설명해 보면
kubectl로 API Server에 pod를 생성하라고 명령을 내린다.
API Server → etcd (pod 리소스 정보 저장) → pod 상태가 클러스터 상태에 등록됨
API Server → Controller (상태(desired status) 점검 해라 명령) → API Server에게 보고
API Server → Schedular (Pod를 어느 Node에 배치할지 결정) → API Server에게 보고
해당 Node의 Kubelet이 API Server로부터 Pod 정보 가져옴
Kubelet → Container Runtime에 요청 → Container 생성 및 실행
Kubelet 감시 시작 & API Server에게 보고
*Kube-proxy는 API Server 계속 감시 (service, endpoints 등)하며,
service 생성 또는 수정 시, 노드 내 iptables/ipvs를 즉시 업데이트한다.