728x90
반응형

서버 관리 == 서버의 상태관리

서버가 갑자기 죽거나, 다운되면 문제가 생긴다. 이런 문제가 생겼을 때 매번 서버에 들어가서 다시 키고 재설정해주려면 서버 관리자는 낮밤이 없어진다.. 그리고 해당 서버를 누구에게 인수인계한다고 했을 때, 모두 설명하기에 너무 어렵다.

그래서 처음에는 해당 내용을 문서로 관리하였다. 그러나 문서는 한계가 있다. 업데이트도 잘 안되고, 관리도 어렵다.

그 뒤에 나온것이 서버 관리를 코드로 하는 방법이였다. 이 때 CHEF, ansible, puppet과 같은 도구들이 나온다. 그런데 이런 도구들 사용법도 난이도가 너무 높아서 다른 방법을 고안해야 했다. 이때 고민한 점이 '어떻게 한 개의 서버에서 여러 개의 버전들을 잘 돌릴 수 있을 것인가의 문제였다.'

가상 머신을 사용하면 해결된다. 그런데 가상머신 또한 지금의 클라우드 환경에 맞지 않고 특정 벤더에(VirtualBox, VMWare)에 의존성이 생긴다. 이때 나온것이 도커와 컨테이너이다.

도커, 컨테이너

도커와 컨테이너는 가상머신과 비교하여 컨테이너 생성이 쉽고 효율적이다.

https://jobdong7757.tistory.com/192

 

도커, 도커 엔진, 컨테이너, 가상 서버, 도커 데몬

도커 컨테이너를 실행하거나 컨테이너 이미지를 만들고 배포하는 플랫폼 도커는 응용 프로그램을 실행 환경 단위로 패키지화해서 컨테이너 이미지를 만듬 컨테이너 이미지는 컨테이너 레지스

jobdong7757.tistory.com

쿠버네티스 등장배경 - '컨테이너'만으로 서비스 실행의 한계점

  1. 컨테이너 관리
    컨테이너 안에 배포되어서 애플리케이션이 실행되는 환경일 때, 각각의 컨테이너를 관리하려면 직접 하나씩 들어가야 한다.

만약 컨테이너가 몇백개, 몇천개가 된다면 절대 불가능한 일이다. 또한 만약 컨테이너들을 새로운 버전으로 업데이트하거나 롤아웃, 롤백해야할 경우가 생긴다면 컨테이너가 많을수록 수행하기가 어렵다.

  1. 서비스 검색

proxy 기능을 하는 nginx 서버 하나와 web 서버를 하나 운영하고 있다고 가정해보자.
그런데 갑자기 web 서버가 하나 늘게 되었다. 그럼 사용자는 새로 로드밸런서를 설치해서 proxy가 로드밸런서를 바라보게 할 수는 있는데, 내부 서비스 간에 통신이 많아지는 경우에는 어려워진다.

컨테이너 오케스트레이션

그래서 복잡한 컨테이너 환경을 효과적으로 관리하기 위한 도구, 기술이 나오게 되었다.

결국 서버 관리자가 하는 일들을 대신해주는 프로그램인 것이다.

컨테이너 오케스트레이션의 특징

1. Cluster

  • 클러스터 안에 여러 개의 노드들, 노드 위에 파드, 파드 안에 컨테이너가 있다고 생각할 수 있다.
  • 그리고 쿠버네티스는 이러한 노드들을 관리할 수 있게 해준다. 노드들도 갯수가 아주 많기 때문에 쿠버네티스는 마스터 노드와 워커 노드를 따로 두어서 마스터 노드에서 모든 워커 노드를 관리할 수 있게 명령어를 보낼 수 있다.

2. State

  • 쿠버네티스는 상태 관리를 해서 컨테이너에 문제가 생기면 없애고 다시 띄우는 것까지 수행한다.

3. Rollback, Rollout

  • 쿠버네티스는 배포 버전을 관리하고 중앙에서 버전을 업데이트 하거나 롤백 할 수 있다.

4. Scheduling

  • 배포 관리를 해주고 어떤 서버에 뭐가 떠있는지, 어떤 서버에 여유가 있는지 알아보는 스케쥴링 기능을 해줘야 한다.

5. Service Discovery

  • 각 서비스들을 등록하고 조회할 수 있다.

