본문 바로가기

Infrastructure/Kubernetes

[K8S] 쿠버네티스란

쿠버네티스 공식문서를 확인하며 쿠버네티스 개념과 관련하여 기억해야 하는 부분을 기록한다.


  • 쿠버네티스는 컨테이너화된 워크로드와 서비스를 관리하기 위한 이식성이 있고 확장가능한 오픈소스 플랫폼이다.
  • 선언적 구성과 자동화를 모두 용이하게 해준다.
  • 쿠버네티스란 명칭은 키잡이(helmsman)이나 파일럿을 뜻하는 그리스어에서 유래했다.
  • 15년 이상의 구글 경험이 담겨있는 쿠버네티스를 구글이 2014년에 오픈소스화했다.

역사

전통적인 배포(Traditional Deployment)가 이루어지던 시기에는 아래와 같은 특징이 있다.

  • 애플리케이션을 물리 서버에서 실행하였고 하나의 물리적인 서버에 여러 애플리케이션이 실행되면서 리서스를 정의할 방법이 없었기 때문에 리소스 할당의 문제가 발생하였다.
  • 해결책으로 서로 다른 여러 물리 서버에서 각 애플리케이션을 실행하는 방법이 있었지만, 리소스가 충분히 활용되지 않거나 확장이 불가능하였고 많은 물리 서버를 유지하기 위해 조직의 많은 비용이 소비되었다.

가상화된 배포(Vitualized Deployment)에서 가상화는 전통적인 배포의 문제를 해결하기 위해 도입되었다.

  • 단일 물리 서버의 CPU에서 여러 가상 시스템(VM)을 실행시킬 수 있게 한다.
  • VM간에 애플리케이션을 격리하고 애플리케이션의 정보를 다른 애플리케이션에서 자유롭게 액세스 할 수 없으므로, 일정 수준의 보안을 제공한다.
  • 물리 서버에서 리소스를 보다 효율적으로 활용할 수 있기 때문에 쉽게 애플리케이션을 추가 및 확장이 가능하여 상대적으로 적은 하드웨어 비용과 높은 확장성을 제공한다.
  • 각 VM은 가상화된 하드웨어 상에서 자체 운영체제를 포함한 모든 구성요소를 실행하는 하나의 완전한 머신이다.

컨테이너 개발(Container Deployment)에서 컨테이너는 VM과 유사하지만 격리 속성을 완화하여 애플리케이션 간에 운영체제(OS)를 공유하고 VM에 비해 상대적으로 가볍게 작동한다.

  • VM과 마찬가지로 컨테이너에는 자체 파일 시스템, CPU 점유율, 메모리, 프로세스 공간이 있다.
  • 기본 인프라와 종속성을 끊었기 때문에 클라우드나 OS 배포본에 모두 이식할 수 있다.
  • VM 이미지를 사용하는 것에 비해 컨테이너 이미지 생성이 보다 쉽고 효율적이다.
  • 안정적이고 주기적으로 컨테이너 이미지를 빌드해서 배포할 수 있고 이미지의 불변성으로 인해 빠르고 효율적으로 롤백할 수 있다.
  • 배포 시점이 아닌 빌드/릴리즈 시점에 애플리케이션 컨테이너 이미지를 만들기 때문에 애플리케이션이 인프라스트럭처에서 분리된다.
  • OS 수준의 정보와 메트릭 뿐만 아니라, 애플리케이션의 헬스와 그 밖의 시그널을 볼 수 있다.
  • 개발, 테스트 및 운영 환경을 동일하게 구축할 수 있으며 개발자의 PC에서도 동일하게 구성할 수 있다.
  • Ubuntu, RHEL 뿐만 아니라 주요 클라우드의 어디에서도 실행이 가능하다.
  • OS를 실행하는 수준에서 논리적인 리소스를 사용하는 OS를 실행하는 수준에서 논리적인 리소스를 사용하는 OS 상에서 애플리케이션을 실행하는 수준으로 추상화 수준이 높아진다.
  • 애플리케이션이 단일 목적의 머신에서 실행되는 것이 아니라 독립적인 단위로 쪼개져서 동적으로 배포가 가능하기 때문에 유연하고 자유롭게 마이크로서비스를 구축할 수 있다.
  • 리소스를 격리하여 애플리케이션의 성능을 예측할 수 있다.

