Today I Learned

[쿠버네티스 인 액션] 4. 레플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포 (1) 본문

쿠버네티스

[쿠버네티스 인 액션] 4. 레플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포 (1)

하이라이터 2022. 8. 16. 02:25
728x90

4장에서 다루는 내용

  • 파드의 안정적인 유지
  • 동일한 파드의 여러 인스턴스 실행
  • 노드 장애 시 자동으로 파드 재스케줄링
  • 파드의 수평 스케줄링
  • 각 클러스터 노드에서 시스템 수준의 파드 실행
  • 배치 잡 실행
  • 잡을 주기적 또는 한 번만 실행하도록 스케줄링

4.1 파드를 안정적으로 유지하기

  • 애플리케이션에서 특별한 작업을 하지 않더라도 쿠버네티스는 실행중인 애플리케이션에서 크러시가 발생하면 자동으로 재시작한다.
  • 하지만 애플리케이션이 무한 루프나 교착 상황에 빠져서 응답을 하지 않는 상황 등 예외 상황이 존재한다. 따라서 애플리케이션 내부 기능에 의존하지 말고 외부에서 애플리케이션의 상태를 체크해야 한다.

4.1.1 라이브니스 프로브 소개

  • 라이브니스 프로브(liveness probe)를 통해 컨테이너가 살아있는지 확인할 수 있다.
  • 파드의 스펙에 각 컨테이너의 라이브니스 프로브를 지정할 수 있다.
  • 프로브의 실행에는 세 가지 메커니즘이 사용된다.
    • HTTP GET 프로브는 지정한 IP 주소, 포트, 경로에 HTTP GET 요청을 수행한다. 서버가 오류 응답 코드를 반환하거나 전혀 응답하지 않으면 프로브가 실패한 것으로 간주돼 컨테이너를 다시 시작한다.
    • TCP 소켓 프로브는 컨테이너의 지정된 포트에 TCP 연결을 시도해 연결 여부를 확인한다.
    • Exec 프로브는 컨테이너 내의 임의의 명령을 실행하고 명령의 종료 상태 코드를 확인한다. 상태 코드가 0이 아니라면 실패로 간주한다.


4.1.2 HTTP 기반 라이브니스 프로브 생성

  • 라이브니스 프로브 데모를 위해 다섯 번째 이후의 요청부터는 500 Internal Server Error HTTP 상태 코드를 반환하는 애플리케이션을 만들어보자.
  • 그리고 HTTP GET 라이브니스 프로브를 포함된 새 파드를 생성한다.
apiVersion: v1
kind: Pod
metadata:
  name: kubia-liveness
spec:
  containers:
  - image: luksa/kubia-unhealthy #약간의 문제가 있는 애플리케이션을 포함한 이미지
    name: kubia
    livenessProbe: #라이브니스 프로브
      httpGet:
        path: /
        port: 8080

4.1.3 동작중인 라이브니스 프로브 확인

  • kubectl get을 실행해보면 RESTARTS 열에서 파드가 한번 재시작했음을 보여준다.

  • 다음 이미지처럼 kubectl describe로 출력되는 내용을 보면 컨테이너가 재시작된 이유를 확인할 수 있다.
  • 컨테이너가 현재 실행중이지만 오류로 인해 이전에 종료된 것을 알 수 있다.
  • 종료 코드 137은 프로세스가 외부 신호에 의해 종료됐음을 나타낸다. 137은 128+x를 의미하며, x는 프로세스에 전송된 시그널 번호이다. 여기서 x는 SGKILL 시그널번호인 9이다. 
  • 아래쪽에 나열된 events는 컨테이너가 종료된 이유를 보여준다.


4.1.4 라이브니스 프로브의 추가 속성 설정

  • kubectl describe는 라이브니스 프로브에 관한 추가적인 정보도 표시된다는 것을 알 수 있다.
  • 명시적으로 지정한 라이브니스 프로브 옵션 외에도 지연(delay), 제한 시간(timeout), 기간(period) 등과 같은 추가 속성을 볼 수 있다. 이런 추가적인 매개변수는 프로브를 정의할 때 지정할 수 있다.
  • 컨테이너가 시작된 후 바로 프로브가 시작되고(delay=0s), 1초 안에 응답해야 하며(timeout=1s), 10초마다 프로브를 수행하고(period=10s), 연속 3번 실패하면(failure=3) 재시작된다.


4.1.5 효과적인 라이브니스 프로브 생성

  • 운영 환경에서 실행중인 파드는 반드시 라이브니스 프로브를 정의해야한다.
  • 프로세스가 실행되는 한 쿠버네티스는 컨테이너가 정상적이라고 간주할 것이다.

