1. 도커와 쿠버네티스티스의 개요

김하영·2021년 9월 12일
1
post-thumbnail

'15단계로 배우는 도커와 쿠버네티스' 기반으로 내용 정리하였습니다.

3. 쿠버네티스의 기본

  • 쿠버네티스의 기본구조와 철학

3.1 아키텍처

  • 쿠버네티스는 한대의 마스터와 여러대의 worker 노드들로 구성.
  • 컴포넌트들은 파드 형태로 띄워짐.
  • /etc/kubernetes/manifests 안 컴포넌트들의 생성하기 위한 yaml 존재.
  • 쿠버네티스가 기동시 yaml 파일을 읽어 스태틱으로 파드를 띄움.

1. 마스터

  • 클러스터 관리
  • 쿠버네티스 설정 환경 저장
  • etcd, kube-apiserver, kube-scheduler, kube-controller-manager 등의 컴포넌트 실행

2. 노드

  • 쿠버네티스는 한대의 마스터와 여러대의 worker 노드들로 구성
  • kubelet, kube-proxy, docker 등 컴포넌트 실행
  • 실제 사용하는 컨테이너 대부분 실행

쿠버네티스를 구성하는 기본 컴포넌트와 플러그인은 아래와 같다.

[ K8s 클러스터를 구성하는 코어 프로세스 (컨테이너) ]

  • kubectl : k8s 클러스터를 조작하기 위한 도구로 가장 빈번하게 이용되는 커맨드 라인 인터페이스

  • kube-apiserver : kubectl 등의 API 클라이언트로부터 오는 REST 요청을 검증하고, API 오브젝트를 구성하고 상태를 보고한다.

  • kube-scheduler : k8s의 기본 스케쥴러이며, 새로 생성된 모든 파드에 대해 실행할 최적의 노드를 선택한다.
    스케줄러는 파드가 실행 가능한 노드를 찾은 다음 점수를 계산하여 가장 점수가 높은 노드를 선택한다.

  • kube-controller-manager : 컨트롤러를 구동하는 마스터상의 컴포넌트

  • cloud-controller-manager : API를 통해 클라우드 서비스와 연계하는 컨트롤러로, 클라우드 업체에서 개발한다.

  • etcd : k8s 클러스터의 모든 관리 데이터는 etcd에 저장된다.이 etcd는 CoreOS가 개발한 분산 키/값 저장소로 신뢰성이 요구되는 핵심 데이터의 저장 및 접근을 위해 설계되었다.

  • kubelet : kubelet은 각 노드에서 다음과 같은 역할을 수행한다.

  1. 파드와 컨테이너의 실행
  2. 파드와 노드의 상태를 API 서버에 보고
  3. 컨테이너의 동작을 확인하는 프로브 실행
  4. 내장된 cAdvisor를 통해 메트릭 수집 및 공개
  • kube-proxy : kube-proxy는 각 노드에서 동작하며 로드밸런싱 기능을 제공한다.
  1. 서비스와 파드의 변경을 감지하여 최신 상태로 유지
  2. iptables 규칙을 관리
  3. 서비스명과 ClusterIP를 내부 DNS에 등록
  • coredns : 파드가 서비스 이름으로부터 IP 주소를 얻기 위해 사용한다.
    버전 1.11부터 kube-dns 대신 coredns가 사용되었다.
    이전 kube-dns의 부족한 신뢰성,보안성,유연성이 coredns로 개선되었다.
    CoreDNS 프로젝트는 CNCF가 관리한다.