쿠버네티스 필요 이유

  • 상용 환경에서는 애플리케이션을 실행하는 컨테이너를 관리하고 가동 중지 시간이 없는지 확인이 필요하며 만약 컨테이너가 다운되면 다른 컨테이너를 다시 시작해야 한다.
  • 쿠버네티스는 분산 시스템을 탄력적으로 실행하기 위한 프레임워크를 제공한다. 애플리케이션의 확장과 장애 조치를 처리하고, 배포 패턴등을 제공한다.

쿠버네티스는 대표적으로 아래와 같은 기능을 제공한다.

  • 서비스 디스커버리와 로드 밸런싱: 쿠버네티스는 DNS 이름을 사용하거나 자체 IP 주소를 사용하여 컨테이너를 노출할 수 있다. 컨테이너에 대한 트래픽이 많으면 네트워크 트래픽을 로드 밸런싱하고 배포하여 배포가 안정적으로 이루어질 수 있다.
  • 스토리지 오케스트레이션: 로컬 저장소, 공용 클라우드 공급자 등과 같이 원하는 저장소 시스템을 자동으로 탑재 할 수 있다.
  • 자동화된 롤아웃 롤백: 배포된 컨테이너의 원하는 상태를 서술할 수 있으며 현재 상태를 원하는 상태로 설정한 속도에 따라 변경할 수 있다. 예를 들어, 쿠버네티스를 자동화해서 배포용 새 컨테이너를 만들고, 기존 컨테이너를 제거하고, 모든 리소스를 새 컨테이너에 적용할 수 있다.
  • 자동화된 빈 패킹(bin packing): 컨테이너화된 작업을 실행하는데 사용할 수 있는 쿠버네티스 클러스터 노드를 제공한다. 각 컨테이너가 필요로 하는 CPU와 메모리(RAM)를 쿠버네티스에게 지시한다. 쿠버네티스는 컨테이너를 노드에 맞추어서 리소스를 가장 잘 사용할 수 있도록 해준다.
  • 자동화된 복구(self-healing): 실패한 컨테이너를 다시 시작하고, 컨테이너를 교체하며, ‘사용자 정의 상태 검사’에 응답하지 않는 컨테이너를 죽이고, 서비스 준비가 끝날 때까지 이런 일련의 과정을 클라이언트에 제공하지 않는다.
  • 시크릿과 구성 관리: 암호, OAuth 토큰 및 SSH 키와 같은 중요한 정보를 저장하고 관리 할 수 있다. 컨테이너 이미지를 재구성하지 않고 스택 구성에 시크릿을 노출하지 않고도 시크릿 및 애플리케이션 구성을 배포 및 업데이터 할 수 있다.

