본문 바로가기
개발공부 개발새발/Kubernetes

kubernetes ) 구성

by 휴일이 2025. 5. 26.

목적

  • 워커 노드 → 쿠버네티스를 loading 할 수 있는 배
  • 마스터 노드 → 적재, 적재를 계획, 선박 식별, 정보를 저장하고 위치는 감시 등등…컨테이너 관리, 모니터링

마스터 노드

 

ETCD : 클러스터의 핵심 데이터 저장소

  • key, value 로 클러스터의 상태 정보를 저장하는 데이터베이스.
    • 노드 정보, 파드 상태, 네임스페이스, 서비스, 엔드포인트 … 등등

kube-scheduler : 파드를 클러스터 내의 적절한 노드에 할당해주는 kubernetes 의 기본 스케쥴러

  • pending 상태인 파드를 보고 어떤 노드가 이 파드를 실행할 수 있을지 결정하는 머리 역할

Node controller , Replication Controller : 상태 불일치를 감지하고 자동 조정하는 “컨트롤 루프” 방식으로 동작

  • Node controller : 노드 관리, 새 노드를 클러스터에 온보딩하고 노드가 사용 불가능한 상황 처리
  • replication controller : 원하는 컨테이너 수가 레플리케이션 그룹에서 항상 실행되도록 보장

Controller Manager : 여러 컨트롤러를 하나의 프로세스로 실행함. (Node controller , Replication Controller)

Kube ApiServer : 클러스터 내에서 모든 작업들을 관리 (오케스트레이팅)

Docker : 컨테이너를 실행할 SW (runtime engine)

kubelet (선장) : 컨테이너의 모든 활동 관리. 선박에 합류할 의사가 있다, 컨테이너의 정보를 받고 적재하고 컨테이너의 상태를 보고..

  • 클러스터의 각 노드에서 실행되는 에이전트
  • kube api 의 지시를 듣고 노드에서 컨테이너 배포, 파괴
  • kube api 가 큐블렛의 주기적으로 상태 보고서를 가져옴

kube proxy : (노드와 컨테이너끼리의 통신) 워커노드의 실행 규칙

도커와 container d

이전엔 도커, 이젠 컨테이너디

도커 스토리

쿠버네티스는 처음에 도커 컨테이너를 오케스트레이션 하기 위해 존재했다. 그러나 이젠 다른 컨테이너 런타임이 필요했다.

CRI (Container Runtime Interface) 를 만들어 쿠버네티스를 컨테이너 런타임으로 작업하게 해줌(OCI 를 지키며 → OCI-Open Container Initative)

이미지펙 → 이미지를 어케 만들어야하는가? : 이미지 빌드 방식에 대한 기준

  • 누구나 이 기준을 지키며 이미지를 빌드하고 쿠버네티스를 사용할 수 있도록

그러나 도커는 CRI 표준을 지키기 위해 만들어진 것이 아님.

dockershim : 쿠버네티스가 도커를 지원하기 위해 만들어진 인터페이스

  • 도커는 CRI 를 지키지 않기 때문에…

도커가 활용하는 컨테이너d 는 CRI 호환이 가능하고 다른 런타임처럼 쿠버네티스와 직접 작업 가능

지금은 쿠버는 도커심을 지원하지 않고 컨테이너d 를 사용함. → 지금은 도커는 지원 런타임에서 제거됨.

컨테이너디

Docker 를 설치하지 않아도 컨테이너디로 컨테이너만 설치할 수 있다.

  • 컨테이너디를 설치하면 ctr 이라는 명령줄 도구를 사용할 수 있다.
    • 컨테이너를 디버깅하기 위해 만들어졌음.
    • 제한된 기능만 지원해서 사용자 친화적이지 않음.
    • 컨테이너와 상호작용하려면 api 를 직접 호출하는 수밖에..
    • 그래서 사용자 친화적인 nerdctl 을 사용함 → Docker 와 유사, 도커가 지원하는 거의 모든 옵션을 지원함.
    • 컨테이너디에 구현된 최신 기능에 엑세스 가능! : 암호화된 컨테이너 이미지 사용하거나 lazy 이미지 로딩도 됨
  • crictl(CRI) 사용 : 명령줄 유틸리티, CRI 호환 가능한 컨테이너 런타임과 상호작용 (쿠버와 상호작용)
    • 디버깅 툴임 → 이걸로 컨테이너를 만들거나 하는 건 아님.
    • 이걸 통해서 컨테이너를 만들면 큐블렛이 그걸 삭제할거임 → 왜 ? 내가 모르는 컨테이너와 포트가 보이면 다 삭제..
    • pull image, images, ps -a, exec -it , logs, pods 명령 등을 사용 (도커와 유사하죠?)

