쿠버네티스(kubernates) 개념

8 분 소요

kubernates

등장 배경

모놀리틱 에서 마이크로 서비스로 전환

모놀리틱 어플리케이션

  • 기존의 모놀리틱 어플리케이션은 모든 것이 강하게 결합되어 있었음
  • 해당 어플리케이션의 한 부분만 수정되어도 전체를 배포해야 했음
  • 시간이 지남에 따라 구성 요소 간의 경계가 불분명해지고 의존성이 커지면서 시스템의 복잡성이 증가
  • 어플리케이션을 수행하기 위한 충분한 성능의 서버가 필요하다
  • scale out 시에는 고려해야 할 부분이 많으며 복잡하다
    • 관계형 DB 는 scale out 이 힘듬

모놑리틱 어플리케이션은 여러 기능을 담당 하고 있기 때문에 특정 API 에 대한 요청이 증가하면 어플리케이션을 scale out 해야한다
그런데 해당 어플리케이션이 DB, Redis 등을 사용하고 있다면 scale out 에 따른 connection 부족 문제가 생길 수 있다
요청이 증가한 API 는 해당 DB, Redis 를 사용하지 않더라도 말이다
(이 부분은 제 개인적인 경험입니다)

마이크로 서비스 어플리케이션(MSA)

  • 모놀리틱 서비스는 이런 저런 이유로 마이크로 서비스로 분할 되어야 한다
  • 각 마이크로 서비스는 독립적인 프로세스로 실행되며 다른 마이크로 서비스와 통신한다
  • 마이크로 서비스는 독립적으로 실행되기 때문에 독립적으로 배포가 가능하다

마이크로 서비스의 단점

  • 어려운 배포
    • 각 서비스간의 상호 의존성이 있기 때문에 배포의 조합 수가 많아 고민이 필요하다
    • 전체 서비스가 하나의 시스템 처럼 동작 할 수 있도록 고려되어야 함
  • 디버깅의 어려움
    • 일반적으로 하나의 어플리케이션으로 구성되는 모놀리틱에 비해 네트워크 통신을 이용하기 때문에 디버깅이 어렵다
    • 다행히 Zipkin 과 같은 분산 추적 시스템으로 해결 가능 함
  • 환경의 다양성
    • 마이크로 서비스는 독립적으로 동작하기 때문에 독립적인 방식으로 개발된다
    • 동일한 서버에서 여러 마이크로 서비스가 동작한다면 서로 다른 버전의 공유 라이브러리가 의존성 충돌이 발생 할 수 있다

어플리케이션에 일관된 환경 제공

각 어플리케이션은 개발 환경과 실행되는 환경이 다르며 실제 운영중인 서버들은 시간이 지남에 따라 환경이 변할 수 있다

  • 이전 글 에서 도커를 사용하는 이유 참고 프로덕션 환경에서만 나타나는 문제를 줄이기 위해 개발과 프로덕션 환경이 정확히 동일하게 실행된다면 미리 문제를 발견할 수 있다

devops

  • 과거 개발 팀은 어플리케이션을 만들고 이를 배포하면 배포된 어플리케이션은 운영팀에서 관리되었다
  • 하지만 개발 팀이 어플리케이션을 배포하고 관리하는 것이 더 낫다는 것을 깨달았다
  • 이렇게 개발 팀이 배포와 관리를 함께 하는 것을 devops 라고 함
  • 개발자가 어플리케이션 실행 환경을 관리하면 사용자가 무엇이 필요하고 어떤 문제가 있는지 더 잘 이해할 수 있다
  • 하지만 개발자가 배포를 하기 위해서는 인프라에 대한 이해가 필요한데 대부분의 개발자는 인프라에 대해 자세히 알지 못하고 알고 싶어 하지도 않음
    • 대게 시스템 관리자가 알아서 관리해주길 원함

쿠버네티스를 사용하면 하드웨어를 추상화 하고 어플리케이션 배포, 실행을 위한 플랫폼으로 제공 할 수 있다
개발자는 쿠버네티스를 이용해 시스템 관리자의 도움 없이도 어플리케이션을 구성, 배포 가능하다
시스템 관리자는 실행되는 어플리케이션에 관계 없이 인프라 운영에만 집중 할 수 있다

컨테이너 오케스트레이션 이란?

쿠버네티스는 컨테이너 오케스트레이션 도구 중 하나인데, 먼저 컨테이너 오케스트레이션에 대해서 알아보자

컨테이너 오케스트레이션은 컨테이너의 배포, 관리, 확장(scale out), 네트워킹 등을 자동화 하는 도구이다
도커의 등장으로 서버 관리를 컨테이너를 이용하여 관리가 쉬어졌다.
하지만 Containerization 만으로는 한계가 존재

배포 문제