쿠버네티스가 아닌 것

  • 쿠버네티스는 전통적인, 모든 것이 포함된 PaaS(Platform as a Service)가 아니다.
  • 하드웨어 수준보다는 컨테이너 수준에서 운영되기 때문에, PaaS가 일반적으로 제공하는 배포, 스케일링, 로드 밸런싱과 같은 기능을 제공하며, 사용자가 로깅, 모니터링 및 알림 솔루션을 통합할 수 있다. 모놀로식(Monolithic)이 아니기 때문에 이러한 기능들을 선택적으로 추가 및 제거 할 수 있다.
  • 개발자 플랫폼을 만드는 구성 요소를 제공하지만, 필요한 경우 사용자의 선택권과 유연성을 지켜준다.
  • 지원하는 애플리케이션의 유형을 제약하지 않고 다양한 워크로드 지원을 목표로 하기 때문에 애플리케이션이 컨테이너에서 구동된다면 무버네티스에서도 잘 동작할 가능성이 높다.
  • 소스 코드를 배포하지 않으며 애플리케이션을 빌드하지 않는다.
  • 데이터베이스, 데이터처리 프레임워크와 같은 애플리케이션 레벨의 서비스를 제공하지 않는다. 다만 이러한 컴포넌트가 쿠버네티스 상에서 구동될 수 있다.
  • 로깅, 모니터링 또는 알림 솔루션을 포함하지 않지만 메트릭을 수집하고 노출하는 메커니즘을 제공한다.
  • 기본 설정 언어/시스템을 제공하거나 요구하지 않는다. 선언적 명세의 임의적인 형식을 목적으로 하는 선언적 API를 제공한다.
  • 포괄적인 머신 설정, 유지보수, 관리, 자동 복구 시스템을 제공하거나 채택하지 않는다.
  • 단순한 오케스트레이션 시스템이 아니며 오케스트레이션의 필요성을 없애준다. 쿠버네티스는 독립적으로 조합 가능한 제어 프로세스들로 구성되어 있으며 이 프로세스는 지속적으로 개발자가 의도한 상태로 나아가도록 한다. 중앙화된 제어도 필요치 않다.

쿠버네티스 컴포넌트

  • 쿠버네티스 클러스터는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 워커 머신의 집합이며 모든 클러스터는 적어도 하나의 워커 노드를 가진다.
  • 워커 노드는 애플리케이션의 구성요소인 파드를 호스팅한다.
  • 컨트롤 플레인은 워커 노드와 클러스터 내 파드를 관리한다.
  • 상용 환경에서는 일반적으로 컨트롤 플레인이 여러 컴퓨터에 걸쳐 설치되고, 클러스터는 일반적으로 여러 노드를 실행하므로 내결함성과 고가용성이 제공된다.


컨트롤 플레인 컴포넌트

  • 컨트롤 플레인 컴포넌트는 클러스터에 관해 스케줄링과 같은 전반적인 결정을 수행한다. 또한 디플로이먼트의 replicas 필드에 대한 요구 조건이 충족되지 않을 경우 새로운 파드를 구동시키는 것과 같은 클러스터 이벤트를 감지하고 반응한다.
  • 컨트롤 플레인 컴포넌트는 클러스터 내 어떠한 머신에서든지 동작할 수 있다. 간결성을 위하여, 구성 스크립트는 보통 동일 머신 상에 모든 컨트롤 플레인 컴포넌트를 구동시키고, 사용자 컨테이너는 해당 머신 상에 동작시키지 않는다.

kube-apiserver

  • API 서버는 쿠버네티스 API를 노출하는 쿠버네티스 컨트롤 플레인 컴포넌트로 컨트롤 플레인의 프론트 엔드로 볼 수 있다.
  • API 서버의 주요 구현은 kube-apiserver이며 수평적으로 확장되도록 디자인 되어 있다.
  • 더 많은 인스턴스를 배포해서 확장할 수 있으며 어러 kube-apiserver 인스턴스를 생성하고 인스턴스간의 트래픽을 균형있게 조절할 수 있다.

etcd

  • 모든 클러스터 데이터를 담는 쿠버네티스 뒷단의 저장소로 사용되는 일관성*고가용성 키-값 저장소다.
  • 클러스터에서 etcd를 뒷단의 저장소로 사용한다면 필수적으로 데이터를 백업해야 한다.

kube-scheduler

  • 노드가 배정되지 않은 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트다.
  • 스케줄링 결정을 위해서 고려되는 요소는 리소스에 대한 개별 및 총체적 요구 사항, 하드웨어/소프트웨어/정책적 제약, 어피니티(affinity) 및 안티-어피니티(anti-affinity) 명세, 데이터 지역성, 워크로드-간 간섭, 데드라인을 포함한다.