6. Volume

  • 컨테이너가 종료되더라도 파일 시스템이 유지되고 싶다면 쿠버네티스 볼륨을 사용할 수 있다. 볼륨은 Pod의 일부분으로 정의되고, Pod와 동일한 라이프사이클을 갖는 디스크 스토리지이다.

=> 물론 컨테이너 오케스트레이션 도구로는 데이즈, 메소스, 노마드, 도커 스웜 등등 있지만 그 중에서 대세는 쿠버네티스이다.

쿠버네티스 아키텍처

만약 사람 한명에게 컨테이너 하나를 띄워달라고 한다면 관리자는 서버 하나에 컨테이너 하나를 띄우면 된다.

이렇게 명령하는 상태를 'Desired State' 즉 원하는 상태라고 한다. 만약 상태 체크를 했는데 명령한 원하는 상태가 아니라면, 조치를 취해야 한다.

여기서 이제 관리자가 '컨테이너 2개를 띄워줘' 라고 한다면 여러 개의 서버 중 어떤 서버가 여유가 있는지 어떻게 더 효율적으로 사용할 수 있는지 고민하게 되는데 이 작업을 '스케쥴러' 가 하게 된다.

그리고 쿠버네티스에는 단순히 컨테이너만 있는 것이 아니고, 네트워크나 노드 등 여러 체크하는 친구들이 필요할 수 있다.

이 친구들을 Controller라고 하고, 관리자는 Controller를 계속해서 뽑아낼 수 있다.

그리고 위에서 말한 'Desired State', 원하는 상태가 여러 개가 있을 수도 있다. 그렇다면 Controller 또한 여러 종류가 될 수도 있다.

지금까지는 비유를 통해서 설명하였다. 여기서 관리자가 되어서 Scheduler나 Controller 같은 애들을 뽑아내는게 API Server가 하는 역할이다. API Server, Controller, Scheduler 등 어떤 상태를 체크하고 실행하는 영역을 쿠버네티스에서는 Master Node가 담당하게 되고, 이것이 실제로 실행되는 부분을 Worker Node라고 하게 된다.

그리고 이런 상태를 저장하고 조회할 수 있는 데이터베이스가 있는데 이 데이터베이스는 etcd라고 해서 Master에 포함된다.

Master Node

1. etcd

  • 쿠버네티스에서 모든 상태와 데이터를 저장
  • 분산 시스템으로 구성하여 안전성
  • Key - Value의 Dictionary 형태로 데이터를 저장
  • 보통은 3대 정도를 띄워놓는다.

2. API Server

  • 상태를 바꾸거나 조회
  • etcd와 유일하게 통신하는 모듈
  • REST API 형태로 제공
  • 권한을 체크하여 적절한 권한이 없을 경우 요청을 차단
  • 관리자 요청 뿐 아니라 다양한 내부 모듈과 통신
  • 수평으로 확장되도록 디자인 되어 있음

3. Scheduler

  • 새로 생성된 Pod를 감지하고 실행할 노드를 선택함.
  • 노드의 현재 상태와 Pod의 요구사항을 체크
    • 노드에 라벨을 부여해서 체크함

4. Controller

  • 논리적으로 다양한 컨트롤러가 존재
    • 복제 컨트롤러
    • 노드 컨트롤러
    • 엔드포인트 컨트롤러
  • 끊임없이 상태를 체크하고 원하는 상태를 유지
  • 복잡성을 낮추기 위해서 하나의 프로세스로 실행

조회 및 수정 흐름

중간에 API 서버가 껴서 통신을 한다.

  1. 컨트롤러는 컨트롤러가 체크하고 있는 상태를 조회할 때, etcd로 바로 요청하는 게 아니라 API 서버에 물어본다.
  2. API 서버는 해당하는 컨트롤러가 해당하는 리소스를 볼 수 있는지 권한체크를 한다.
  3. 권한이 있다고 판단이 들면 etcd에 정보를 조회해서 알려주게 된다.
  4. etcd는 원하는 상태를 변경한 것도 저장이 되니까 만약에 원하는 상태가 변경이 된다면 컨트롤러한테 지금 원하는 상태가 변경이 되었다고 알려주고, 컨트롤러는 현재 상태랑 원하는 상태가 바뀌었기 때문에 조치를 해야 한다.
  5. 그 조치를 해서 리소스 변경을 하고, 리소스 변경된 결과를 전달을 해준다.
  6. API 서버는 변경할 수 있는 쓰기 권한이 있는지 체크해서 권한이 있다면 etcd에 있는 정보를 갱신한다.