요약

ctr 인터페이스는 컨테이너디와 함께 제공되고 작동됨 → 디버깅 목적으로 매우 제한된 기능 이상적으로는 전혀 사용하지 않음

nerdctl → 걍 도커임 컨테이너를 만들고 도커CLI 와 비슷하게 작동 굿굿 ㅋㅋ

crictl → 쿠버네티스 커뮤니티에서 만듬. CRI 호환 가능한 런타임과 상호작용할때 사용 (통틀어 작동)

그냥 스토리

→ 쿠버는 오픈 소스, 도커는 영리 기업

오픈 소스인 쿠버네티스가 영리 기업인 도커 뒷바라지(?) 하는 게 맞냐? → 자체 오픈소스인 컨테이너디를 사용하자.

  • 컨테이너 엔진이 별개의 스펙을 쓰는 게 아니라 도커가 빌드한 이미지도 띄울 수 있음.
    • 컨테이너디가 도커 이미지를 띄운다.
  • 컨테이너랑 이미지는 다르고 컨테이너디는 도커의 스펙을 충실하게 따라서 뭐로 빌드하던 차이가 없다.
  • 컨테이너디를 직접 로컬에 띄울 필요는 없다.
  • 도커 이미지를 땡겨와서 그걸 컨테이너디로 작업하고 쿠버네티스를 사용하는 것이어서 도커는 계속 쓰는 것이라고 생각하면 됨.
그런 고로 도커 공부를 게을리할 이유가 없다…

ETCD

쿠버네티스의 모든 상태 정보를 저장하는 분산 키-값 저장소

쿠버네티스에서 ETCD 의 역할은?

  • 클러스터에 대한 정보를 저장한다.
    • 노드, 포트, 설정, accounts, roles …
  • 클러스터에 노드가 추가되거나 할 때 포드 배포할 때마다 서버에 업데이트 됨. ETCD 에 업데이트 되어야 진정으로 상태가 변경됐다고 볼 수 있음 (최종)

사용자가 따로 운영하는 방식은 아니다.

[사용자 kubectl 명령]
        ↓
  [Kube API Server]
        ↓
       [etcd]
        ↑
[Scheduler, Controller Manager]

그냥 Control plane (쿠버의 두뇌)와 연결되어 있고 일부라고 보면 됨.

  • 파드를 띄우고 애플리케이션이 도는 곳과는 별개로, 쿠버의 정보를 저장하고 관리하는 곳

예시

  1. nginx 에 파드 3개를 띄우는 명령을 쿠버네티스에게 한다.
  2. API Server 가 이 요청을 etcd 에 저장한다.
  3. Scheduler 가 이 정보를 기반으로 적절한 노드에 파드 스케쥴링 한다.
  4. 컨트롤러가 파드 개수를 계속 모니터링하다가 3개가 안 되면 다시 띄운다.
  5. 파드 상태도 ETCD 에 업데이트 된다.

→ ETCD 가 없으면 쿠버네티스는 기억을 못해서 동작을 못 함.

kube api server

쿠버네티스 클러스터의 모든 명령이 들어가는 입구.

  • kubectl 명령을 실행하면 kube api server 에 요청이 도달하고, 요청을 인증하고 유효성을 확인한 후 ETCD 에서 정보를 얻어 그 정보로 응답한다.
  • kubectl 명령 말고 직접 api 를 호출할 수도 있음!
  • 모든 요청을 받고 상태를 ETCD 에 기록한다.

모든 요청은 kube api server 로 도달한다.

pod 생성 요청

# kubectl
kubectl apply -f pod.yaml

# REST Api
POST /api/v1/namespaces/default/pods