kube-controller-manager

  • 컨트롤러 프로세스를 실행하는 컨트롤 플레인 컴포넌트다.
  • 논리적으로, 각 컨트롤러는 분리된 프로세스이지만, 복잡성을 낮추기 위해 모두 단일 바이너리로 컴파일되고 단일 프로세스 내에서 실행된다.

아래와 같은 컨트롤러 종류가 있다.

  • 노드 컨트롤러: 노드가 다운되었을 때 통지와 대응에 관한 책임을 가진다.
  • 레플리케이션 컨트롤러: 시스템의 모든 레플리케이션 컨트롤러 오브젝트에 대해 알맞은 수의 파드들을 유지시켜 주는 책임을 가진다.
  • 엔드포인트 컨트롤러: 엔드포인트 오브젝트를 채워 서비스와 파드를 연결시킨다.
  • 서비스 어카운트 & 토큰 컨트롤러: 새로운 네임스페이스에 대한 기본 계정과 API 접근 토큰을 생성한다.

cloud-controller-manager

  • 클라우드별 컨트롤 로직을 포함하는 쿠버네티스 먼트롤 플레인 컴포넌트다.
  • 클라우드 컨트롤러 매니저를 통해 클러스터를 클라우드 공급자의 API에 연결하고, 해당 클라우드 플랫폼과 상호 작용하는 컴포넌트와 클러스터와만 상호 작용하는 컴포넌트를 구분할 수 있게 해 준다.
  • 클라우드 제공자 전용 컨트롤러만 실행하며, 자신 PC와 같은 학습환경에서 쿠버네티스를 실행 중인 경우에는 존재하지 않는다.
  • kube-controller-manager와 마찬가지로 논리적으로 독립적인 여러 컨트롤 루프를 단일 프로세스로 실행하는 단일 바이너리로 결합한다. 수평으로 확장해서 성능을 향상시키거나 장애를 견딜 수 있다.

아래의 컨트롤러들은 클라우드 제공 사업자의 의존성을 가질 수 있다.

  • 노드 컨트롤러: 노드가 응답을 멈춘 후 클라우드 상에서 삭제되었는지 판별하기 위해 클라우드 제공 사업자에게 확인하는 것
  • 라우트 컨트롤러: 기본 클라우드 인프라에 경로를 구성하는 것
  • 서비스 컨트롤러: 클라우드 제공 사업자 로드밸런서를 생성, 업데이트 및 삭제하는 것

노드 컴포넌트

  • 노드 컴포넌트는 동작 중인 파드를 유지시키고 쿠버네티스 런타임 환경을 제공하며, 모든 노드 상에서 동작한다.

kubelet

  • 클러스터의 각 노드에서 실행되는 에이전트로 파드에서 컨테이너가 확실하게 동작하도록 관리한다.
  • 다양한 메커니즘을 통해 제공된 파드 스펙(PodSpec)의 집합을 받아서 컨테이너가 해당 파드 스펙에 따라 건강하게 동작하는 것을 보장한다. 단, 쿠버네티스를 통해 생성되지 않는 컨테이너는 관리하지 않는다.

kube-proxy

  • 클러스터의 각 노드에서 실행되는 네트워크 프록시로, 쿠버네티스의 서비스 개념의 구현부다.
  • 노드의 네트워크 규칙을 유지 관리한다. 이 네트워크 규칙을 통해 내부 네트워크 세션이나 클러스터 밖에서 파드로 네트워크 통신을 할 수 있도록 해준다.
  • 운영 체제에 가용한 패킷 필터링 계층이 있는 경우, 이를 사용한다. 그렇지 않으면, kube-proxy는 트래픽 자체를 포워드(forward)한다.

컨테이너 런타임

  • 컨테이너 실행을 담당하는 소프트웨어다.
  • 쿠버네티스는 containerd, CRI-O와 같은 컨테이너 런타임 및 모든 Kubernetes CRI(컨테이너 런타임 인터페이스) 구현체를 지원한다.

애드온

  • 애드온은 쿠버네티스 리소스(데몬셋, 디플로이먼트 등)를 이용하여 클러스터 기능을 구현한다. 이들은 클러스터 단위의 기능을 제공하기 때문에 애드온에 대한 네임스페이스 리소스는 kube-system 네임스페이스에 속한다.