[ 애드온 컴포넌트 ]

  • kube-flannel : kube-flannel은 모든 노드에서 실행되어 여러 노드 사이에서 IPv4 네트워크를 제공한다.
    이에 따라 컨테이너는 k8s 클러스터 내부에서 사용되는 IP 주소를 바탕으로 다른 노드에 있는 파드와 통신이 가능하다.
    네트워크 접근 제어가 필요하다면 calico를 사용해야한다.

  • calico-kube-controllers : calico를 위한 컨트롤러.
    데이터 스토어로서 etcd를 이용하기 위해 사용된다.

  • calico-node : 모든 노드에서 실행되어 노드 간 파드 통신, 라우팅, 네트워크 접근 관리 기능을 제공한다.

  • kubernetes-dashboard : Web 대시보드

  • heapster : kubelet에 내장된 cAdvisor로부터 매트릭 정보를 수집. 그러나 1.11부터 지원 중단

  • metrics-server : heapster를 대신하여 1.8부터 도입되었다.
    API의 aggregation layer를 통해 k8s 클러스터 전체로부터 메트릭을 수집한다.

3.2 쿠버네티스 계층 구조

  • 클라이언트의 역할
  1. 오브젝트 생성 / 변경 / 삭제 요구
  2. 상태 조회
  • 마스터의 역할
  1. K8s 클러스터 관리
  2. 파드(컨테이너) 관리
  • 노드의 역할
  1. 컨테이너 실행 환경
  • 컨테이너의 종류
  1. 애플리케이션
  2. 미들웨어
  3. 실행 환경 유지

마스터 노드의 역할

  1. 쿠버네티스의 API서버로서 클라이언트로부터의 명령을 받아들여 실행
  2. 컨테이너를 파드 단위로 스케줄링 및 삭제
    여기서 말하는 스케줄링은 파드를 실행할 노드를 정하는 것을 의미
  3. 파드의 컨트롤러 기능과 외부 리소스 관리

[ Pod 생성 요청 시 흐름 ]

  1. 사용자 kubectl create 명령 으로 pod 생성 요청
  2. kube-api server 로 전달
  3. etcd 에 파드 입력 정보 저장(etcd는 쿠버네티스에서 여러 정보를 저장하는 디비 역할)
  4. kube-scheduler가 각각 노드의 자원을 체크, watch 기능으로 etcd에 파드 생성 요청이 들어온게 있는지 감시
    4-1. node 자원 상태 확인 후 pod가 어느 노드에 할당되면 좋을지 판단
    4-2. etcd에 node 정보 붙여줌
  5. work node 의 kubelet이 kube-apiserver를 감시하고 있다가 pod 정보가 있으면 가져와서 pod 생성
  6. kublet > 도커한테 컨테이너 생성 요청
  7. kublet > kube-proxy 네트워크 생성 요청
    7-1. 모든 노드에 이미 kube-proxy 생성되어져 있음.
    kube-proxy가 container 에 네트워크 설정 도와줌

3.3 쿠버네티스의 API 오브젝트

쿠버네티스 API 리소스의 개요를 살펴보자.

쿠버네티스에서 사용되는 API 리소스 타입의 이름은 IT 업계에서 관용적으로 사용해던 용어와
다소 다른 의미로 사용되니 주의하자.

쿠버네티스 API란?
쿠버네티스의 모든 조작은 API를 통해 이루어진다.

CLI 인터페이스인 kubectl은 마스터 노드 상의 kube-apiserver에게 쿠버네티스 API 규약에 맞게
기술된 목표 상태 선언서인 YAML 형식 또는 JSON 형식으로 전송하여 오브젝트를 만들고 바꾸고 제거한다.

또한 다양한 프로그램 언어로 API 라이브러리가 제공된다. 예를 들면 파이썬, Go 언어를 사용하여
쿠버네티스 운영을 자동화 하는 것이 가능하다.

오브젝트란?
k8s 오브젝트란 k8s 클러스터 내부의 엔터티로서 이후 설명할 파드, 컨트롤러, 서비스 등의 인스턴스를 의미

각 오브젝트는 메타데이터에 기술된 이름에 의해 식별되며 오브젝트를 만들 때는 반드시 이름을 부여해야한다.
같은 종류의 오브젝트 이름은 하나의 네임스페이스에서 반드시 유일해야한다.

