K8s from scratch - 2. 쿠버네티스 구성 요소
쿠버네티스 클러스터를 이루는 구성 요소들은 파드 형태로 이루어져 있습니다.

K8s Cluster Architecture

마스터노드 (Control-Plane)
- kubectl
- 쿠버네티스 클러스터에 명령을 내림. 마스터노드에 있을 필요는 없지만 통상적으로 API서버와 통신하므로 API서버가 위치한 마스터노드에 구성하였습니다.
- api-server
- 클러스터의 중심역할을 하는 통로입니다. 상태값을 저장하는 etcd와 주로 통신합니다.
- etcd
- 구성요소들의 상태값이 모두 저장되는곳입니다. 분산저장이 가능한 키-밸류 저장소이므로 복제본을 둔다면 etcd에서 장애가 나더라도 가용성을 확보할 수 있습니다.
- controller-manager
- 클러스터의 오브젝트 상태를 관리합니다.워커노드에 통신이 안되는경우 상태 체크와 복구는 컨트롤러 매니저에 속한 노드 컨트롤러에서 이루어집니다. 또한 레플리카셋 컨트롤러는 레플리카셋에 요청받은 파드 개수대로 파드를 생성합니다. 서비스와 파드를 연결하는 역할 또한 컨트롤러 매니저가 하는일 입니다.
- scheduler
- 노드의 상태와 자원, 레이블, 요구조건 등을 고려해 파드를 어떤 워커노드에 생성할 것인지에 대해 결정하고 할당합니다.
워커노드
- kubelet
- 파드의 구성내용을 받아서 컨테이너 런타임으로 전달하고, 파드안의 컨테이너들이 정상적으로 작동하는지 모니터링 합니다.
- Container Runtime Interface (Containerd)
- 파드를 이루는 컨테이너의 실행을 담당합니다. 컨테이너가 문제없이 작동하게 만드는 표준 인터페이스입니다.
- Pod
- 한개 이상의 컨테이너로 단일 목적의 일을 하기 위해서 모인 단위입니다. 웹서버나 로그 분석, 데이터 분석 컨테이너등을 예로 들 수 있습니다. 파드는 언제라도 죽을 수 있는 존재입니다.
선택 가능한 구성요소
- CNI
- 쿠버네티스 클러스터의 통신을 위해서 네트워크 플러그인을 사용해야합니다. 본 문서에서는 위브넷(WeaveNet)을 사용합니다.
- CoreDNS
- CNCF에서 보증하는 프로젝트로 , 빠르고 유연한 DNS서버입니다. 쿠버네티스 클러스터에서 도메인 이름을 이용해 통신하는데 사용됩니다.
쿠버네티스 구성 요소의 기능
kubectl
kubectl 명령을 사용해서 노드들의 정보를 확인해보도록하겠습니다. kubectl은 어디에 있더라도 API서버의 접속 정보만 있다면 쿠버네티스 클러스터에 명령을 내릴 수 있습니다.
ubuntu@master001:~$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-5d78c9869d-dpxlk 1/1 Running 0 10d
kube-system coredns-5d78c9869d-wnjnw 1/1 Running 0 10d
kube-system etcd-master001 1/1 Running 0 10d
kube-system kube-apiserver-master001 1/1 Running 0 10d
kube-system kube-controller-manager-master001 1/1 Running 0 10d
kube-system kube-proxy-dhgrf 1/1 Running 0 10d
kube-system kube-proxy-f9tj6 1/1 Running 0 10d
kube-system kube-proxy-shwnf 1/1 Running 0 10d
kube-system kube-scheduler-master001 1/1 Running 0 10d
kube-system weave-net-vfkv4 2/2 Running 0 10d
kube-system weave-net-wrtdm 2/2 Running 1 (10d ago) 10d
kube-system weave-net-zqllr 2/2 Running 0 10d
ubuntu@master001:~$
kubelet
kubelet은 쿠버네티스에서 파드의 생성과 상태 관리 및 복구를 담당합니다. 때문에 문제가 생기면 파드가 정상적으로 관리되지 않습니다.
테스트를 위해 파드를 하나 배포해보도록 하겠습니다.
ubuntu@master001:~$ kubectl run nginx --image=nginx
pod/nginx created
ubuntu@master001:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 39s
ubuntu@master001:~$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 46s 10.36.0.1 slave002 <none> <none>
ubuntu@master001:~$
배포된 노드인 slave002에 접속하여 kubelet서비스를 중단해보도록 하겠습니다.
ubuntu@slave002:~$ sudo systemctl stop kubelet
ubuntu@slave002:~$
다시 마스터 노드에 접속하여 파드를 삭제해보도록 하겠습니다.
ubuntu@master001:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2m54s
ubuntu@master001:~$ kubectl delete pod nginx
pod "nginx" deleted
^Cubuntu@master001:~$
응답이 없어 ^C(Control+C)를 입력하여 중지하였습니다. 다시 파드의 상태를 확인합니다.
ubuntu@master001:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Terminating 0 3m56s
ubuntu@master001:~$
Terminating 하고있지만 삭제되고있지 않습니다. 다시 워커노드로 접속하여 kubelet을 복구합니다.
ubuntu@slave002:~$ sudo systemctl start kubelet
ubuntu@slave002:~$
마스터노드에 접속하여 파드가 삭제되었는지 확인합니다.
ubuntu@master001:~$ kubectl get po
No resources found in default namespace.
ubuntu@master001:~$
kube-proxy
kube-proxy는 파드의 통신을 담당합니다. 본 문서에서는 br_netfilter커널모델을 적재하고 Iptables를 거쳐서 통신하도록 설정했습니다.
테스트를 위해 마스터노드에서 파드를 배포해보도록 하겠습니다.
ubuntu@master001:~$ kubectl run webserver --image=nginx
pod/webserver created
ubuntu@master001:~$
파드의 IP와 워커노드를 확인합니다.
ubuntu@master001:~$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
webserver 1/1 Running 0 44s 10.44.0.1 slave001 <none> <none>
ubuntu@master001:~$
curl로 메인페이지 내용을 확인합니다.
ubuntu@master001:~$ curl 10.44.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
ubuntu@master001:~$
파드가 실행되고 있는 워커노드에 접속하고(slave001) br_netfilter모듈을 제거하고 내용을 적용하여 kube-proxy에 문제가 생기는 상황을 임의적으로 만들어보겠습니다.
ubuntu@slave001:~$ sudo modprobe -r br_netfilter
ubuntu@slave001:~$ sudo systemctl restart systemd-networkd
마스터노드에서 다시 웹페이지를 받아오도록하겠습니다. 요청을 못받아오는것을 확인할 수 있습니다.
ubuntu@master001:~$ curl 10.44.0.1
curl: (7) Failed to connect to 10.44.0.1 port 80: No route to host
ubuntu@master001:~$
다시 워크노드로 접속하여 br_netfilter를 적재하고 시스템을 다시시작하여 적용하도록 하겠습니다.
ubuntu@slave001:~$ sudo modprobe br_netfilter
ubuntu@slave001:~$ sudo reboot
Connection to 10.0.142.128 closed by remote host.
Connection to 10.0.142.128 closed.
bastion_ubuntu@ip-10-0-11-75:~$
마스터노드에서 파드를 다시 확인해보면 RESTART가 증가한것을 확인할 수 있습니다.
ubuntu@master001:~$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
webserver 1/1 Running 1 (36s ago) 10m 10.44.0.1 slave001 <none> <none>
ubuntu@master001:~$
다시 curl명령을 실행하여 정상적으로 웹페이지를 받아오는지 확인합니다.
ubuntu@master001:~$ curl 10.44.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
ubuntu@master001:~$