DNS

  • 여타 애드온들이 절대적으로 요구되지 않지만, 많은 예시에서 필요로 하기 때문에 모든 쿠버네티스 클러스터는 클러스터 DNS를 갖추어야만 한다.
  • 클러스터 DNS는 구성환경 내 다른 DNS 서버와 더불어, 쿠버네티스 서비스를 위해 DNS 레코드를 제공해주는 DNS 서버다.
  • 쿠버네티스에 의해 구동되는 컨테이너는 DNS 검색에서 이 DNS 서버를 자동으로 포함한다.

웹 UI(대시보드)

  • 대시보드는 쿠버네티스 클러스터를 위한 범용의 웹 기반 UI로 사용자가 클러스터 자체뿐만 아니라, 클러스터에서 동작하는 애플리케이션에 대한 관리와 문제 해결을 할 수 있도록 해준다.

컨테이너 리소스 모니터링

  • 중앙 데이터베이스 내의 컨테이너들에 대한 포괄적인 시계열 매트릭스를 기록하고 그 데이터를 열람하기 위한 UI를 제공해 준다.

클러스터-레벨 로깅

  • 클러스터-레벨 로깅 메커니즘은 검색/열람 인터페이스와 함께 중앙 로그 저장소에 컨테이너 로그를 저장하는 책임을 가진다.

쿠버네티스 API

  • 쿠버네티스 컨트롤 플레인의 핵심은 API 서버이며 API 서버는 최종 사용자, 클러스터의 다른 부분 그리고 외부 컴포넌트가 서로 통신할 수 있도록 HTTP API를 제공한다.
  • 쿠버네티스 API를 사용하면 파드, 네임스페이스, 컨피그맵, 이벤트와 같은 쿠버네티스의 API 오브젝트를 질의(query)하고 조작할 수 있다.
  • 대부분의 작업은 kubectl 커맨드 라인 인터페이스(CLI) 또는 API를 사용하는 kubeadm 과 같은 다른 커맨드 라인 도구를 통해 수행할 수 있다. REST 호출을 사용하여 API에 직접 접근도 가능하다.

OpenAPI 명세

OpenAPI V2

  • 쿠버네티스 API 서버는 /openapi/v2 엔드포인트를 통해 통합된(aggregated) OpenAPI v2 스펙을 제공한다.
  • 주로 클러스터 내부 통신을 위해 대안적인 Protobuf에 기반한 직렬화 형식을 구현한다.

