Managing Kubernetes - 02.쿠버네티스 살펴보기

2023년 5월 6일

쿠버네티스 살펴보기

쿠버네티스 API를 기반으로 애플리케이션을 작성, 배포, 관리하는 것은 그 자체로 아주 복잡한 주제입니다.

컨테이너

컨테이너는 도커가 등장하며 대중화되었으며 개발자가 애플리케이션을 패키지화하고 배포하는 방식에 혁명을 일으켰습니다.

쿠버네티스는 컨테이너 오케스트레이터 이기 때문에 쿠버네티스를 제대로 이해하기 위해서는 일단 컨테이너가 무엇을 의미하는지 정확히 이해하는 것이 중요합니다.

컨테이너는 아래의 개념을 포함합니다.

  • 컨테이너 이미지
  • 실행중인 프로세스 또는 프로세스를 격리하는 일련의 운영체제 개념

컨테이너 이미지

  • 애플리케이션 런타임을 포함하는데, 이는 바이너리, 라이브러리, 컨테이너를 실행하는 데 필요한 기타 데이터로 구성합니다.
  • 개발자는 자신의 컴퓨터에서 애플리케이션을 컨테이너 이미지로 패키지화합니다.
  • 다른 사용자의 컴퓨터나 데이터 센터 서버와 같은 다른 환경에서 이미지를 배포하고 실행할 때, 자신의 컴퓨터에서와 동일하게 컨테이너가 작동합니다.

💡 다양한 환경에서의 이식성과 일관된 실행은 컨테이너 이미지가 추구하는 주요 가치입니다.

  • 컨테이너 이미지가 실행될 때 운영체제의 네임스페이스를 사용하여 실행합니다.
  • 이러한 네임스페이스는 프로세스를 포함하고 있으며, 이 프로세스는 시스템에서 실행 중인 다른 작업의 프로세스나 이와 관련된 것과 격리합니다.
  • 각 컨테이너에는 고유한 자체 네트워크 및 프로세스 식별자(PID) 네임스페이스 존재합니다.
  • 또한 제어그룹(cgroup)을 사용하면 메모리나 CPU와 같은 리소스 사용 격리합니다.

💡 격리에 관해 이야기 할때는 CPU, 메모리, 파일과 같은 자원과 관련이 있다는 것이 중요합니다.

이 모든 작업을 수행하기 위해 컨테이너형 애플리케이션을 빌드하고 배포하는 데 도움이 되는 여러 툴이 존재합니다.

컨테이너 이미지 빌더

오픈 컨테이너 이니셔티브 (OCI) 표준으로 이미지 형식이 표준화

OCI (Open Container Initative)

-> 이 표준으로 클라우드 API, CI/CD 또는 새로운 대체 툴과 라이브러리로 제공되는 다른 이미지 빌더를 개발

표준 동작(standard operation)
  • 표준 컨테이너 도구들을 이용하여 컨테이너의 생성, 시작, 정지
  • 표준 파일 시스템 도구를 이용해서 컨테이너의 스냅샷과 복사
  • 표준 네트워크 도구들을 이용해서 컨테이너의 업로드와 다운로드
내용 중립성(content-agnostic)
  • 표준 컨티에너는 컨테이너가 담고 있는 애플리케이션의 종류에 상관 없이 표준 동작들이 동일하게 동작
인프라 중립성 (Infrastructure agnostic)
  • 표준 컨테이너는 OCI 지원 인프라라면 종류에 상관없이 컨테이너 실행이 가능
자동화를 위한 설계 (designed for Automation)
  • 표준 컨테이너는 컨테이너 내용과 인프라 종류에 상관없이 동일한 표준 동작을 지원하기 때문에 자동화가 용이
산업 수준의 배포 (Industrygrade delivery)
  • 표준 컨테이너는 기업 규모에 상관 없이 산업 수준의 배포가 가능
이미지 레지스트리
  • 컨테이너 이미지를 만든 후에는 해당 이미지를 사용자의 컴퓨터에서 다른 사용자, 클라우드, 개인 데이터 센터에 배포하는 방법이 필요
  • 이미지 레지스트리는 이미지를 업로드하고 관리하기 위한 API
  • 이미지가 빌드되면 이미지 레지스트리로 푸시
  • 모든 레지스트리는 이미지를 푸시할 수 있는 권한이 있어야 하지만 일부 레지스트리는 공개되어 있으므로, 이미지를 푸시하면 전세계 누구나 이미지를 가져오거나 실행
  • 모든 공개 클라우드에는 사용할 수 있는 서비스 레지스트리가 있으며, 자체 사용자 환경에서 다운로드해서 실행할 수 있는 오픈 소스 레지스트리 서버 존재