도커 컨테이너 위에 돌아가는 어플리케이션을 실행하기 위해서 각 서버에 ssh 로 접속하여 docker stop, run 등을 실행 해주어야 했음

on-promise 환경에서는 어플리케이션 환경 구성을 위해 서버에 직접 설치했음
docker 의 등장으로 환경 구성은 docker container 를 이용하여 관리가 가능하지만 실제 어플리케이션 관리를 위해서 docker 명령어가 필요하다

배포된 어플리케이션을 롤백하려면 이전 버전의 도커 이미지를 수동으로 실행해야함 -> 빠른 롤백의 어려움

서비스 검색(Service Discovery) 문제

일반적으로 운영환경에서는 로드 밸런서를 이용하여 서비스를 구축하는데, 스케일 아웃이 필요하면 로드 밸런서의 설정 업데이트가 필요

  • 새로 등록된 서버 IP 를 추가 해주어야 함

서비스 장애,부하 모니터링의 문제

예상치 못한 부하에 대한 대응을 일일히 사람이 해주어야 함 서비스 장애도 사람이 수동으로 모니터링하여 대응해야 함

이러한 문제점들을 해결하기 위해서 컨테이너 환경을 효율적으로 관리 하기 위해서 등장한 기술이 컨테이너 오케스트레이션 이다

쿠버네티스의 등장

쿠버네티스는 다른 오케스트레이션 도구들에 비해서 비교적 늦게 등장했는데,
기존에 도커 진영에서 개발된 도커 스웜 이 쉽고 간단한 사용법으로 세력을 넓히고 있었고 AWS 에서는 ECS, Hashicorp 에서는 Nomad, Mesos 에서는 Marathon 을 발표했었으나
구글의 컨테이너 관리 노하우가 녹아있는 쿠버네티스가 등장하고 나서는 쿠버네티스가 압도적인 점유율을 자랑하게 되었다
클라우드의 대명사인 AWS, Google Cloud, Azure 등 클라우드 환경에서도 쿠버네티스 관리형 서비스를 내놓은 것만 봐도 그 위상을 알 수 있다

쿠버네티스 vs 도커 스웜

  • 쿠버네티스는 스웜 보다 더 많은 기능을 갖춘 컨테이너 오케스트레이션 시스템 으로 컨테이너 런타임을 다룰 수 있음

쿠버네티스 란 ?

쿠버네티스는 컨테이너를 쉽고 빠르게 배포/확장(scale out) 하고 관리를 자동화 해주는 오픈소스 플랫폼이다

  • 쿠버네티스라는 명칭은 키잡이(helmsman) / 파일럿(pilot)을 뜻하는 그리스어에서 유래 되었다고 함
  • 주로 컨테이너 오케스트레이션 도구라고 불리며 구글 주도로 개발되었음
  • 컨테이너들을 다루기 위한 API 및 CLI 환경을 지원함
  • 단순히 컨테이너 관리 플랫폼을 넘어서 MSA, 클라우드 플랫폼을 지향하고 손쉽게 관리할 수 있는 그릇역할을 수행

쿠버네티스의 특징

  • 서비스 디스커버리와 로드 밸런싱 : DNS 이름을 사용하거나 자체 IP 주소를 이용하여 컨테이너를 노출 가능함
  • 스토리지 오케스트레이션 : 로컬 저장소, 클라우드 저장소 등을 연결하여 사용 가능함
  • 자동화된 롤아웃과 롤백 : 쿠버네티스로 배포된 컨테이너는 원하는 상태 (desired state) 를 서술할 수 있으며 현재 상태를 원하는 상태가 되도록 한다
    ex) 배포시 마다 매번 새로운 컨테이너를 띄우도록 자동화하면 기존 컨테이너를 제거하고 새로운 컨테이너에 모든 리소스를 적용할 수 있다
  • 자동화된 빈 패킹(bin packing) : 컨테이너화 작업을 실행하는데 사용할 수 있는 쿠버네티스 클러스터 노드를 제공함
    각 컨테이너가 필요로 하는 CPU 와 메모리를 쿠버네티스에게 지시하면 쿠버네티스는 컨테이너를 노드에 맞추어서 리소스를 잘 사용할 수 있도록 해줌
  • 자동화된 복구(self-healing) : 쿠버네티스는 실패한 컨테이너를 다시 시작하고, 컨테이너를 교체하며, 응답하지 않는 컨테이너를 죽이는 등 원하는 상태가 되도록 노력한다
    서비스가 준비가 되기 전까지 클라이언트에게 알려주지 않음
  • 시크릿과 구성 관리 : Oauth 토큰 및 SSH 키와 같은 중요한 정보를 저장하고 관리할 수 있음
    컨테이너 이미지를 재구성하지 않고 스크릿 및 애플리케이션 구성을 배포 및 업데이트 가능함