라이브니스 프로브가 확인해야 할 사항

  • 단순히 서버가 응답하는지를 넘어 특정 URL 경로에 요청하도록 프로브를 구성해 애플리케이션 내에서 실행중인 모든 주요 구성 요소가 살아 있는지 또는 응답이 없는지 확인하도록 구성할 수 있다.
  • 라이브니스 프로브는 애플리케이션의 내부만 체크하고, 외부 요인의 영향을 받지 않도록 해야한다.
  • 예를 들어 프론트엔드 웹서버의 라이브니스 프로브는 웹서버가 백엔드 데이터베이스에 연결할 수 없을 때 실패를 반환해서는 안된다. 근본적인 원인이 데이터베이스에 있다면 웹서버 컨테이너를 재시작하더라도 문제가 해결되지 않는다.

프로브를 가볍게 유지하기

  • 라이브니스 프로브가 너무 많은 연산 리소스를 사용해서는 안되고, 완료하는 데 너무 오래 걸리지 않아야 한다. 기본적으로 1초 내에 완료돼야 한다.
  • 프로브의 CPU 사용 시간은 컨테이너의 CPU 시간 할당량으로 계산되므로, 무겁게 만들면 메인 애플리케이션 프로세스가 사용 가능한 리소스가 줄어들게 된다.

프로브에 재시도 루프를 구현하지 마라

  • 프로브에 실패 임곗값을 1로 설정하더라도, 쿠버네티스는 실패로 간주하기 전에 프로브를 여러 번 재시도한다. 따라서 프로브에 자체적인 재시도 루프를 구현하는 것은 헛수고이다.

4.2 레플리케이션 컨트롤러 소개

  • 레플리케이션 컨트롤러는 파드가 항상 실행되도록 보장하며, 사라진 파드가 감지되면 교체 파드를 생성한다.
  • 일반적으로 레플리케이션 컨트롤러는 파드의 여러 복제본(레플리카)을 작성하고 관리한다. 


4.2.1 레플리케이션 컨트롤러의 동작

  • 레플리케이션 컨트롤러는 실행 중인 파드 목록을 지속적으로 모니터링하고, 파드 수가 의도하는 수와 일치하는지 확인한다.
  • 의도하는 파드 수보다 더 많이 생성되는 경우도 있는데 다음과 같은 이유로 발생할 수 있다.
    • 누군가 같은 유형의 파드를 수동으로 생성
    • 누군가 기존 파드의 유형(type)을 변경
    • 누군가 의도하는 파드 수를 줄임

컨트롤러 조정 루프 소개

레플리케이션 컨트롤러의 세 가지 요소 이해

  • 레이블 셀렉터(label selector) : 레플리케이션 컨트롤러의 범위에 있는 파드를 결정
  • 레플리카 수(replica count) : 실행할 파드의 의도하는 수를 지정
  • 파드 템플릿(pod template) : 새로운 파드 레플리카를 만들 때 사용

컨트롤러의 레이블 셀렉터 또는 파드 템플릿 변경의 영향 이해

  • 레이블 셀렉터와 파드 템플릿을 변경해도 기존 파드에는 영향을 미치지 않는다.
  • 레이블 셀렉터를 변경하면 기존 파드가 레플리케이션 컨트롤러의 범위를 벗어나므로 컨트롤러가 해당 파드에 대한 관리를 중지한다.
  • 또한 레플리케이션 컨트롤러는 파드를 생성한 후에는 파드의 실제 콘텐츠(컨테이너 이미지, 환경변수 및 기타사항)에 신경을 쓰지 않는다.
  • 따라서 템플릿은 이 레플리케이션 컨트롤러로 새 파드를 생성할 때만 영향을 미친다.

레플리케이션 컨트롤러 사용 시 이점

  • 기존 파드가 사라지면 새 파드를 시작해 파드가 항상 실행되도록 한다.
  • 클러스터 노드에 장애가 발생하면 장애가 발생한 노드에서 실행중인 모든 파드에 관한 교체 복사본이 생성된다.
  • 수동 또는 자동으로 파드를 쉽게 수평으로 확장할 수 있다.


4.2.2 레플리케이션 컨트롤러 생성

  • 레플리케이션 컨트롤러를 위한 yaml 파일을 만든다.
apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    app: kubia
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia
        ports:
        - containerPort: 8080