컨테이너 오케스트레이션
  • 애플리케이션을 컨테이너 이미지로 패키징하고 레지스트리로 푸시한 다음에는 해당 컨테이너를 사용하여 애플리케이션을 배포해야 한다.
  • 레지스트리 어딘가에 컨테이너 이미지를 저장한 후 동작하는 애플리케이션을 만들려면 컨테이너 이미지를 실행해야 한다.
  • 쿠버네티스의 역할은 CPU, 메모리, 디스크와 같은 컴퓨팅 리소스 그룹을 가져와서 개발자가 컨테이너를 배포하는 데 사용할 수 있도록 컨테이너 지향 API로 변환하는 것.
# ‘컨테이너 이미지를 실행하고 올바르게 운영하려면 코어 3개와 메모리 10GB가 필요합니다.’
1. 쿠버네티스 시스템은 일련의 리소스를 검토
2. 해당 컨테이너 이미지가 실행될 수 있는 좋은 위치를 검토
3. 해당 컴퓨터 위치에서 컨테이너가 실행되도록 스케줄
→ 개발자는 자신의 컨테이너 이미지가 실행되는 것을 확인할 수 있지만 컨테이너가 구체적으로 어디에서 실행되는지 관심을 둘 필요가 없다.
  • 오케스트레이션 시스템은 컨테이너를 서버에 스케줄 하는 것 이상의 의미
  • 쿠버네티스 오케스트레이터는 문제가 발생했을 때 컨테이너를 복구하는 방법이 내장 → 컨테이너 내부의 프로세스가 충돌하면 쿠버네티스가 다시 시작
  • 사용자 정의 상태 검사(health check)를 정의하면 쿠버네티스는 애플리케이션이 교착 상태에 있어서 다시 시작해야 하는지 정상 검사(liveness check), 로드 밸런싱 조정 서비스 준비 상태 검사(Readness check) 를 해야 하는지 확인
  • 로드밸런싱(부하분산)과 관련하여 쿠버네티스는 다양한 레플리카(복제본)간 트래픽의 로드밸런싱 방법을 정의하는 API 오브젝트 제공 또한 쿠버네티스는 제로 다운타임 롤아웃을 수행하고 설정, 퍼시스턴트 볼륨, 시크릿등을 관리하는 오브젝트를 가지고 있습니다.

쿠버네티스 API

쿠버네티스 API는 HTTP 및 JSON 기반의 RESTful API이며 API 서버가 제공되며 모든 구성 요소는 API를 이용해 통신

기본 오브젝트 : 파드, 레플리카셋, 서비스

파드(Pod)
  • 쿠버네티스 클러스터 스케줄링에서 가장 작은 원자
  • 파드를 원자라고 하는 것은 모든 컨테이너가 클러스터에서 동일한 시스템을 차지하도록 보장한다는 의미합니다.
  • 파드는 하나 이상의 실행중인 컨테이너로 구성합니다.
  • 프로세스와 프로세스 간 통신 네임스페이스를 공유하고 있어서, 공유 메모리나 시그널링 같은 툴을 사용하여 다른 컨테이너에서 파드의 여러 프로세스를 제어합니다.
  • 이러한 밀접한 그룹화는 메인 컨테이너와 백그라운드에서 데이터를 로딩하는 컨테이너 처럼 파드가 컨테이너 사이의 공생관계를 이상적으로 적합하다는 것을 의미합니다.
  • 만약 컨테이너 이미지를 별도로 유지하면 일반적인 경우에 서로 다른 팀 간 컨테이너 이미지를 소유하거나 재사용할 때 빠르게 사용할 수 있습니다.
  • 반면 컨테이너 이미지를 런타임에 파드 안에서 함께 그룹화하면 조화롭게 사용합니다.
  • 파드는 스케일링과 복제의 단위
  • 파드는 애플리케이션이 계속해서 실행 상태에 있도록 도와줍니다.
  • 컨테이너의 프로세스가 충돌하면 쿠버네티스는 자동으로 프로세스를 다시 시작합니다.
레플리카셋(ReplicaSet)
  • 컨테이너 오케스트레이션을 사용하는 주된 이유는 복제된 시스템을 안정적으로 더 쉽게 구축하기 위함
  • 주어진 파드 정의에서 시스템에 여러 개의 복제본이 존재함을 보장
