쿠버네티스는 컨테이너 기반 환경에서 서비스의 고가용성, 운영, 스케일아웃, 네트워크, 로드밸런싱을 쉽게 할 수 있도록 나온 오픈소스이다.
기업에서 쿠버네티스만을 쓰는 곳은 없고, 관리형 쿠버네티스인 EKS
와 같은 서비스를 이용한다고 한다.
1.24v
이후부터 컨테이너엔진을 골라서 사용할 수 있는데, 그 이전 버전은 도커엔진을 사용하도록 하드코딩 돼있다.
따라서 실습 환경은 1.23v
을 사용할 것이다.
VM 기반으로 클러스터를 구성할 것이며 Control Plane
1대, Worker Node
2대로 이루어져있다.
클러스터의 각 노드들은 각자의 사설IP로 통신하며, TCP/IP 기반의 네트워크 통신을 한다.
K8S는 컨테이너 오케스트레이터로 배포의 단위가 컨테이너가 아닌 상위 개념의 POD
이다.
pod 내부에서는 localhost로 통신이 가능하다.
어플리케이션을 독립적으로 배포하기 위해서 만든 것이 쿠버네티스인데, 의존도가 있는 어플리케이션들을 묶어서 배포하기 위해 pod라는 상위 개념으로 여러 컨테이너와 DB를 묶어 배포한다.
하지만 MSA 환경에서 배포를 진행할 때에는 1 POD , 1 Container로 약속을 해야 적절한 로드벨런싱과 섬세한 스케일아웃이 가능하다.
모든 POD 생성 요청은 Control Plane에서 진행된다.
모든 POD의 요청은 C/P로 전달되기 때문에 이 부분이 부하가 가장 크다.
따라서 API Server 를 부하분산을 시켜주어야 하는데 2개로 해버리면 Data replica 과정에서 오류가 났을 때 무엇이 실패한 명령인지 확인할 수 없다.
따라서 3중화를 통해 과반수가 넘는 설정 파일을 성공한 명령어로 믿고 작업을 진행한다.
POD를 어떤 노드에 배치하는게 최적의 배치인가? 를 처리해주는 K8S의 역할이다.
이와 같은 기능을 위해서는 각 파드끼리 통신하기 위한 CNI ( Container Network Interface )
를 구축해주어야 한다.
kubernetes API를 노출하는 컴포넌트로, kubectl 등으로 부터 리소스를 조작하라는 지시를 받는다.
API 서버는 최종 사용자, 클러스터의 다른 부분 그리고 외부 컴포넌트가 서로 통신할 수 있도록 HTTP API를 제공한다
pod를 어떠한 워커노드에 배치하는게 최적인가를 Scheduler
가 처리해준다.
개발자는 C/P에 pod를 배포해달라는 명령만 내리면 된다.
최적 노드를 선정하는 방식은 etcd
라는 C/P의 DB에 저장돼있는 정보를 통해 확인한다.
이 저장소에는 워커노드의 kubelet
의 정보등과 함께 클러스터에서 발생하는 모든 이벤트들을 저장한다.
각각의 이벤트들을 확인하면서 동일한 파드가 노드에 있는지와 리소스 사용률이 적은 곳을 우선적으로 스케쥴러가 판단해서 파드를 배포한다.
kubelet은 항상 C/P의 etcd를 확인하며 본인의 노드에 주어진 일이 있는지를 확인한다.
배포 요청을 확인하면 docker0
에 요청하고 이미지를 내려 받아서 pod를 띄워준다.
워커노드에서 kubelet이 파드를 배치했을 때 C/P에 요청된 replicas의 수와 같은지 Controller Manager
가 지속적으로 확인한다.
Spring Cloud의 Eureka Server의 기능을 해준다.
k8s는 service
라는 네트워크 요소를 구성할 수 있게 해준다.
서비스를 생성하고 replicas = n
으로 pod들을 배포하면, 각 pod들의 사설IP ( end point ) 들이 서비스의 가상IP와 1:N 맵핑된다.
미리 알고 있는 가상 IP로 서비스를 호출하면 서비스의 EndPoint인 사설IP들 중 하나로 트래픽을 부하분산시켜준다.
이를 도메인 기준으로 설정하게 도와주는 역할을 Core-dns
가 해준다.
가상 IP또한 동적으로 바뀔 수 있기 때문에 DNS가 필요하다.
POD 배포부터 다시 돌아가보자.
C/P에 nginx 컨테이너 배포 요청이 spec.selector.matchLabels.app = myApp
과 함께 왔다고 해보자. replicas = 2 이다.
그러면 C/P는 Core-dns에 myApp : <<가상 IP>>
로 맵핑을 한다.
다음으로 W/N에서는 kubelet이 etcd를 살펴보며 배포요청을 확인하고 이미지를 당겨와 pod를 배포한다.
이때 pod의 end-point를 생성한다.
end-point를 생성할 때 C/P의 Core-dns에도 기입해 가상 IP와 POD End Point가 맵핑되게 한다.
이후 kube-proxy
가 iptables
에 서비스로 이동하는 Rule
을 적용시킨다.
서비스로 요청이 들어왔을 때 iptable이 서비스 가상IP를 보고 직접 부하분산을 진행한다.
kube-proxy가 부하분산을 진행한다는 말도 있는데 직접 부하분산을 진행하는 것은 iptables이지만 룰을 설정해주는 컴포넌트가 kube-proxy 이기 때문에 나온 말이다.
쿠버네티스는 파드의 헬스체크를 할 수 있다.
C/P에 파드 요청을 할 때 파드가 정상인지 체크한다. 사용자가 요청했을 때 파드가 정상이 아니라면, 연결을 해주지 않고 다른 곳으로 부하분산을 해준다.
만일 파드가 문제가 있다면 파드를 내리고 다시 띄워준다.
K8S는 절대로 migration을 하지 않는다. 단순히 새로 배포하는 것이 컨테이너 환경의 주요 메커니즘이며 컨테이너를 stateless
하게 빌드해야 하는 이유이다.
만일 실수로 ec2를 지워버리면 controller manager가 pod의 개수의 이상함을 감지하고, 스케쥴러가 워커노드의 상태를 보고 다른 곳에 배포하는 이벤트를 etcd에 남긴다. 그래서 항상 Contrller manager를 살펴보고 pod를 지워주어야 한다.
Spring Cloud의 Config server 역할을 해준다.
어플리케이션내의 파일 정보를 쿠버네티스의 configMap
에 객체로 만들 수 있다.
즉 어플리케이션내의 환경 설정을 어플리케이션과 분리시켜주는 기능
민감한 정보는 configMap에서 secret 객체가 있는데, Base64로 인코딩해준다. 암호화는 아니다.
etcd에는 시크릿 객체가 암호화돼서 저장돼있다.
실무에서는 네트워크 스토리지는 개발자가 구성해서 사용하는 것은 불가능하다.
어떤 파드를 요청하면 자동으로 스토리지가 생성되고 붙여준다.
파드가 죽거나 삭제되면 파드가 사용하던 스토리지를 죽일지, 살릴지, 보관할지 설정 가능하다.
Cloud와 같이 사용하면 powerful하다.
저도 개발자인데 같이 교류 많이 해봐요 ㅎㅎ! 서로 화이팅합시다!