$kubectl create -f kubia-rc.yaml
  • 레이블 셀렉터 app=kubia와 일치하는 파드 인스턴스가 세 개를 유지하도록 하는 kubia라는 이름의 레플리케이션 컨트롤러를 생성한다.
  • 템플릿의 파드 레이블은 레이블 셀렉터와 완전히 일치해야 한다. 그렇지 않으면 새 파드가 무한정 생성될 수 있다. 이 경우를 방지하기 위해 api 서버는 레플리케이션의 정의를 검증하고 잘못된 경우 받아들이지 않는다.
  • 셀렉터를 지정하지 않으면 템플릿의 레이블로 자동 설정된다.


4.2.3 레플리케이션 컨트롤러 작동 확인

  • 파드를 조회해 레플리케이션 컨트롤러가 해야할 작업을 수행했는지 확인해보자.

삭제된 파드에 관한 레플리케이션 컨트롤러의 반응 확인

  • 파드 중 하나를 수동으로 삭제해서, 컨트롤러가 어떻게 새로운 파드를 즉시 기동하는지 확인한다.

  • 파드를 다시 조회하면 4개가 표시된다. 이는 삭제한 파드가 종료중(Terminating)이고 새 파드는 이미 생성됐기 때문이다.

레플리케이션 컨트롤러 정보 얻기

  • 다음 명령으로 레플리케이션 컨트롤러의 정보를 살펴보자.
$kubectl get rc

  • 다음과 같이 kubectl describe 명령을 사용해 추가 정보를 볼 수 있다.

컨트롤러가 새로운 파드를 생성한 원인 정확히 이해하기

  • 컨트롤러는 삭제되는 파드에 대해 즉시 통지를 받지만(API 서버는 클라이언트가 리소스 및 리소스 목록의 변경을 감시할 수 있도록 허용한다), 이 통지 자체가 대체 파드를 생성하게 하는 것은 아니다.
  • 이 통지는 컨트롤러가 실제 파드 수를 확인하고, 적절한 조치를 취하도록 하는 트리거 역할을 한다.

노드 장애 대응

  • 레플리케이션 컨트롤러는 노드의 파드가 다운됐음을 감지하자마자 파드를 대체하기 위해 새로운 파드를 기동한다.
  • 실습을 위해 먼저 다음 명령어로 파드가 실행중인 노드들을 확인한다.
$kubectl get pods -o wide

  • 다음 명령어를 통해 파드가 실행중인 노드 중 하나에 ssh로 접속한다.
$gcloud compute ssh gke-kubia-pool-1-01349329-nw03

  • 그리고 다음 명령어로 네트워크 인터페이스를 종료한다.
$sudo ifconfig eth0 down
  • 이제 새로운 터미널에서 노드를 조회하면 노드가 다움된 것을 쿠버네티스가 감지해서 NotReady로 표시된다.

  • 지금 파드를 조회하면 쿠버네티스가 파드를 다시 스케줄링하기 전에 잠시 대기하기 때문에(일시적인 네트워크 결함이나 kubelet이 다시 시작하는 이유로 노드에 도달할 수 없는 경우) 이전과 동일하게 세 개의 파드로 계속 표시된다.
  • 노드가 몇 분 동안 접속할 수 없는 상태로 유지될 경우 해당 노드에 스케줄된 파드의 상태가 알 수 없음(unknown)으로 변경되고 새로운 파드가 기동된다.
  • (그런데 책과는 다르게 실습에서는 Terminating 상태로 변경되었다.)

  • 노드를 되돌리려면 다음 명령으로 노드를 재설정해야 한다.
$gcloud compute instances reset gke-kubia-defualt-pool-1-01349329-nw03
  • 노드가 다시 부팅되면 노드가 준비(Ready) 상태로 돌아오고, 알 수 없는(unknown) 상태의 파드는 삭제된다.

4.2.4 레플리케이션컨트롤러의 범위 안팎으로 파드 이동하기

  • 컨트롤러가 생성한 파드는 컨트롤러와 묶이지 않으며, 컨트롤러는 레이블 셀렉터와 일치하는 파드만을 관리한다.
  • 파드의 레이블을 변경하면 컨트롤러의 범위에서 제거되거나 추가될 수 있다.
  • 파드의 레이블을 변경해 컨트롤러의 레이블 셀렉터와 일치하지 않게 만들면 파드는 더이상 관리되지 않게되며, 컨트롤러는 사라진 파드를 대체하기 위한 새로운 파드를 기동한다.
  • 컨트롤러는 파드에 추가 레이블이 있는지 상관하지 않으며 오직 파드가 레이블 셀렉터에서 참조하는 모든 레이블을 갖고 있는지만 고려한다.