네임스페이스(Namespace)는 K8s 클러스터를 논리적으로 분할하여 사용하기 위해 존재하는 기능이다.
예를 들어 쿠버네티스의 시스템 관련 기능을 수행하는 오브젝트들은 일반적인 애플리케이션들과 구별하기 위해
kube-system이 만들어지고 kubectl의 유효 범위는 지정한 네임스페이스로 제한된다.

워크로드(Workload)
워크로드란 오브젝트의 카테고리를 나타내는 용어로 컨테이너와 파드, 그리고 컨트롤러의 그룹을 의미한다.

컨테이너(Container)
쿠버네티스는 컨테이너만을 독자적으로 실행하는 것이 불가능하며, 반드시 파드 내에서 실행해야한다.

컨테이너 기동 시 설정할 수 있는 항목은 이미지의 이름, 실행 명령어, 실행 인자, 환경 변수, 볼륨, CPU 사용 시간과 메모리 크기의 요청값 및 상한값 등이 있다.

파드(Pod)
파드는 컨테이너를 실행하기 위한 오브젝트이다.
하나의 파드에는 하나 또는 여러개의 컨테이너가 구동할 수 있다.
이 구조는 마치 완두콩이 콩을 담고 있는 모양과 비슷하다.
그래서 꼬투리를 의미하는 영어 단어 Pod이 이름이 되었다.

컨트롤러(Controller)
컨트롤러는 파드의 실행을 제어하는 오브젝트로, 여러 종류의 컨트롤러가 있어 각 컨트롤러의 기능을 이해하고
목적에 맞게 적절히 구별해 사용해야한다.

예를 들어, 클라이언트-서버 모델에 적합한 디플로이먼트 컨트롤러는 서버가 돌아가는 파드의 개수가
지정한 숫자보다 적으면 자동으로 지정한 개수가 되도록 파드를 기동시킨다.

배치를 위한 잡 컨트롤러는 배치 처리가 정상 종료될 때 까지 재실행을 반복한다.

설정(Configuration)
컨테이너 내 애플리케이션의 설정값이나 비밀번호 등의 정보를 저장할 수 있는 ConfigMap과 Secret이라는 오브젝트가 있다.

이들을 통해 네임스페이스에 저장된 정보는 컨테이너 내의 파일이나 환경 변수를 통해 애플리케이션에서 참조할 수 있다.

서비스(Service)
k8s의 서비스는 파드와 클라이언트를 연결하는 역할을 수행한다.
서버 역할의 파드가 클라이언트의 요청을 받을 수 있도록 대표 IP 주소를 취득하여 내부 DNS에 등록한다.
그리고 대표 IP의 주소로서 요청 트래픽을 지정된 파드들에 부하분산하여 전송하는 역할을 수행한다.

스토리지(Storage)
파드나 컨테이너는 실행 시에만 존재하는 일시적인 존재이므로 중요한 데이터를 저장하기 위한 공간이 필요하다.
이를 위한 퍼시스턴트 볼륨을 사용하여 전원이 꺼져도 데이터가 유지되는 스토리지 시스템이다.

다만 복수의 노드에서 접속 가능한 퍼시스턴트 볼륨은 쿠버네티스의 범위에 포함되지 않으므로
외부 스토리지 시스템을 연동해야한다.

3.4 파드의 기본

하나의 파드에 속하는 모든 컨테이너는 같은 노드에서 동작한다.

컨테이너 재사용 촉진을 위한 플랫폼
파드는 하나의 목적을 위해 만들어진 컨테이너를 부품처럼 조합할 수 있도록 설계되었다.

  1. 파드 내부의 컨테이너는 파드의 IP 주소와 포트번호를 공유한다.
  2. 파드 내부 컨테이너들은 localhost로 서로 통신할 수 있다.
  3. 파드 내부 컨테이너들은 System V 프로세스 통신이나 POSIX 공유 메모리를 사용하여 서로 통신할 수 있다.
  4. 파드의 내부 컨테이너들은 파드의 볼륨을 마운트하여 파일 시스템을 공유할 수 있다.

파드는 일시적 존재
파드는 일시적인 존재이며 나타났다, 사라지기를 반복한다.

