Kubernetes for appliation developers - 1. 쿠버네티스 구조
Kubernetes for application developers(LFD459)
1. 쿠버네티스 구조
1-1. 쿠버네티스란?
컨테이너를 데스크탑에서 실행하는 것은 쉽다. 하지만 여러 호스트에 다운타임 없이 스케일링 하며 배포하고 연결하는 것은 어렵다.
쿠버네티스는 분산 시스템을 탄력적으로 실행하기 위한 프레임워크를 제공한다. 스케줄러와 API 서버를 통해 새로운 오브젝트와 오퍼레이터를 다양한 프로덕션 요구에 맞게 커스터마이징 할 수 있다.
쿠버네티스는 CI/CD 의 필수적인 부분이 될 수 있다. Helm, Jenkins 를 사용해 다양한 환경에서 소프트웨어를 테스트하고 배포하는 일관된 방법을 제공한다.
그리고 다양한 환경에서 소프트웨어를 배포하는 방법을 제공한다. 쿠버네티스는 업데이트와 롤백을 쉽게 하도록 컨테이너의 라이프 사이클과 인프라 리소스에 연결을 다룬다.
1-2. 쿠버네티스의 구성
전통적으로 모노톨릭한 어플리케이션이 전용 서버에 배포되었다. 트래픽이 증가하면 어플리케이션은 수정되고 더 큰 리소스를 가진 전용 서버로 옮겼다. 트래픽을 처리하기 위한 많은 수정이 어플리케이션에 되었다.
요즘은 큰 서버를 사용하는 대신 쿠버네티스를 활용해 작은 서버 여러 개를 배포한다. 서버에 replicas 로 불리는 여러 마이크로 서비스 형태로 배포한다.
결합도가 높은 httpd 데몬을 여러 개 가진 아피치 서버 대신 서로의 존재를 모르는 nginx 서버가 자주 사용된다.MSA 구조를 위해 서비스와 API 호출을 사용한다. 서비스는 어플리케이션에서 다른 어플리케이션으로 트래픽을 연결하고 IP 나 다른 정보를 다룬다.
서비스는 죽게 되면 다른 서비스로 대체되어야 한다.
1-3. 쿠버네티스의 도전 과제
컨테이너(도커)는 개발자가 컨테이너 이미지를 쉽게 만들고 레지스트리를 사용해 공유하고 관리하도록 한다.
그러나 컨테이너를 마이크로 서비스 원리로 스케일링하고 분산 어플리케이션 구조를 짜는 것은 여전히 어렵다.
CI 파이프라인으로 컨테이너 이미지를 만들고 테스트해 검증해야 한다. 그리고 컨테이너를 실행하기 위한 클러스터가 필요하다.
또한 컨테이너를 실행하고 다운 되었을 때 복구할 시스템이 필요하다. 뿐만 아니라 롤백하거나 업데이트도 가능해야한다.모든 기능들은 유연하고 스케일링 가능해야 하며 네트워크와 스토리지를 쉽게 관리할 수 있어야 한다.
워커 노드에 컨테이너가 실행되면 네트워크는 리소스와 다른 컨테이너에 연결되어야 한다. 그리고 스토리지를 유지, 재사용하는 원활한 방법을 제공해야 한다.
1-4. Borg
- 구글은 자신들이 제공하는 어플리케이션을 관리하기 위한 내부 시스템인 Borg 를 15년간 운영한 경험을 통해 쿠버네티스를 만들었다.
1-5 쿠버네티스 구조
쿠버네티스를 배포하면 클러스터를 얻는다.
쿠버네티스 클러스터는 컨테이너화된 애플리케이션을 실행하는 워커 노드를 포함한다.
모든 클러스터는 최소 한 개의 워커 노드를 가진다. 워커 노드는 애플리케이션의 구성요소인 파드를 호스트한다.컨트롤 플레인 노드는 워커 노드와 클러스터 내 파드를 관리한다. CP 노드는 API 서버, 스케줄러, 다양한 기능 그리고 클러스트의 상태와 컨테이너와 네트워크 설정 등의 데이터를 저장할 저장소를 가진다.
kubectl 이라는 명령어로 CP 노드의 API 서버에 명령을 내릴 수 있다.
kube-scheduler 는 API 요청을 확인하고 새로운 컨테이너를 스케줄해 실행한다.
클러스터 내 각 노드들은 kubelet, kube-proxy 두 개의 컨테이너를 기본으로 실행한다.
kueblet 은 컨테이너의 컨테이너 설정, 필요한 리소스 다운로드 및 관리 그리고 컨테이너 엔진 동작을 위해 스펙 정보를 받는다.
kube-proxy 는 컨테이너를 네트워크로 드러내기 위한 방화벽 정책, 네트워크 설정을 관리한다.쿠버네티스에서 컨테이너를 동작, 관리하는 과정은 이벤트를 통해 동작한다.
1-6. 용어
클러스터는 리소스 공유와 분배를 위해 여러 노드를 묶은 그룹이다.
노드는 쿠버네티스에서 최소 단위의 컴퓨팅 하드웨어 이며, 하나의 개별머신이다. 컨트롤 플레인 노드와 워커 노드 두 종류가 있다. 파드는 노드에서 실행된다.
컨테이너는 하나 이상의 프로세스 모음이다.
파드는 고유한 IP 주소와 DNS 명 그리고 스토리지, 네임 스페이스를 공유하는 한 개 이상의 컨테이너로 구성되어 있다. 일반적으로 한 파드는 한 개의 컨테이너를 가진다.
오케스트레이션은 컨테이너를 배포, 확장하고 관리를 자동화 해주는 도구이다. 오케스트레이션은 오퍼레이터(컨트롤러)로 관리된다.
디플로이먼트 는 로컬 상태가 없는 파드를 실행해 복제된 애플리케이션을 관리하는 API 오브젝트이다.
레플리카셋은 같은 스펙 정보로 여러 파드를 배포한 오퍼레이터이다.
데몬셋(DaemonSet) 은 모든 노드에 1개 씩 생성되고 노드가 추가되면 자동으로 이미지를 추가해 준다. 주로 로그, 모니터링, APM 등이 사용된다.
스테이트풀셋(StatefulSet) 파드들을 특정한 순서로 배포할 때 사용한다.
레이블 오브젝트를 식별하기 위한 태그이다. 오브젝트의 메타데이터 중 하나이다.
어노테이션 오브젝트를 식별 하는데 사용할 수 없다. 오브젝트에 메타데이터를 첨부할 때 사용하는 키-밸류 쌍이다.
네임스페이스는 쿠버네티스에서 하나의 클러스터 내에 리소스 그룹의 격리를 지원하기 위해 사용하는 추상적인 개념이다.
서비스는 파드에서 실행 중인 애플리케이션을 네트워크 서비스로 노출하는 방법을 추상화 한 것이다.
1-7. Control Plane Node
- 컨트롤 플레인 노드는 클러스터를 위한 여러 서버와 매니저 프로세스를 실행한다. CP 노드는 클러스터에 대한 전반적인 결정을 수행하고 클러스터 이벤트를 감지하고 반응한다.
1-7-1. kube-apiserver
쿠버네티스 클러스터의 내부 및 외부 요청을 처리한다. API 요청은 인증, 권한, 승인 절차를 통해 수행된다.
etcd 데이터베이스에 연결되어 있는 유일한 개체이다.
1-7-2. kube-scheduler
- 파드의 리소스 요구사항과 함께 클러스트의 상태를 고려해 적절한 노드에 파드를 실행한다. 그리고 taints, tolerations, 파드의 레이블을 참고해 파드가 실행될 적정한 노드를 선택한다.
1-7-3. Etcd Database
클러스터의 상태, 설정, 네트워크 및 그 외의 정보를 저장하는 키-값 저장소이다.
쿠버네티스 클러스터 정보를 백업할 때 etcd 데이터베이스 만 백업하면 된다.
1-7-4. kube-controller-manager
kube-apiserver 와 상호작용해 클러스터의 상태를 결정한다. 상태가 맞지 않으면 적정한 컨트롤러를 사용해 원하는 상태로 수정한다. kube-control-manager 에는 아래 컨트롤러를 포함한다.
노드 컨트롤러 : 노드가 다운되었을 때 대응한다.
레플리케이션 컨트롤러 : 레플리케이션에 맞는 파드의 수를 유지한다.
엔드포인트 컨트롤러 : 서비스와 파드를 연결하는 역할을 한다.
네임스페이스 컨트롤러 : 네임스페이스를 관리한다.
1-7-5. cloud-controller-manager
- 클라우드 서비스 회사가 만들어 배포한다. 클라우드 공급자의 API 에 연결하고 해당 클라우드 플랫폼과 상호 작용하는 컴포넌트와 클러스터와 상호 작용하는 컴포넌트를 구별한다.
1-8. Worker Nodes
- 워커 노드는 kubelet, kube-proxy 그리고 도커와 같은 컨테이너 엔진을 실행한다. 동작 중인 파드를 유지시킨다.
1-8-1. kubelet
- 각 노드에서 실행되는 에이전트로 컨테이너가 파드에서 실행되게 한다. CP 노드에서 워커 노드에 작업을 요청하는 경우 워커 노드의 kbuelet 이 작업을 실행한다.
1-8-2. kube-proxy
클러스터의 각 노드에서 실행되는 네트워크 프록시로 쿠버네티스 서비스의 구현이다.
노드의 네트워크 규칙(iptable 등)을 관리해 클러스터 외부에서 파드로 또는 클러스터 내부에서 파드 간 통신할 수 있도록 해준다.
1-9. Pods
리눅스 컨테이너를 하나 이상 모아 놓은 것으로 쿠버네티스 애플리케이션의 최소 단위이다.
리소스를 효율적으로 공유하기 위해 컨테이너를 파드로 그룹화 한다. 같은 파드에 속한 컨테이너는 동일한 컴퓨팅 리소스를 공유한다.기본적으로 파드 내의 컨테이너는 병렬적으로 실행된다.
따라서 어떤 컨테이너가 먼저 사용 가능 한지 알 수 없다.
initContainers 를 사용하면 파드 내 특정 컨테이너가 실행 완료된 후 다른 컨테이너가 실행 되도록 할 수있다.파드는 랜덤으로 지정되는 한 개의 고유한 IP를 가지고 있다. 그리고 파드 내 여러 컨테이너가 있다면 컨테이너들은 같은 IP 를 공유한다.
파드 내 컨테이너 간에 통신 하려면 IPC, loopback 인터페이스 또는 파일 시스템 공유를 활용한다.보통 한 개의 파드에 한 개의 컨테이너를 실행하지만 로깅이나 보안 등 보조하는 태스크를 담당하는 컨테이너를 함께 실행하는 경우가 있다.
이런 경우 사용하는 패턴을 sidecar 패턴이라고 한다.파드는 제네레이터를 통해 실행되거나 JSON 이나 YAML 파일을 통해 생성, 삭제될 수 있다. 또는 오퍼레이터/watch-loop 를 통해 실행될 수 있다.
kubectl run newpod –image=nginx –generator=run-pod/v1
kubectl create -f newpod.yaml
kubectl delete -f newpod.yaml
1-10. Services
파드 그룹의 단일 진입점을 제공한다.
여러 파드 사이에서 인바운드 요청을 분산하는 NodePort 나 LoadBalancer 같은 마이크로 서비스이다. 그리고 서비스는 인바운드 요청의 접근 정책을 관리한다.
서비스는 어떤 오브젝트를 연결하는지 알기 위해 레이블 키와 값을 동등 비교 하거나 in, notin, exist 같은 연산자를 사용한다.
서비스는 지정된 IP 로 생성이 가능하고 고유한 DNS 이름을 가질 수 있다.
서비스는 네 가지 타입을 제공한다.
1) ClusterIP : 파드 그룹의 단일 진입점인 가상 IP 를 생성한다.
2) NodePort : ClusterIP 를 생성하고 각 워커 노드에 설정한 포트를 연다.
3) LoadBalancer : NodePort 동작을 포함한다. 그리고 클러스터 외부의 로드밸런서와 NodePort 를 연결해 준다.
AWS, AZURE 등 클라우드 플랫폼에서 사용할 수 있다.
4) ExternalName : 클러스터 내부에서 네이밍 서비스를 사용할 수 있도록 지원한다.
1-11. Operators
오퍼레이터는 쿠버네티스 어플리케이션을 패키징, 배포 및 관리하는 방법이다. 현재 상태를 질의하고 스펙과 비교한다. 상태가 스펙과 다른 경우 어떻게 동작할 지 작성된 코드에 맞게 동작한다.
오퍼레이터는 쿠버네티스 API 기능을 확장해 애플리케이션 인스턴스 생성, 설정 및 관리한다.
1-12. Single IP per Pod
파드는 기본적으로 랜덤으로 생성된 고유한 IP 한 개를 가진다.
파드는 컨테이너들과 관련된 데이터 불륨이 함게 위치한 그룹이다. 파드 내 모든 컨테이너들은 같은 네트워크 네임스페이스를 공유한다.
Pause 컨테이너는 파드 내부 컨테이너들의 일종의 부모 컨테이너로서 리눅스 네임스페이스를 공유할 수 있도록 해준다.
그리고 pid 네임스페이스 공유가 설정되었을 때, 파드에서 initProcess(pid 1) 로서의 역할과 좀비 프로세스를 정리하는 기능을 수행한다.파드 내에서 컨테이너 간에 통신하기 위해 IPC, loopback 인터페이스 또는 공통 파일시스템에 write 하는 방법을 사용한다.
1-13. Networking setup
네트워크 관점에서 파드는 한 개의 VM 이나 물리적 호스트로 보여진다. 따라서 쿠버네티스의 네트워크는 파드에 IP 를 할당하고 모든 노드의 모든 파드 간에 트래픽 분배를 해야한다.
파드는 NAT 없이 모든 노드의 모든 파드와 통신할 수 있다.
쿠버네티스에는 해결해야 할 세 가지 네트워크 이슈가 있다.
1) 컨테이너 간 통신 2) 파드 간 통신 3) 파드외 외부 간 통신서비스가 ClusterIP 타입으로 실행되면 가상 IP 를 만들어 파드 그룹의 단일 진입점으로 사용한다.
서비스의 NodePort 타입은 ClusterIP 를 만들고 각 노드의 파드에 설정된 포트를 ClusterIP 와 함께 연다.
클라우드 플랫폼 환경에서 로드밸런서가 있는 경우, 서비스는 LoadBalancer 타입으로 실행해 ClusterIP 를 만들고 NodePort 를 만들어 클러스터 외부 로드밸런서와 연결한다.Ingress 컨트롤러는 요청을 적절한 서비스로 전달하는 역할을 한다.
1-14. CNI Network 설정 파일
Container Network Interface 는 파드 간 네트워크를 제어할 수 있는 플러그인을 만들기 위한 인터페이스 이다. 쿠버네티스는 kubenet 이라는 단순한 CNI 플러그인을 제공한다.
보통 3rd party 플러그인을 사용하는데 Flannel, Calico 등을 사용한다. 쿠버네티스 네트워크에 오버레이 네트워크를 구성해준다.
오버레이 네트워크는 노드 간의 네트워크 위해 별도의 네트워크 레이어를 구성한다.
1-15. Pod to Pod 통신
파드 내 컨테이너들은 pause 컨테이너가 만든 가상 인터페이스를 통해 호스트의 docker0 브리지 네트워크로 연결된다.
노드로 요청이 도착하면 호스트의 eth0 을 거쳐 docker0 브리지를 통해 veth0 으로 전송된다. 그 다음 veth0 에 연결된 컨테이너의 eth0 로 전달된다.
클러스터 내 각각의 워커 노드에 있는 파드가 서로 통신할 때, 10.100.0.2 워커 노드와 10.100.0.3 워커 노드 내 파드 둘 다 172.17.0.2 로 같은 IP 를 가지기 때문에 문제가 있다.
이 문제를 해결하기 위해 오버레이 네트워크를 지원하는 3rd party CNI 를 사용한다.
각 파드는 오버레이 네트워크 상에서 IP 를 할당 받고 그 IP 를 통해 서로 통신할 수 있다.