쿠버네티스의 기본 개념

Desired State

Desired_State

  • desired state (원하는 상태) 는 쿠버네티스의 가장 중요한 개념중 하나로 관리자가 바라는 환경을 의마함
  • 관리자는 원하는 서버의 대수, 포트 등의 상태를 정의할 수 있음
  • 쿠버네티스는 현재 상태 (current state) 를 모니터링 하면서 관리자가 정의한 원하는 상태(desired state) 로 유지하려고 내부적으로 이러저런 처리를 수행함
  • 이런 개념때문에 실제 배포시에도 어떤 동작을 명령하는 방식이 아닌 상태를 선언하는 방식을 사용한다
  • ex) nginx 를 실행하라는 명령(imperative) 대신에 nginx 컨테이너 1개를 유지해달라는 상태를 선언(declarative) 한다
  • 이런 차이는 명령에서도 알 수 있음
$ docker run # 명령    
 
$ kubectl create # 원하는 상태 생성 

쿠버네티스의 핵심은 상태이며 쿠버네티스를 사용하려면 어떤 상태들이 있고 어떻게 상태를 선언해야 하는지 알아야 함

쿠버네티스 Object

공식_쿠버네티스 Object
쿠버네티스는 상태를 나타내기 위해서 오브젝트를 이용하며 구체적으로는 아래와 같음

  • 어떤 컨테이너화된 애플리케이션이 동작 중인지 (+어느 노드인지)
  • 그 애플리케이션이 사용가능한 리소스
  • 그 애플리케이션의 재구동 정책, 업그레이드, 문제 발생시 정책 등
    쿠버네티스에는 여러가지 상태를 나타내기 위한 여러 오브젝트를 제공하고 있으며 새로운 오브젝트 추가가 쉬워 확장성이 좋음

쿠버네티스 오브젝트는 상태 외에도 명세(spec) 가 있는데 이것은 오브젝트에 대한 정보를 yaml 로 정의 하고 원하는 상태를 기술하는데 사용함

  • 오브젝트의 명세는 생성, 조회, 삭제로 관리할 수 있어서 REST API 로 쉽게 노출이 가능함

쿠버네티스 오브젝트는 다양한 종류가 있는데, 여기서는 자주 사용되는 몇 가지만 소개함

Pod

공식_쿠버네티스 Pod

node_pod

  • 파드는 쿠버네티스 애플리케이션의 배포가능한 가장 작은 단위로 한 개 이상의 컨테이너와 스토리지, 네트워크 속성이 있음
  • 파드는 노드에 배치되는 컨테이너 그룹의 논리적인 개념이라고 보면됨
  • Pod 에 속한 컨테이너들은 Pod 의 네트워크와 스토리지를 공유하고 localhost 로 서로 접근이 가능함
  • Pod 의 네트워크 인터페이스에는 Node 의 IP 와 연결되기 위한 IP 가 존재함
  • 실제 어플리케이션은 Pod 내부의 container 로 구동되기 때문에 외부에서 접근 할 수 있는 방법을 정의해야 한다

ReplicaSet

공식_쿠버네티스 ReplicaSet
Pod 를 여러 개 복제하여 생성하고 관리하는 오브젝트
레플리카 세트를 이용하면 지정된 수의 레플리카 파드가 유지되도록 보장해줌
일반적으로 레플리카 세트를 직접 사용하기 보다는 아래 나오는 디플로이먼트(Deployment) 를 사용함

공식 도큐에서도 디플로이먼트 사용을 권장하고 있다

Deployment

공식_쿠버네티스_Deployment
디플로이먼트는 레플리카 셋의 상위 개념으로 추가적인 유용한 기능들을 제공하는 오브젝트
ㄴ 파드 개수를 유지 해줄 뿐만 아니라 배포 작업을 좀 더 세분화 하여 관리가 가능함
ㄴ ex) 롤링 업데이트, 블루/그린 배포 등
디플로이먼트에서 의도하는 상태를 기술하면 디플로이먼트 컨트롤러는 현재 상태를 의도한 상태가 되도록 조정한다
ㄴ 일반적으로 애플리케이션 배포에 기본이 되는 단위라고 볼 수 있음

디플로이먼트를 사용해서 애플리케이션을 배포하게 되면 새로운 레플리카 세트가 생성되며 기존에 있던 레플리카 세트는 교체된다

  • pod 의 갯수만 수정한 경우(scale out)에는 기존 레플리카 세트를 그대로 유지한다

디플로이먼트는 레플리카와 가장 큰 차이점으로 리비전 을 갖는데, 이는 배포에 대한 버전이라고 생각하면 된다
디플로이먼트가 업데이트 되면 리비전도 업데이트 된다
ㄴ ex) REVISION=1 -> REVISION=2
롤백을 수행한 경우에 쿠버네티스는 이 리비전을 이용하여 롤백을 수행한다