서비스(Service)
  • Service는 TCP나 UDP 로드 밸런싱 서비스를 나타낸다.
  • 모든 서비스는 TCP 또는 UDP에 상관없이 아래의 세가지를 갖고 있다.
  • 자체 IP 주소
  • 쿠버네티스 클러스터 DNS 항목
  • Service를 구현하는 파드로 트래픽을 프록시하는 로드밸런싱 규칙
  • Service가 생성되면 고정 IP가 할당됩니다.
  • 이 IP는 가상 주소여서 네트워크에 있는 인터페이스과 일치하지는 않습니다.
  • 대신 할당된 IP주소는 로드 밸런싱될 IP주소로 네트워크 패브릭에 프로그램이 됩니다.
  • 패킷이 해당 IP로 전송되면 Service를 구현하는 파드 집합으로 로드밸런스 됩니다.
  • 로그밸런싱은 라운드 로빈이나 소스 및 대상 ip 주소 튜플에 기반해 결정하는 방식으로 수행합니다.
라운드 로빈 스케줄링 (Round Robin Scheduling)

시분한 시스템을 위해 설계된 선점형 스케줄링 프로세스들 사이에 우선 순위를 두지 않고, 순서대로 시간 단위로 CPU를 할당하는 방식

  • 고정 IP가 주어지면, DNS 이름이 쿠버네티스 클러스터의 DNS 서버에 프로그래밍합니다.
  • 이 DNS 주소는 쿠버네티스 Service 오브젝트의 이름과 동일한 의미의 이름을 제공하며, 클러스터의 다른 컨테이너가 Service 로드밸런서의 IP 주소를 검색할 수 있게 해줍니다.
  • Service의 로드 밸런싱은 쿠버네티스 클러스터의 네트워크 패브릭에 프로그래밍 되어 Service IP 주소와 통신하려고 시도하는 컨테이너가 해당 파드에 올바르게 로드밸런싱합니다.
  • 이 네트워크 패브릭 프로그래밍은 동적이므로 ReplicaSet의 장애나 확장으로 파드들이 오갈 때 로드밸런서는 클러스터의 현재 상태와 일치하도록 끊임없이 다시 프로그래밍합니다.
  • 즉, 클라이언트는 Service를 구현하는 파드에 대한 Service IP 주소 연결을 신뢰할 수 있음을 의미합니다.

스토리지: 퍼시스턴트 볼륨, 컨피그맵, 시크릿

  • 쿠버네티스에서 처음 소개된 스토리지 개념이 볼륨이다.
  • 실제로 파드 API 의 일부
  • 볼륨은 다양한 유형에서 선택할 수 있으며 NFS, iSCSI, gitRepo, 클라우드 스토리지 기반 볼륨등 10가지가 넘는 유형의 볼륨을 생성
  • 파드에 볼륨을 추가할 때 실행 중인 각 컨테이너의 임의의 위치에 볼륨을 연결
  • 실행중인 컨테이너가 볼륨 내의 스토리지에 접근
  • 다른 컨테이너들은 이 볼륨을 다른 위치로 연결하거나 무시
ConfigMap 오브젝트
  • 구성 파일의 모음
  • 파드에 ConfigMap 기반의 볼륨을 추가하면 ConfigMap의 파일이 실행중인 컨테이너의 지정된 디렉토리에 나타냅니다.
Secret
  • 쿠버네티스는 데이터베이스 암호 및 인증서와 같은 보안 데이터에 시크릿 구성 유형을 사용합니다.
  • 볼륨으로 파드에 부착할 수 있으며 사용중인 컨테이너에 연결할 수 있습니다.

persistentVolumes(퍼시스턴티 볼륨)과 persistenetVolumesClaims(퍼시스턴트 볼륨 클레임)

  • 구체적 제공자를 지정하지 않고 일반적인 스토리지를 요청하는 경우에는 파드 정의가 필요합니다.
  • 파드에 직접 볼륨을 결합하는 대신 PersistentVolume이 별도의 오브젝트로 생성합니다.
  • PersistentVolumesClaims이 오브젝트를 특정 파드에 할당하고 이 요청으로 파드에 최종 연결합니다.

클러스터 구성 오브젝트 : 네임스페이스, 레이블, 어노테이션