IP도 고정적이지 않다.
그래서 파드에 요청을 보내고 싶다면 반드시 서비스가 필요로하게 된다.

파드는 컨테이너의 실행 상태를 관리
파드는 활성 프로브와 준비 상태 프로브를 설정하여 내부 애플리케이션의 상태를 감시할 수 있다.

활성 프로브를 설정하면 애플리케이션이 멈춰있는 상태를 감지하여 컨테이너를 강제 종료 시킬 수 있고,
준비 상태 프로브를 설정하면 파드가 요청을 받을 준비가 될 때까지 서비스 오브젝트가 요청을 전송하지 않는다.

파드는 초기화 전용 컨테이너를 실행

3.5 파드의 라이프 사이클

k8s의 트러블 슈팅 중 가장 많이 발생하는 것이 바로 파드의 기동 실패 원인 분석이다.

이 문제를 파악하기 위해서는 kubectl get pods를 실행했을 때 나타나는 STATUS 열의 정보가 중요하다.

이 필드의 정보는 k8s API를 통해 획득하는데, 이 API를 통해 얻을 수 있는 여러 정보 중 도움이 될 만한 정보가 선별되어 STATUS 열에 표현되기 때문이다.

기본적으로 익히 잘 알고 있는

  1. Pending : 파드 생성 요구를 받았지만 생성이 덜 된 상태

  2. Running : 정상 구동 중

  3. Failed : 파드 내에 적어도 하나 이상의 컨테이너 종료

  4. Succeeded : 파드 내 모든 컨테이너가 정상적으로 종료

  5. Unknown : 파드 상태 불명

  6. ContainerCreating : 이미지를 다운로드 중이거나 컨테이너를 생성하는 중
    컨피그맵과 시크릿이 마운트되지 않아 컨테이너 생성이 보류되는 경우일 수 있음

  7. CrashLoopBackOff : 굉장히 빈번하게 발생하는 상태 중 하나이다.
    파드 내의 컨테이너가 종료되어 다음 기동 시 까지 대기 상태에 있음을 의미한다.
    2회 이상 컨테이너가 종료되면 CrashLoopBackOff 시간 동안 대기하게 된다.
    이 경우 컨테이너 내의 프로세스를 검토할 필요가 있다.

  8. Terminating : 컨테이너에 종료 요청 시그널을 보낸 후 컨테이너가 종료할 때까지 대기 중임을 의미.
    유예 시간을 넘겨도 컨테이너가 종료할 수 없는 경우 컨테이너를 강제 종료한다.

  9. Completed : 파드 내 컨테이너 정상 종료.

  10. Error : 컨테이너가 이상 종료된 경우.
    Exit 코드가 0이 아닌 경우 발생한다.

3.6 파드의 종료 처리

k8s는 종료 요청 시그널을 받은 컨테이너의 애플리케이션이 일정 시간 내에 종료 처리를 완료하고
정상 종료되도록 요구하고 있다.

이 종료처리의 흐름은 아래와 같다.

  1. 사용자가 kubectl delete pod을 실행하면 파드가 종료되기 시작한다. 기본 유예 시간은 30초다

  2. kubectl get pod의 status는 Terminating이 표시된다.

  3. 다음 세 가지 작업이 동시에 진행된다.

  • 파드의 PreStop hook이 정의되어있다면 파드 내에서 호출된다.
    유예 시간을 넘으면 PreStop hook이 실행되더라도 파드 내의 메인 프로세스에 SIGTERM이 보내지며, 2초 후에 SIGKILL로 강제 종료된다.

  • PreStop hook이 정의되어있지않다면 곧바로 파드 내의 메인 프로세스에 SIGTERM 신호가 송된되며 종료 처리가 개시된다.

  • 파드가 서비스의 엔드포인트 목록에서 제거되며 로드 밸런서(kube-proxy등)의 목록에서도 제거된다.

  • 유예 시간을 넘어서서 파드 내의 프로세스가 살아 있다면 파드의 메인 프로세스에 SIGKILL을 보내서 강제로 종료한다.

  • 제거 대상인 파드가 표시되지 않게 한다.