Service

공식_쿠버네티스_Service
네트워크와 관련된 오브젝트로써 파드를 외부 네트워크와 연결해주고 여러 개의 Pod 를 바라보는 내부 로드 밸런서를 생성할 때 사용한다

말이 좀 어려운데, 왜 필요한지 먼저 살펴보자

  • 쿠버네티스의 파드는 비영구적인 리소스로 디플로이먼트를 이용하여 배포를 수행하면 동적으로 파드가 생성되거나 제거 될 수 있음
  • 각 파드는 고유한 IP 주소를 갖지만, 디플로이먼트 업데이트를 수행하면 기존의 파드는 교체 된다
  • 이것은 파드의 집합을 IP 만으로 찾을 수 없음을 의미한다 > 서비스 디스커버리 불가능

서비스 오브젝트를 이용하면 클러스터 내부/외부에서 클러스터 상에 존재하는 파드 집합을 찾을 수 있도록 서비스 디스커버리 역할을 수행함
ㄴ 서비스 Object 는 일반적으로 파드 집합을 식별하기 위한 셀렉터 가 필요함
ㄴ 헤드리스 서비스(headless service) 라는 셀렉터를 지정하지 않는 서비스도 존재함

서비스 오브젝트의 Type

  • ClusterIP
    서비스 생성시 type 을 ClusterIP 로 지정하여 클러스터의 고유한 IP 를 지정 가능
    ㄴ type 의 기본값
    ClusterIP 는 클러스터 내부에 IP 를 노출시키며 외부로 부터는 접근 할 수 없다
    클러스터 내부 노드나 파드에서 ClusterIP 를 이용해서 서비스에 연결되어 파드에 접근이 가능하다

  • NodePort
    고정 포트로 각 노드의 IP 에 서비스를 노출 시킬 수 있으며 외부에서 접근이 가능하다 ㄴ 외부에서 <노드 IP="">: 로 접근 가능 NodePort 타입은 자동으로 ClusterIP 가 생성됨 ㄴ 실제로 노드 1 에만 파드가 떠있고 노드 2 에는 파드가 없어도 노드2 IP 를 이용해서 접근해도 노드 1의 파드가 응답이 가능

  • LoadBalancer
    클라우드 공급자가 제공하는 로드 밸런서를 사용하여 서비스를 외부에 노출 시킴
    외부 로드 밸런서가 라우팅되는 NodePort 와 ClusterIP 가 자동으로 생성됨
    해당 로드 밸런서의 IP 를 이용해서 외부에서 접근이 가능함

  • ExternalName
    서비스를 ExternalName 값이랑 매칭하는 역할을 수행
    클러스터 내부에서 외부로 접근할 때 주로 사용됨
    이 서비스로 접근하면 설정한 CNAME 값으로 연결되어 클러스터 외부로 접근이 가능함
    내부에서 외부로 접근할 때 사용하는 값이기 때문에 셀렉터가 필요 없음

Ingress 를 이용하여 서비스를 노출시킬 수 있는데, 서비스 유형은 아니지만 클러스터의 진입점 역할을 수행함

Ingress

공식_쿠버네티스_Ingress
인그레스는 클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트로 일반적으로 HTTP 를 관리

인그레스의 간단한 예시
kubernetes_ingress

  • 인그레스는 외부에서 서비스로 접속 가능한 URL, 로드밸런스 트래픽, SSL/TLS 종료, 이름 기반의 가상 호스팅을 제공하도록 구성 가능함
  • 인그레스가 위의 기능들을 정의 해둔 자원이라면 인그레스 컨트롤러는 정의한 대로 동작하게 해주는 관리자
  • 클라우드 상에서는 일반적으로 로드 밸런서 서비스들과 인그레스를 연동해 주지만, 직접 인그레스를 사용하기 위해서는 인그레스 컨트롤러를 인그레스와 직접 연동해주어야 함

Volume

공식_쿠버네티스_Volume
Volume 은 저장소와 관련된 오브젝트다

볼륨이 필요한 이유

  • 컨테이너의 특성 상 어떤 문제가 발생하여 컨테이너가 삭제되면 데이터도 같이 삭제된다
  • ex) 컨테이너 런타임에 생성된 로그 파일
  • 컨테이너가 종료되더라도 유지해야 하는 파일을 저장하기 위해서 볼륨을 이용해야 함

볼륨은 호스트 디렉토리를 그대로 사용할 수 있고 EBS 같은 스토리지를 동적으로 생성하여 사용 가능함

  • 임시 볼륨인 Pod 의 볼륨과 영구 저장용 볼륨인 퍼시스턴트 볼륨 등이 있음

래퍼런스