→ kubectl 로 포드를 만들든, 직접 api 를 호출하든 결국 api server 를 통해서만 클러스터와 소통할 수 있다.

  1. 인증(Authentication) : 이 사용자가 누구인지 확인
  2. 권한 확인(Authorization) : 이 사용자가 파드를 만들 권한이 있는지 확인
  3. 유효성 검사(Admission) : 보안 정책, 리소스 할당 같은 규칙 적용

ETCD 에 기록

요청이 유효하면 API Server 는 ETCD 에 “파드가 생성되어야 한다”는 정보 저장.

  • 파드를 아직 띄우지 않았지만 기록만 일단 저장.

kube-scheduler

큐브스케쥴러가 api 서버를 계속 watch 하고 있다가 아직 어느 노드에도 배치되지 않은 파드를 발견하면..

  1. 적절한 노드를 선택(예:메모리 많은 노드)
  2. api 서버에 이 파드는 노드1에 띄워야한다고 알려줌.

→ 이 때도 ETCD 에 상태 업데이트가 들어감

kublet 이 실행

노드1에 있는 큐블렛이 노드를 띄우라는 명령을 받았으니 api server 를 통해 정보를 가져온다.

  1. 컨테이너디에게 지시함.
  2. 컨테이너디는 실제 실행을 함.

상태 보고 & 반복

  1. 파드가 성공적으로 실행되면 큐블렛은 현재 상태를 api server 에 보고
  2. api server 는 그 상태를 ETCD 에 기록
  3. kubectl get pods 로 확인할 수 있는 상태가 이거임!

항상 → API Server → etcd → scheduler/controller → kubelet → 상태 보고 패턴 반복

kube controller manager

컨트롤러 : 리소스의 현재 상태를 원하는 상태로 맞춰주자 → (모니터링) 상태를 감시하고 문제가 생기면 조치를 취하자

큐브 컨트롤러 매니저 : 여러 컨트롤러를 관리하는 중앙 관리자 프로세스

  • 노드 컨트롤러
    • 노드의 상태를 감시하고 애플리케이션이 계속 실행되도록 필요한 조치를 취함. → kube api server 를 통하여
  • 복제 컨트롤러 (replication controller)
    • 레플리카셋의 상태를 모니터링 원하는 수의 포드가 셋 내에서 항상 사용 가능하도록 함
      • 파드가 죽으면 다른 파드 실행

→ 실제로는 개별 프로세스가 아니라 하나의 바이너리 프로세스 안에 다 모여 있음. api server 를 watch 하면서 변화가 생기면 자동으로 대응함.

동작 원리

  1. api server 에서 리소스 watch(감시)
  2. 현재 상태를 읽어옴
  3. 원하는 상태와 비교
  4. 차이가 있으면 조정 (ex: 파드 생성, 삭제 등)

노드 컨트롤러

클러스터 내 노드의 생존 여부(상태) 를 감시하고, 노드가 다운됐을 때 파드를 다른 노드로 옮기거나 삭제 함.

  • kublet 이 주기적으로 하트비트 보냄
  • 노드 컨트롤러는 이 하트비트를 api 서버를 통해 감시
  • 일정 시간 이상 하트비트가 없으면 → 노드를 Not Ready 상태로 변경
  • 그 노드에 있던 파드를 다른 노드로 스케쥴링.

레플리케이션 컨트롤러

설정한 갯수 만큼 파드 수를 유지시켜주는 컨트롤러, 지금은 ReplicaSet 으로 대체 됨.(기능은 유사)

아키텍처

      [사용자] ---> [API Server] <--- [kubectl apply, etc.]
                          ↑
                          ↓ watch
      +------------------------+
      | kube-controller-manager|
      |                        |
      |  ├── Node Controller   |--- 감시: 노드 상태
      |  ├── Replication Ctrlr |--- 감시: 포드 개수
      |  └── 기타 컨트롤러들    |
      +------------------------+
                          ↓
                      [etcd 저장소]
                          ↑
                          ↓
                  [kubelet on Node]