또한, kubectl delete를 실행할 때, 옵션 '--grace-period=초'를 통해 유예 시간을 별도로 지정할 수 있다.
0 으로 지정 시, 즉시 파드를 제거한다.

3.7 클러스터 네트워크

k8s 클러스터 내부에서 사용되는 클러스터 네트워크에 대해 알아보자.
파드는 이 네트워크 상의 IP 주소를 부여받아 다른 노드에 있는 파드와 서로 통신한다.

서비스의 IP 주소나 포트번호를 K8s 클러스터 외부 네트워크에서 접근할 수 있게 하려면
서비스 타입을 NodePort 혹은 LoadBalancer로 설정하거나 인그레스를 함께 사용하면 된다.

아래는 2개의 대표적인 오픈 소스 네트워크 에드온이다.

Flannel
간단한 L3 네트워크를 노드 간에 구축한다.

Flannel 파드는 데몬셋 컨트롤러에 의해 배포된다.
때문에 클러스터에 새로운 노드가 추가되면 자동적으로 파드 네트워크가 확장된다.

Flannel은 단순 네트워크 기능만 지원하며 ACL 기능은 지원하지 않는다.

Calico
노드 간 파드 통신에 더해 ACL 기능을 제공한다.

3.8 서비스의 기본

서비스의 필요성은 파드가 기동할 때 마다 IP 주소가 계속해서 바뀌기 때문이다.
파드에 접속해야하는 클라이언트는 서비스가 가지는 대표 IP를 사용해 접속해야한다.

서비스의 역할에 대해서 조금 더 자세히 알아보자.

  1. 서비스는 로드밸런서의 역할을 가지며 대표 IP 주소를 획득한다.

  2. 서비스의 이름은 내부 DNS에 등록되기 때문에 클라이언트는 서비스의 이름만으로 서비스의 IP 주소를 획득할 수 있다.

  3. 서비스는 셀렉터에 저장된 라벨과 일치하는 파드 중 하나에게 요청을 전송한다.

  4. 서비스가 만들어지고 나서 기동된 파드의 컨테이너에는 서비스에 대한 정보가 담긴 환경 변수가 자동으로 설정된다.

  5. 서비스에는 네 종류의 서비스 타입이 있어 클라이언트의 범위를 k8s 클러스터 내부로 한정할지, 외부까지 확장할지, 또한 k8s 클러스터 외부의 IP 주소에 전송할지를 설정한다.

3번에 대한 조금 더 자세한 내용은 다음과 같다.

파드는 기동될 때 라벨이나 IP 주소를 포함한 자신의 오브젝트 정보를 마스터 노드의 etcd에 등록한다.

그래서 서비스의 전송처를 결정할 때 셀렉테(selector)의 라벨에 일치하는 파드를 etcd에서 조회하여 전송할 파드의 IP 주소를 취득한다.

이처럼 라벨에 의해 대상 오브젝트를 결정하는 것이 k8s의 기본 동작이다.

서비스의 기능을 이해할 때 중요한 7개의 키워드는 다음과 같다.

1. 대표 IP 주소
서비스는 파드의 그룹을 대표해 클라이언트의 요청을 받을 대표 IP 주소를 가진다.

헤드리스로 지정한 경우에는 대표 IP 주소를 획득하지 않고, 파드의 IP 주소를 직접 내부 DNS에 설정한다.

2. 부하분산
서비스의 대표 IP 주소에 도착한 요청은 셀렉터의 라벨과 일치하는 파드에 전송된다.

3. 이름 해결
서비스는 IP 주소와 서비스명을 k8s 클러스터 내부의 DNS에 등록한다.

그래서 클러스터 내의 파드에서는 서비스 이름으로 파드에 접근하는 것이 가능하다.

4. 환경 변수
서비스가 만들어지나고 나서 생성되는 파드의 컨테이너에는 환경 변수가 설정되어있다.

