강의 정보
- 러닝스푼스에서 2023년 4월 ~ 6월 간 강의한 쿠버네티스 딥다이브 2기 를 듣고 정리한 내용입니다.
강의 필기록 원본이라 글이 좀 어수선할 수 있습니다.
컨트롤러 이야기
컨트롤러?
- Spring 에서 MVC 의 Controller 는 왜 Controller 인가? Spring 에서는 HTTP Handler 를 왜 Controller 로 이름붙였을까?
- 리모컨 즉 Remote Controller 는 에는 왜 Controller 라는 이름이 붙는가?
- 컴퓨터에서 메모리 컨트롤러는 왜 컨트롤러인가?
컨트롤러란
- 컨트롤러는 서로 다른 두가지 계 (System) 사이에서 둘 간의 인터렉션이 원활하게 이루어질 수 있게 하기 위한 것: 즉, System 을 연결하기 위한 Component 이다
- Spring 에서는 Controller 는 HTTP System 와 자바 시스템을 연결지어주기 위한 컴포넌트
- 리모컨은 사람과 TV 를 연결지어주기 위한 컴포넌트
- 메모리 컨트롤러는 속도가 빠른 CPU 와 비교적 속도가 느린 메모리 를 연결지어주기 위한 컴포넌트
Kube-controller
쿠버네티스에서의 컨트롤러
- 일반적인 컨트롤러는 위와 같지만, 쿠버네티스에서는 의미가 좀 다르다.
- 이전에 공식문서에서 본것처럼 쿠버네티스 컨트롤러는 기계공학에서의
Open Loop System
와 유사하고, 이것은 상태를 지속적으로 체크하여 현재 상태가 원하는 상태로 유지될 수 있도록 한다.
Kube-controller 잡담
- 처음에는 Kind 별로 MSA 형식으로 개발되었으나 서비스가 너무 많아지면서 하나의 바이너리로 합쳐버린놈
- 레플리카가 여러개 있어도 Active-standby 로 관리되기에 여러개 배포한다고 성능향상이 되지 않는다
- Kube-controller 의 podgc 가 pod evitction timeout 과 관련된 작업을 하는듯
- 노드 장애시 Kubelet 이 응답하지 않기 때문에 Pod 가 삭제되지 않는데 이를 위해 podgc 가 kubelet 이 응답이 없을 경우에 notreadytoleration 이었나 등의 시간이 지난 뒤에 삭제하는 것을 담당한다.
- Kube-controller 는 Kube-apiserver 만 바라보고 있기 때문에 굳이 클러스터 내부에 있을 필요가 없다.
- EKS 에서는 Kube-controller 가 클러스터 내부에 없고 모든 EKS 클러스터의 Kube-controller 들만을 구동시키기 위한 중앙 클러스터에 배포된다
기본적인 Object 소개
Deployment
- Deployment 는 기존의 Replicaset 과 동일하나, 단순히 replica 개수만이 아니고 Pod template 이 변경되는것 또한 주시하고 있다는 차이점이 있다
이 생성되는 과정 간단히
- YAML 을 작성하여 Kubectl 로 전달해주면 Kubectl 이 Kube-apiserver 로
HTTP_POST
요청을 보냄 - Kube-apiserver 는 defaulting 을 하고 나서 etcd 에 저장 요청을 보냄
- etcd 는 저장한 후에 저장되었다는 이벤트를 kube-apiserver 로 보냄 (watcher?)
- kube-apiserver 는 deployment 가 생성되었다는걸 publish 함
- 그럼 kube-controller 가 해당 msg 를 subscribe 하고 있으므로 메세지를 수신
- Kube-controller 는 replicaset 을 생성하는 요청을 apiserver 로 보냄
- 후략 (#draft 나중에 더 적어라)
잡담
- Deployment 는 podTemplate 으로 hash 를 계산해서 replicaset 을 생성
- 따라서 podTemplate 이 변경되었을 때는 hash 가 변경되므로 해당 이름을 가지는 replicaset 을 새로 생성하여 변경점이 반영되도록 한다.
- Informer: MQ 에서 메세지가 유실되는 문제때문에 etcd 와 병렬적으로 etcd 왜 동기화되는 캐시를 구동하는데 이를 위해 뭐 어쩌고 했는데 기억이가 안남..#draft
StatefulSet
- STS 의 pod 는 이전에는 pet 으로 불렸음
- K8s 에서 리소스는 rancher, 즉 가축처럼 다룬다: 죽어도 별 감흥이 없음
- 하지만 죽으면 문제가 되는 리소스가 있을 수 있고 이에 따라 죽으면 안되는, 소중히 다뤄줘야 한다는 의미로 pet 이라는 의미를 붙인거
DaemonSet
- Daemonset update strategy:
- Rolling update: pod 을 자동으로 하나씩 갈아끼우는 것
- Ondelete: pod 갈아끼우기를 관리자가 직접 해주는 것
- 가령 예를 들면, ingress controller 를 daemonset 을 배포한 상황에서
- 노드를 LB 의 멤버로 제외를 시켰다 해도 실제로 노드에 트래픽이 안들어오기까지는 시간이 오래 걸릴 수 있다
- 하지만 rolling update 를 하면 update 되는 동안에는 해당 노드로 들어오는 트래픽이 유실됨
- 그래서 일단 LB 멤버로 제외한 이후 트래픽이 안들어오는 것을 확인한 뒤에야 명시적으로 pod 를 삭제해서 재실행 될 수 있도록 해주기 위함
Pod lifecycle
podSpec
- Ephermeral Container: 파드를 디버깅하기 위해 컨테이너를 잠깐 띄워볼 수 있는 기능
- Termination grace period: SIGTERM 을 준 후 이 기간이 지날 때 까지 안죽었으면 SIGKILL 을 줘서 컨테이너 강제종료
- Service Account: pod 가 apiserver 에 접근할 수 있는 권한 부여
- hostNetwork, hostPid, hostIpc: 각각에 대해 격리하지 않고 노드와 공유 유무
- Priority:#draft
- ReadinessGate:#draft
- bind:#draft
- podLifecycle.preStop:#draft
실습
- pod 시작할 때 요청 거절: Container 가 시작되었지만 아직 트래픽을 받을 수 있는 상황이 아닌데 트래픽이 pod 로 흘러들어가는 상황
- Readiness probe 생각보다 잘 작동한다: pod 생성했을 당시에는 503이 뜨는 경우가 있었는데 readiness probe 를 설정하니까 503이 안뜲
- +) 503에 대한 고찰: port 가 안열려 있어 TCP CONN 이 안되면 reset 패키지가 날라오고 그러면 ingress controller 에서 503 을 보내게 되는 것
- pod 삭제될 때 요청 거절: 마찬가지로 Container 가 죽었지만 service endpoint 에서는 제외되지 않아 트래픽이 흘러들어가는 상황
- 문제상황
- green 을 종료했을 때 잠깐동안 503이 뜨다가 30초간 트래픽이 유실된다
- 문제 원인
- pod 삭제하면 port 정리 -> SIGTERM -> ip 제거 순서로 처리되는데
- port 정리되면 당연히 reset 패킷에 의해 TCP Refuse 가 되고 IC 가 503을 반환
- SIGTERM 으로 프로세스가 죽은 뒤에 ip 가 제거되면 IC 입장에서는 이제부터는 TCP Refuse 가 아닌 Timeout 이 나기 때문에 멍청하게 기다리게 된다
- 근데 IC 와 Client 간에는 TCP CONN 이 맺어져 있기 때문에 불필요한 커넥션이 소모된다
- 최악의 경우에는 이게 쌓여서 리눅스의 TCP CONN 을 모두 차지하게 되어 Timeout 동안 노드 자체에 트래픽이 막혀버리는 상황이 된다
lifecycle.prestop
:- 이게 내가 잘 이해한게 맞는지 모르겠는데
- prestop 으로 SIGTERM 이전에 특정 작업을 수행하도록 할 수 있고
- 이때
exec: [“sleep ‘30’”]
을 하게 되면 - 아마 readiness probe 실패 -> endpoint 에서 제거 -> sleep 기간 + SIGTERM 이후의 기간동안 이쪽으로 트래픽이 안와서 timeout 혹은 refuse 없이 파드가 정리되는거같음 (이건 좀 더 찾아봐야겠다..)
- 가 아니라 deletiontimestamp 가 설정이 안되어 있어야 endpoint 에서 제거되는데 delete 명령을 날리게 되면 deletetimestamp 가 설정되고 endpoint 에서 제거되서 트래픽이 안감 -> 따라서 pod 는 여전히 ready 상태이지만 엔드포인트에서 빠져 트래픽이 안가게 되는거
- 문제상황
- 참고) 1.27 부터 resource request, limit 이 immutable 에서 mutable 로 되어 런타임중에 cgroup 을 수정해 자원사용을 건들 수 있다