Worker Node

워커 노드에는 크게 2가지의 컴포넌트가 있다. kubelet과 proxy가 있는데 두 노드 모두 마스터랑 통신하게 되면 API 서버를 바라보게 된다.
(마이크로서비스하게 잘 되어 있다)

Proxy

  • 네트워크 프록시와 부하 분산 역할
  • 우리가 생각하는 Proxy는 이제 Pod이 요청을 보내기 전에 거쳐가거나, API Server의 요청을 Proxy가 먼저 받는건가? 라고 생각할 수 있는데,
    쿠버네티스에서 처음에 그렇게 설계하였다가 성능상 이슈가 있어서, 프록시라는 애플리케이션을 별도로 띄우지 않았다.
  • 성능상의 이유로 별도의 프록시 프로그램 대신
    → 성능상 이슈가 있었어서 프록시라는 애플리케이션을 별도로 띄우지 않고, 커널 레벨에서 굉장히 빠른 IP 테이블이나 IPVS를 사용해서 프록시가 실제로 하는 역할은 설정만 관리한다.
  • 설정을 관리하고 실제로 프록시와 부하 분산 역할을 하는 것이다.
  • iptables나 ipvs 방식을 사용(설정만 관리)

Kubelet

직접 Pod랑 통신한다.

kubelet은 각 노드에 다 떠있어야 한다. → 계속해서 Pod를 실행하고 중지하고 상태를 체크하기 때문에

  • 각 노드에 다 떠 있어야 한다
  • 각 노드에서 실행
  • Pod를 실행, 중지하고 상태를 체크
  • CRI (Container Runtime Interface)
    • (도커 말고 다른 런타임들도 있음)
    • docker
    • Containerd
    • CRI-O
  • 컨테이너를 사용할 수 있도록 kubelet이 컨테이너를 직접 쓰는 것이 아니라 Pod라는 것으로 감싸서 사용을 하게 된다고 생각할 수 있다.

Pod을 요청하게 되면 실행되는 흐름

  1. Pod 생성을 요청하면 API Server가 받음
  2. API 서버는 etcd에다가 적어놓는다.
  3. 컨트롤러가 새로생긴 Pod이 있는지 요청을 계속 확인하다가('새로 Pod 생성하라는 명령이 있나?' 체크)
    • 새 Pod 요청 확인을 하게 된다.
    • '요청이 들어왔네?'를 확인하고 Controller가 실제 Pod을 할당하는 요청을 한다.
  4. 그럼 API 서버는 다시 요청을 할당 받아서 etcd의 상태를 바꾸게 된다. ('Pod을 할당 요청 해라!')
  5. 그럼 스케쥴러는 계속 할당 요청이 들어온 Pod가 있는지 확인한다. ('Pod에 할당 요청한 명령어 없나?' 체크)
    • Pod에 할당 요청한 명령을 확인하고, 여러 개의 노드 중에서 어디에 띄울까 고민을 하다가 특정 노드에 저 pod를 할당한다.
  6. 그럼 API 서버가 다시 받아서 Pod를 특정 노드에 할당하는데 상태는 아직 실행되기 전 상태다 라고 etcd에 업데이트 한다.
  7. 그럼 Kubelet이 ‘어 내 노드에 할당된 pod 중에서 아직 실행이 안된 Pod가 있나?’ 확인을 계속 한다.
    1. 체크하다가 요청한 명령을 확인하고, 새로 추가된것이니까 pod를 하나 생성하고
    2. 그 정보를 다시 API 서버가 etcd에 업데이트를 해준다.

etcd에는 'POD이 특정 노드에 할당이 되어 있고, 실행 중이다'라는 상태로 지금 최종 업데이트가 되어 있는 상태이다.

계속해서 스케쥴러, 컨트롤러, 큐블렛은 상태를 체크하고 있는 것이다.

만약 새로 상태가 변한 것이 없다면 체크만 하고 넘어가고, 어떤 업데이트하는 과정이 없는 것이다.

추가적인 컴포넌트들

  • CNI(네트워크)
  • DNS(도메인, 서비스 디스커버리)
  • 대시보드(시각화)

[참고]

https://www.inflearn.com/course/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%9E%85%EB%AC%B8/dashboard

728x90
반응형

+ Recent posts