네임스페이스
  • 클러스터 구성을 위한 첫 번째 오브젝트는 Namespace입니다.
  • 쿠버네티스 API 오브젝트를 위한 폴더
  • Namespace는 역할 기반 접근 제어(RBAC:Role-Based Access Control) 규칙의 범위를 제공합니다.
  • 폴더와 마찬가지로 Namespace를 삭제하면 그 안에 잇는 모든 오브젝트도 삭제합니다.
  • 모든 쿠버네티스 클러스터에는 default라는 이름의 기본 제공 Namespace가 있으며, 보통 쿠버네티스를 설치할 때는 클러스터 운영 컨테이너가 생성되는 곳인 kube-system이라는 Namespace도 같이 생성합니다.

💡 쿠버네티스 오브젝트는 네임스페이스에 배치할 수 있는지에 따라 네임스페이스 오브젝트와 비네임스페이스 오브젝트로 나눈다. 가장 일반적인 쿠버네티스API 오브젝트는 네임스페이스 오브젝트이다. 그러나 전체 클러스터에 적용되는 일부 오브젝트는 네임스페이스 오브젝트가 아니다.

  • 쿠버네티스 오브젝트를 구성하는 것 외에도 namespace는 service용으로 작성된 DNS 이름과 컨테이너에 제공되는 DNS 검색 경로에도 배치됩니다.
  • 즉, 서로 다른 Namespace의 서로 다른 Service가 서로 다른 정규화된 도메인 이름(FQDNs : Fully Qualified Domain Names)를 갖게 된다는 뜻입니다.
  • 또한 각 컨테이너의 DNS 검색 셩로에는 Namespace가 포함되어 있습니다.
# foo namesapce의 frontend 컨테이너에 대한 DNS 조회 
frontend.svc.foo.cluster.internal 
# bar namespace의 frontend 컨테이너에 대한 DNS 조회 
frontend.sve.bar.cluster.internal
레이블과 레이블 쿼리
  • 쿠버네티스 API의 모든 오브젝트는 연관된 임의의 레이블 집합을 가질 수 있습니다.
  • 레이블은 오브젝트를 식별하는 데 도움이 되는 문자열 키/값 쌍
ex ) “role” : “frontend”
레이블 쿼리
  • 레이블을 사용하여 API의 오브젝트를 조회하고 필터링합니다.
레이블 셀렉터
  • 쿠버네티스 API의 많은 오브젝트는 자신에게 적용되는 오브젝트 집합을 식별하는 방법합니다.
ex) 노드 셀렉터 : 파드를 실행할 수 있는 노드 집합을 식별 / 파드 셀렉터 : service에서 로드 밸런스를 조정해야 하는 파드 집합을 식별
어노테이션
  • API 오브젝트에 할당할 모든 메타데이터 값이 정보를 식별하는 용도는 아닙니다.
  • 일부 정보는 단순히 오브젝트 자체에 대한 어노테이션(주석)
  • 오브젝트 옆에 표시할 아이콘이나, 오브젝트가 시스템에 의해 해석되는 방식을 변경하는 수정자 같은 것이 포함합니다.

고급 오브젝트 : 디플로이먼트, 인그레스, 스테이트풀셋

디플로이먼트(Deployment)
  • ReplicaSets은 동일한 컨테이너 이미지의 여러 레플리카를 실행하는 기본 요소이지만 애플리케이션은 정적 오브젝트가 아닙니다.
  • 새 코드를 Service에 적용하는 작업은 부하를 안정적으로 처리하기 위해 복제하는 것만큼이나 중요합니다.
  • Deployment 오브젝트는 한 버전에서 다른 버전으로 안전한 롤아웃을 나타햅니다.
  • 여러 개의 ReplicaSets에 대한 포인터를 보유할 수 있으며 한 ReplicaSet에서 다른 ReplicaSet으로 빠르고 안전한 이동(migration)을 제어할 수 있습니다.
[동작 이해]
# rs-v1이라는 ReplicaSet의 레플리카 3개에 배포된 애플리케이션
1) Deployment에 새 이미지 (v2)를 롤아웃하도록 요청
2) Deployment는 단일 레플리카를 사용하여 새 ReplicaSet(rs-v2) 작성 
3) Deployment는 이 레플리카가 정상적으로 유지될때 까지 기다림
4) 잘 유지되면 Deployment는 rs-v1의 레플리카 수를 2로 줄임
5) 그런 다음 rs-v2의 레플리카 수도 2개로 늘리고 v2의 두 번째 레플리카가 정상저긍로 유지될 때 까지 기다림
6) 위의 프로세스를 v1 replica가 더는 없고 v2 replica가 3개가 될 때까지 반복