예시 : nginx 레플리카 3개를 유지하고 싶은데 파드 1개가 죽었을 때

  1. 사용자가 nginx deployment 생성 (replicas: 3)
  2. kube-api server 가 요청을 받아 ETCD 에 저장.
  3. Replication controller (혹은 ReplicaSet Controller)가 상태 확인
    1. 현재 nginx 파드 중 1개 죽어 있음.
  4. 파드 수가 부족 → 새 파드 생성 요청
  5. scheduler 가 노드에 파드 할당.
  6. kublet 이 해당 파드 실행.
  7. 상태가 변경 되면 ETCD → api server → 유저 확인 가능.

kube-scheduler

어떤 파드가 어떤 노드에 들어갈지 결정 함.

왜 필요?

kubectl 로 파드를 만들면, 그 파드는 아직 어느 노드에 띄울지 모르는 채로 생성.

  • 전체 노드의 상태를 확인하고
  • 자원이나 조건을 고려해서
  • 가장 적절한 노드를 선택(스케줄링)해준다.

결정법

어떤 파드를 가지고 그 파드에 맞는 가장 적합한 노드에 파드를 놓는다.

CPU 가 10 필요한 노드가 있을 경우

  1. 리소스로 필터링
    1. CPU 가 10 필요한 파드가 있다면, CPU 자원이 4인 노드에는 둘 수 없다.
    2. CPU 리소스가 10 과 같거나 10 보다 큰 노드에 파드가 들어가도록 결정한다.
  2. 가장 적합한 노드 고르기
    1. 노드에 점수를 매겨서 제일 적합한 노드 찾음.
    2. 파드를 놨을 때 리소스가 많이 남는다 → 12 파드보단 16 바드가 더 많이 남는다.

아키텍처

                        +-----------------+
                        |   kubectl apply |
                        +--------+--------+
                                 |
                                 v
                      +----------+-----------+
                      |     Kube API Server  |
                      +----------+-----------+
                                 |
                      (파드: nodeName 없음)
                                 |
                                 v
                +-------------------------------+
                |         kube-scheduler        |
                +---------------+---------------+
                                |
             (1) 후보 노드 필터링
             (2) 점수 계산 및 정렬
             (3) nodeName 결정
                                |
                                v
                    [API Server에 업데이트]
                       (파드에 nodeName 할당)
                                |
                                v
               +------------------------------+
               |       kubelet on nodeX       |
               +------------------------------+
                                |
                     (컨테이너 런타임으로 실행)

kublet

배의 선장, 선내의 모든 활동을 지휘한다!

쿠버네티스에서 파드를 실행하고 관리하는 에이전트. ”명령을 받으면 직접 실행! 상태 보고! 문제가 나면 스스로 복구!”

내부 동작

  1. api 서버 감시
    • 이 노드에 배치된 파드가 있는가?
  2. 실행 대상 발견
    • 내가 실행해야 할 파드는?
  3. containerd 등에 실행 요청
    • containerd, docker 등에게 “이 이미지로 컨테이너 띄워줘” 요청
  4. 상태 감시 + 보고
    • 컨테이너 상태가 running , crashLoopBackOff 인지 확인하고
    • API Server 에 주기적으로 보고
  5. 프로브 수행
    • 파드에 설정된 헬스 체크 실행
    • 상태 이상이면 재시작하거나 서비스에서 제외

왜 중요?

  • kublet 이 없으면 파드 실행되지 않음.
  • kublet 은 할 일 목록을 직접 실행하는 사람임.

kube-proxy

쿠버네티스 노드에서 서비스를 외부 또는 내부 트래픽과 연결해주는 네트워크 라우터

왜 필요?

파드는 동적으로 계속 생겼다가 사라지고 IP 도 계속 바뀜.. 그럼 어디로 요청을 보내야 되?

  • 서비스 IP 로 요청을 보내면 kube-proxy 가 알아서 뒤에 있는 파드로 연결시켜줌.

역할

  • 서비스 라우팅 : 서비스 IP → 실제 파드 IP 로 연결해줌
  • NAT 처리 : 외부 IP 에서 들어온 트래픽을 내부 파드로 전달
  • 클러스터 DNS 와 연결 : 클러스터 IP 로 트래픽 보낼 수 있도록 처리
  • iptables / IPVS 설정 : 실제 라우팅 처리는 커널 레벨에서 함.

→ kublet 이 파드를 실행시키면, kube-proxy 가 그 파드로 요청이 잘 전달되도록 경로를 만들어줘

728x90