5. 서비스 타입
서비스를 설정할 때는 해당 서비스를 이용하는 클라이언트를 고려하여 서비스 타입을 지정할 수 있다.

6. 어피니티
기본적으로 부하분산에 사용되는 알고리즘은 랜덤이다.

클라이언트에 따라 전송되는 파드를 고정시키고 싶다면 sessionAffinity 항목에 ClientIP를 설정한다.

HTTP 헤더안의 쿠키 값에 따라 전송되는 파드를 고정시키고 싶다면 인그레스를 이용해야한다.

7. 셀렉터와 라벨
서비스에 도달한 요청 트래픽이 파드에 전송될 때 셀렉터와 라벨을 참조한다.

3.9 컨트롤러의 기본

컨트롤러는 파드를 제어한다.

파드에게 부여할 워크로드의 타입, 처리에 따라 적절한 컨트롤러를 설정해야한다.

이 세션에서는 워크로드와 컨트롤러의 특징을 살펴보자.

1. 워크로드 타입

  • 프론트엔드 처리

스마트폰, IoT, 컴퓨터 등 클라이언트로부터 요청을 받아들이는 워크로드를 총칭한다.
이 타입의 워크로드는 대량의 클라이언트 요청에 대해 짧은 시간에 응답을 반환해주는 것이 중요하다.

  • 백엔드 처리

백엔드는 요쳥량이 변하더라도 일정한 응답속도를 유지해주어야한다.
또한 요구사항에 맞게 단 기간에 기능을 추가하고 변경하는 것이 가능해야한다.

  • 배치 처리

배치 처리는 어떤 트리거에 의해 실행되며 대용량 데이터 전송에 주로 사용된다.

  • 시스템 운영 처리

시스템 운영을 돕기 위해 k8s API를 사용하기도 한다.
구글이 강조하는 SRE는 소프트웨어 기술자가 시스템 운영의 자동화에 집중하여 효율적인 시스템 운영을 실현한다.

2. 컨트롤러 타입

컨트롤러는 앞서 살펴본 워크로드를 처리하기 위해 파드를 제어하고 실행하는 역할을 담당한다.

대표적인 컨트롤러 7개의 역할과 특징은 다음과 같다.

  • 디플로이먼트(Deployment)

대등한 관계에 있는 여러 개의 파드로 수평한 클러스터를 구성할 때 사용한다.
가동중인 파드를 차례대로 교체하거나 규모를 조절할 수 있는 기능을 갖추고 있다.

  • 스테이트풀셋(StatefulSet)

파드와 퍼시스턴트 볼륨을 조합하여 데이터의 보관에 초점을 둔 컨트롤러이다.

  • 잡(Job)

배치 처리를 하는 컨테이너가 정상 종료할 때까지 재실행을 반복하는 컨트롤러이다.

  • 크론잡(CronJob)

정해진 시간에 정기적으로 앞서 설명한 잡을 생성한다.

  • 데몬셋(DaemonSet)

k8s 클러스터의 모든 노드에서 같은 파드를 실행하기 위해 존재한다.

  • 레플리카셋(ReplicaSet)

디플로이먼트 컨트롤러와 연동해 파드가 기동해야하는 수를 관리한다.
레플리카셋은 직접 다루기보다는 디플로이먼트를 통해 이용하는 것이 기본이다.

  • 레플리케이션 컨트롤러(Replication Controller)

(구) 디플로이먼트 지금은 안쓴다.

노드의 스케일업과 관련하여

CPU 코어수를 늘리거나 메모리 증설 등 노드의 스케일업과 관련된 기능은 컨트롤러에서 담당하지않는다.

이러한 노드 스케일 업은 클라우드의 경우 보다 많은 CPU 코어 수나 메모리 용량을 탑재한 노드를 준비해서
k8s에 추가 후, 파드의 노드 셀렉터를 설정해 마이그레이션해야한다.

profile
Back-end Developer

0개의 댓글