레플리케이션컨트롤러가 관리하는 파드에 레이블 추가

  • 관리되는 파드에 레이블을 추가하더라도 레플리케이션컨트롤러가 상관하지 않는지 확인해보자.
$kubectl label pod kubia-dx6x4 type=special
$kubectl get pods --show-labels

  • 파드 중 하나에 type=special 라벨을 추가하더라도 컨트롤러와 관련해서 어떤 변경도 발생하지 않았기 때문에 전체 파드를 조회하면 여전히 파드 세 개가 표시된다.

관리되는 파드의 레이블 변경

  • 파드가 더이상 컨트롤러의 레이블 셀렉터와 일치하지 않도록 변경해보자.
$kubectl label pod kubia-dx6x4 app=foo --overwrite
  • overwrite 인수가 없으면 경고만 표시되고 레이블이 변경되지 않는다.
kubectl get pods -L app

  • 전체 파드를 다시 조회해보면 네 개의 파드가 표시된다.
  • kubia-dx6x4는 이제 독자적인 파드가 됐으며, 수동으로 삭제할 때까지 계속 실행된다.

컨트롤러에서 파드를 제거하는 실제 사례

  • 파드가 오작동하는 것을 발견했다면 레플리케이션컨트롤러의 범위 밖으로 빼내 새 파드로 교체하도록 한 다음, 원하는 방식으로 파드를 디버그하거나 문제를 제연해볼 수 있다. 완료되면 파드를 삭제한다.

레플리케이션컨트롤러의 레이블 셀렉터 변경

  • 파드의 레이블은 변경하는 대신 레플리케이션컨트롤러의 레이블 셀렉터를 수정하면 모든 파드가 컨트롤러의 범위를 벗어나므로 세 개의 새로운 파드가 생성된다.

4.2.5 파드 템플릿 변경

  • 레플리케이션컨트롤러의 파드 템플릿을 수정하더라도 기존 파드에는 영향을 주지 않으며 새로운 파드에만 적용된다.

  • 다음 명령을 사용해 레플리케이션 컨트롤러를 편집할 수 있다.
$kubectl edit rc kubia
  • 파드 템플릿 섹션을 찾아 메타데이터에 레이블을 수정하고 신규 파드로 교체되도록 하면 새로운 레이블을 갖는 파드를 볼 수 있다.


4.2.6 수평 파드 스케일링

레플리케이션컨트롤러 스케일 업(확장)하기

  • 레플리케이션컨트롤러가 최대 10개의 파드 인스턴스를 유지하도록 조정해보자.
$kubectl scale rc kubia --replicas=10
  • 위 명령어를 사용할 수도 있지만 이번에는 다른 방식을 사용한다.

레플리케이션컨트롤러의 정의를 편집해 스케일링하기

  • 레플리케이션컨트롤러의 정의를 편집해 선언적인 방식으로 확장할 것이다.
$kubectl edit rc kubia

  • 파일을 저장하면 레플리케이션컨트롤러가 업데이트되고, 즉시 파드의 수가 10개로 확장된다.

  • kubectl scale 명령이 쿠버네티스에게 무엇을 해야할지 정확히 알려주는 것처럼 보인다면, 이제는 레플리케이션컨트롤러의 의도하는 상태를 선언적으로 변경한다는 것이 훨씬 명확해 보인다.

kubectl scale 명령으로 스케일 다운(축소)하기

  • 이제 이전 상태인 세 개로 축소해보자. 이 명령은 kubectl edit을 통해 변경했을 때와 같이 레플리케이션 컨트롤러 정의의 spec.replicas 필드의 값을 수정하는 것이다.
$kubectl scale rc kubia --replicas=3

스케일링에 대한 선언적 접근 방법 이해

  • 쿠버네티스에서 파드를 수평으로 확장한다는 것은 쿠버네티스에게 무엇을 하라고 말하는게 아니라 의도하는 상태를 지정할 뿐이다.
  • 이 선언적 접근 방식을 통해 쿠버네티스 클러스터와 쉽게 상호작용 할 수 있으며, 명시적인 방식보다 훨씬 적은 작업과 오류 발생율을 가진다.

4.2.7 레플리케이션컨트롤러 삭제

  • kubectl delete를 통해 레플리케이션컨트롤러를 삭제하면 파드도 삭제된다. 그러나 컨트롤러만 삭제하고 파드는 실행 상태로 둘 수도 있다.

  • 이 작업은 파드에 영향을 주지 않고 수행할 수 있으며 파드를 관리하는 레플리케이션컨트롤러를 교체하는 동안 중단없이 실행할 수 있다.
$kubectl delete rc kubia --cascade=false

728x90
Comments