💡 실제로 대부분의 최신 클러스터에서는 사용자가 Deployment 오브젝트를 단독으로 사용하고 ReplicaSets을 관리하지 않는다.

HTTP 로드 밸런싱과 인그레스
  • 사용자가 컨테이너와 쿠버네티스를 사용하여 배포하는 대부분의 애플리케이션은 HTTP 웹 기반 애플리케이션이기 때문에 HTTP를 이해하는 로드밸런서를 제공
  • Ingress(인그레스, 수신) API가 쿠버네티스에 추가합니다.

    • 경로 및 호스트 기반 HTTP 로드 밸런서와 라우터를 나타냅니다.
    • 오브젝트를 만들 때 Ingress 오브젝트는 서비스와 마찬가지로 가상IP주소를 받지만, 서비스 IP주소와 파드 집합 간의 일대인 관계 대신 Ingress가 HTTP 요청 내용을 사용하여 이를 다른 Service로 라우팅합니다.
    • 호스트나 경로, 혹은 둘 다 설정 가능합니다.
[동작 이해]
# foo와 bar라는 두 개의 쿠버네티스 Service가 존재
# 각자 고유한 IP주소가 있지만 실제로 동일한 호스트의 일부로 인터넷에 노출하려고 한다.
1) foo.company.com, bar.company.com Ingress 오브젝트를 만들고 IP 주소를 각 DNS 이름과 연결
2) Ingress 오브젝트에서 호스트 이름 두 개를 각각의 쿠버네티스 Service에 매핑
3) foo.company.com에 대한 요청이 수신될 때 클러스터의 foo Service로 라우팅 (bar도 마찬가지)
4) 호스트 외에 경로로 설정이 가능하여 company.com/bar를 bar Service로 라우팅 가능

💡 쿠버네티스는 Ingress 오브젝트를 저장하지만 생성할 때는 아무 일도 일어나지 않는다. 대신 클러스터에서 인그레스 컨트롤러를 실행하여 Ingress 오브젝트를 만들 때 적절한 작업을 수행해야 합니다.

스테이트풀셋(StatefulSet)
  • 각 레플리카는 다른 레플리카와 구별되는 고유한 ID가 없습니다.
  • ReplicaSets과 마찬가지로 StatefulSets은 쿠버네티스 클러스터에서 실행되는 동일한 컨테이너 이미지의 여러 인스턴스를 만들지만, 각 컨테이너의 이름에 따라 컨테이너를 만들고 삭제합니다.
  • ReplicaSet에서 복제된 각 파드는 임의의 해시(ex. frontend-13au2)와 관련된 이름으로 생성되며 순서를 지정하지 않습니다.
  • StatefulSet의 경우, 각 레플리카는 단조롭게 증가하는 색인(ex. frontend—0,frontend-1 등)으로 생성됩니다.
  • StatefulSets은 레플리카 1이 생성되기 전에 레플리카 0이 생성되어 정상적이 될 것이라고 보장합니다.

배치 워크로드 : 잡과 크론잡

잡(Job)
  • 행해야 할 작업 집합
  • ReplicaSets와 StatefulSets와 마찬가지로 컨테이너 이미지를 실행하여 작업을 실행하는 파드를 생성합니다.
  • ReplicaSets와 StatefulSets과 달리 Job에 의해 생성된 파드는 작업을 완료하고 종료합니다.
크론잡(CronJob)
  • Job에 일정을 추가하여 Job 오브젝트 위에 구축합니다.
  • 생성하려는 Job 오브젝트의 정의와 해당 Job을 언제 생성해야 하는지 스케줄 포함합니다.

클러스터 에이전트와 유틸리티 : 데몬셋

  • 쿠버테니트스는 DaemonSet API로 사용자가 클러스터에 에이전트를 설치할 수 있게 합니다.
  • DaemonSet이 생성되면 쿠버네티스는 이 파트가 클러스터의 각 노드에서 실행중인지 확인합니다. -> 나중에 새로운 노드가 추가되면 쿠버네티스는 해당 노드에도 파드를 만들게 됩니다.
  • 기본적으로 쿠버네티스는 클러스터의 모든 노드에 파드를 배치하지만 DaemonSet은 노드 셀렉터 레이블 쿼리도 제공할 수 있으며, DaemonSet의 파드를 해당 레이블 쿼리와 일치하는 노드에만 배치합니다.