OpenAPI V3

  • 쿠버네티스 v1.25 에서는 OpenAPI v3 API 발행(publishing)에 대한 베타 지원을 제공한다. 이는 베타 기능이지만 기본적으로 활성화되어 있다.
  • kube-apiserver 구성 요소에 OpenAPIV3 기능 게이트를 비활성화하여 이 베타 기능을 비활성화할 수 있다.
  • /openapi/v3 디스커버리 엔드포인트는 사용 가능한 모든 그룹/버전의 목록을 제공한다. 이 엔드포인트는 jSON만을 반환하며 아래와 같은 형식으로 제공된다.
{
    "paths": {
        ...
        "api/v1": {
            "serverRelativeURL": "/openapi/v3/api/v1?hash=CC0E9BFD992D8C59AEC98A1E2336F899E8318D3CF4C68944C3DEC640AF5AB52D864AC50DAA8D145B3494F75FA3CFF939FCBDDA431DAD3CA79738B297795818CF"
        },
        "apis/admissionregistration.k8s.io/v1": {
            "serverRelativeURL": "/openapi/v3/apis/admissionregistration.k8s.io/v1?hash=E19CC93A116982CE5422FC42B590A8AFAD92CDE9AE4D59B5CAAD568F083AD07946E6CB5817531680BCE6E215C16973CD39003B0425F3477CFD854E89A9DB6597"
        },
        ...
}
  • 상대 URL은 변경 불가능한(immutable) OpenAPI 상세를 가리키고 있으며, 이는 클라이언트에서의 캐싱을 향상시키기 위함이다. 같은 목적을 위해 API 서버는 적절한 HTTP 캐싱 헤더를 설정한다.

지속성

  • 쿠버네티스는 오브젝트의 직렬화된 상태를 etcd에 저장한다.

API 그룹과 버전 규칙

  • 필드를 쉽게 제거하거나 리소스 표현을 재구성하기 위해, 쿠버네티스는 각각 /api/v1 또는 /apis/rbac.authorization.k8s.io/v1alpha1과 같은 서로 다른 API 경로에서 여러 API 버전을 지원한다.
  • 버전 규칙은 리소스나 필드 수준이 아닌 API 수준에서 수행되어 API가 시스템 리소스 및 동작에 대한 명확하고 일관된 보기를 제공하고 수명 종료 및 실험적 API에 대한 접근을 제어할 수 있도록 한다.
  • API 리소스는 API 그룹, 리소스 유형, 네임스페이스 및 이름으로 구분된다. API 서버는 API 버전 간의 변환을 투명하게 처리한다. 서로 다른 모든 버전은 실제로 동일한 지속 데이터의 표현이며 API 서버는 여러 API 버전을 통해 동일한 기본 데이터를 제공할 수 있다.
  • 동일한 리소스에 대해 v1v1beta1이라는 두 가지 API 버전이 있다고 가정했을 때 원래 API의 v1beta1 버전을 사용하여 오브젝트를 만든 경우, 나중에 v1beta1 또는 v1 API 버전을 사용하여 해당 오브젝트를 읽거나 업데이트하거나, 삭제할 수 있다.

API 변경 사항

  • 성공적인 시스템은 새로운 유스케이스가 등장하거나 기존 사례가 변경됨에 따라 성장하고 변화하기 때문에 쿠버네티스 API는 지속적으로 변경되고 성장할 수 있도록 설계되어 있다.
  • 쿠버네티스 프로젝트는 기존 클라이언트와의 호환성을 깨지 않고 다른 프로젝트가 적응할 기회를 가질 수 있도록 장기간 해당 호환성을 유지하는 것을 목표로 한다.
  • 일반적으로, 새 API 리소스와 새 리소스 필드는 자주 추가될 수 있으며 리소스 또는 필드를 제거하려면 API 지원 중단 정책을 따라야 한다.
  • API 버전 v1에서 안정 버전(GA)에 도달하면, 공식 쿠버네티스 API에 대한 호환성 유지를 강력하게 이행한다. 또한 가능한 경우 베타 API 버전에서도 호환성을 유지하며 베타 API를 채택하면 기능이 안정된 후에도 해당 API를 사용하여 클러스터와 계속 상호 작용할 수 있다.
  • 알파 API 버전에 대한 호환성을 유지하는 것을 목표로 하지만, 일부 상황에서는 호환성이 깨질 수 있다. 알파 API 버전을 사용하는 경우, API가 변경될 수 있으므로 클러스터를 업그레이드할 때 쿠버네티스에 대한 릴리즈 정보를 확인해야 한다.

API 확장

쿠버네티스는 아래와 같은 방법으로 확장이 가능하다.

  • 커스텀 리소스를 사용하면 API 서버가 선택한 리소스 API를 제공하는 방법을 선언적으로 정의할 수 있다.
  • 애그리게이션 레이어(aggregation layer)를 구연하여 쿠버네티스 API를 확장할 수도 있다.

참고 자료

'Infrastructure > Kubernetes' 카테고리의 다른 글

[클러스터 아키텍처] 노드  (0) 2022.10.13
[K8S] 오브젝트 - 2  (0) 2022.10.12
[K8S] 오브젝트 - 1  (0) 2022.10.12
[K8S] 모범 사례  (0) 2022.10.12
[K8S] 컨테이너 런타임  (0) 2022.10.12