Kubernetes 인 액션 4장 래플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포
Devops/Kubernetes

Kubernetes 인 액션 4장 래플리케이션과 그 밖의 컨트롤러: 관리되는 파드 배포

뉴비뉴 2023. 4. 22.

다루는 내용

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

노드 전체에 장애가 발생하면 노드에 있는 파드는 유실되며, 이전에 언급한 래플리케이션컨트롤러나 그와 유사한 기능을 하는 컨트롤러가 해당 파드를 관리하지 않는 한 새로운 파드로 대체되지 않는다.

4. 1 파드를 안정적으로 유지하기

파드가 노드에 스케줄링되는 즉시, 해당 노드의 kubelet은 파드의 컨테이너를 실행하고 파드가 존재하는 한 컨테이너가 계속 실행되도록 할 것이다. 컨테이너의 주 프로세스에 크래시가 발생하면 kubelet이 컨테이너를 다시 시작한다.

4.1.1 liveness probe 소개

쿠버네티스는 주기적으로 프로브를 실행하고 프로브가 실패할 경우 컨테이너를 다시 시작한다.

  • HTTP GET probe는 지정한 IP 주소, 포트, 경로에 HTTP GET 요청을 수행한다. probe가 응답을 수신하고 응답 코드가 오류를 나타내지 않는 경우 프로브가 성공했다고 간주된다.
  • TCP 소켓 probe는 컨테이너의 지정된 포트에 TCP 연결을 시도한다. 연결에 성공하면 프로브가 성공한 것이고, 그렇지 않으면 컨테이너가 다시 시작된다.
  • Exec probe는 컨테이너 내의 임의의 명령을 실행하고 명령의 종료 상태 코드를 확인한다. 상태 코드가 0이면 프로브가 성공한 것이다.

4.1.2 HTTP 기반 liveness probe 생성

웹 애플리케이션이므로 웹 서버가 요청을 처리하는지 체크하는 liveness probe를 추가하는 것이 좋다.

이 디스크립터는 Kubernetes가 주기적으로 “/” 경로와 8080포트에 HTTP GET을 요청해서 컨테이너가 정상 동작하는지 확인하도록 httpGet liveness probe를 정의한다.

 

kubectl describe로 컨테이너가 다시 시작 된 이유를 확인할 수 있다.

 

컨테이너가 현재 실행 중이지만 오류로 인해 이전에 종료된 것을 알 수 있다. 종료코드는 137이며 특별한 의미를 가진다. 이는 프로세스가 외부 신호에 의해 종료됐음을 나타낸다. 숫자 137은 두 숫자를 합한 값으로, 128 + x다. 여기서 x는 프로세스에 전송된 시그널 번호이며, 이 시그널로 인해 컨테이너가 종료됐다. x는 SIGKILL 시그널 번호인 9이며, 포르세스가 강제로 종료됐음을 의미한다.

 

|노트| 컨테이너가 종료되면 완전히 새로운 컨테이너가 생성된다. 동일한 컨테이너가 다시 시작되는 것이 아니다.

4.1.4 liveness probe의 추가 속성 설정

kubectl describe

Liveness: http-get http://:8080 delay=0s timeout=1s period=10s 
# success=1
# failure=3

지연(delay), 제한 시간(timeout), 기간(period) 등과 같은 속성을 볼 수 있다.

 

delay=0s 부분은 컨테이너가 시작된 후에 바로 probe가 시작된다는 것을 나타낸다. 제한 시간이 1초로 설정돼 있으므로 컨테이너가 1초 안에 응답해야 한다. 그렇지 않으면 probe가 실패한 것으로 카운트된다. 컨테이너는 10초마다 probe를 수행하며 probe가 3번 연속 실패하면 (#failure=3) 컨테이너가 다시 시작된다.

 

|팁| 애플리케이션 시작 시간을 고려해 초기 지연을 설정해야 한다는 점을 명심하자

LET ME) liveness probe 를 사용할 땐 너무 많은 일을 하는 것을 시켜서는 안된다. 그냥 간단하게 /health 로 요청을 보내 확인하는 간단한 방법으로 처리하는 것이 좋다. EX) 1초 이내 완료

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

레플리케이션컨트롤러는 Kubernetes 리소스로서 파드가 항상 실행되도록 보장한다.

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

레플리케이션컨트롤러는 실행 중인 파드 목록을 지속적으로 모니터링하고, 특정 “유형”의 실제 파드 수가 의도하는 수와 일치하는지 항상 확인한다.

 

레플리케이션컨트롤러는 파드 유형이 아니라 특정 레이블 셀렉터와 일치하는 파드 세트에 작동한다.

컨트롤러 조정 루프 소개

레플리케이션컨트롤러의 역할은 정확한 수의 파드가 항상 레이블 셀렉터와 일치하는지 확인하는 것이다. 그렇지 않은 경우 레플리케이션컨트롤러는 의도하는 파드 수와 실제 파드 수를 일치시키기 위한 적절한 조치를 취한다.

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

  • 레이블 셀렉터는 레플리케이션컨트롤러의 범위에 있는 파드를 결정한다.
  • 레플리카 수는 실행할 파드의 의도하는 수를 지정한다.
  • 파드 템플릿은 새로운 파드 레플리카를 만들 때 사용한다.

레이블 셀럭터와 파드 템플릿을 변경해도 기존 파드에는 영향을 미치지 않는다. 레이블 셀럭터를 변경하면 기존 파드가 레플리케이션컨트롤러의 범위를 벗어나므로 컨트롤러가 해당 파드에 대한 관리를 중지한다.

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

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

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

파일을 API 서버에 게시하면, Kubernetes는 레이블 셀렉터 app=kubia 와 일치하는 파드 인스턴스가 세 개를 유지하도록 하는 kubia라는 이름의 새로운 레플리케이션컨트롤러를 생성한다.

|팁| 레플리케이션컨트롤러를 정의할 때 파드 셀렉터를 지정하지 말라. Kubernetes가 파드 템플릿에서 이를 추출하도록 하라. 이렇게 하면 YAML을 좀 더 간결하고 단순하게 유지할 수 있다.

 

파드의 레이블을 변경하는 대신 레플리케이션컨트롤러의 레이블 셀렉터를 수정하면 모든 파드가 레플리케이션컨트롤러의 범위를 벗어나게 되기 때문에 세 개의 새로운 파드를 생성하게 될 것이라고 답했다면 정답이다.

 

LET ME) 전에 배웠듯이 kubectl label pod cslee-kg2fk app=special --overwrite 하면 기존의 app=cslee 라벨, 즉 3개의 파드를 바라보고 있던 라벨은 1개가 app=sepcial 로 변경되었기에 다시금 app=cslee 라벨의 Pod를 생성한다. 왜냐하면 app=cslee 는 레플리케이션컨트롤러로 관리되고 있기 때문에

4.2.6 수평 파드 스케일링

지금까지 레플리케이션컨트롤러가 특정 수의 파드 인스턴스를 항상 실행하도록 보장하는 방법을 살펴봤다.

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

$ kubectl scale rc cslee --replicas=10 (확장)

$ kubectl scale rc cslee --replicas=1 (축소)

or

$ kubectl edit rc cslee

spec:
  replicas: 3 -> 10

$ kubectl delete rc cslee --cascade=false

하게되면 rc 즉 레플리케이션컨트롤러만 삭제되고, Pod는 문제없이 남아있다.

LET ME) 만약 --cascade=true 로 되어 있다면 파드도 삭제된다.

4.3 레플리케이션컨트롤러 대신 레플리카셋 사용하기

레플리카셋ReplicaSet이라는 유사한 리소스가 도입됐다. (레플리케이션컨트롤러는 결국 사용되지 않게 될 것이다.)

LET ME) 하 참 이럴거면 진작 레플리카셋을 알려주지 왜!!!

4.3.1 레플리카셋과 레플리케이션컨트롤러 비교

레플리케이션컨트롤러는 레이블이 env=production인 파드와 레이블이 env=devel인 파드를 동시에 매칭시킬 수 없다. 그러나 레플리카셋은 하나의 레플리카셋으로 두 파드 세트를 모두 매칭시켜 하나의 그룹으로 취급할 수 있다.

4.3.2 레플리카셋 정의하기

가장 먼저 주목할 점은 레플리카셋이 v1 API의 일부가 아니다. -> apps/v1beta2

# 차이점은 셀럭터에 있다. 
# 레플리케이션컨트롤러의 경우 
selector: 
  app: cslee

# 레플리카셋의 경우 
selector: 
  matchLabels: 
    app: cslee

LET ME) 책을 수정해주고 싶다. apps/v1beta2 → apps/v1 정확한 명령어 찾는 법은 kubectl api-resources | grep 

4.3.4 레플리카셋의 더욱 표현적인 레이블 셀렉터 사용하기

레플리카셋 예제에서는 의도적으로 단순한 matchLabels 셀렉터를 사용해 레플리카셋이 레플리카컨트롤러와 다르지 않다는 것을 확인했다. 이제 더 강력한 matchExpression를 사용해보자

  • In은 레이블의 값이 지정된 값 중 하나와 일치해야 한다.
  • NotIn은 레이블의 값이 지정된 값과 일치하지 않아야 한다.
  • Exists는 파드는 지정된 키를 가진 레이블이 포함돼야 한다(값을 중요하지 않음) 이 연산자를 사용할 때는 값(value) 필드를 지정하지 않아야 한다.
  • DoesNotExist는 파드에 지정된 키를 가진 레이블이 포함돼 있지 않아야 한다. 값 필드를 지정하지 않아야 한다.

모든 표현식이 True 여야 한다. matchLabels와 matchExpressions를 모두 지정하면, 셀렉터가 파드를 매칭하기 위해서는, 모든 레이블이 일치하고, 모든 표현식이 true로 평가돼야 한다.

LET ME) 모든 레이블이 일치해야 되기 때문에 좀 더 명확하고 정확하게 필요한 것에 설정할 수 있겠다.

4.4 데몬셋을 사용해 각 노드에서 정확히 한 개의 파드 실행하기

레플리케이션컨트롤러와 레플리카셋은 Kubernetes 클러스터 내 어딘가에 지정된 수만큼의 파드를 실행하는 데 사용된다. 그러나 클러스터의 모든 노드에, 노드당 하나의 파드를 실행되길 원하는 경우가 있을 수 있다.

 

시스템 수준의 작업을 수행하는 인프라 관련 파드가 이런 경우다. 예를 들면 모든 노드에서 로그 수집기와 리소스 모니터를 실행하려는 경우가 좋은 예다. 또 다른 좋은 예는 Kubernetes의 kube-proxy 프로세스이며, 서비스를 작동시키기 위해 모든 노드에서 실행돼야 한다.

데몬셋은 각 노드에서 하나의 파드만 복제본만 실행하지만 레플리카셋은 클러스터 전체에서 무작위로 파드를 분산시킨다.

Kubernetes를 사용하지 않는 환경에서는 일반적으로 노드가 부팅되는 동안에 시스템 초기화 스크립트 또는 systemd 데몬을 통해 시작된다. Kubernetes 노드에서도 여전히 systemd를 사용해 시스템 프로세스를 실행할 수도 있지만, 그렇게 하면 Kubernetes가 제공하는 모든 기능을 최대한 활용할 수가 없다.

4.4.1 데몬셋으로 모든 노드에 파드 실행하기

데몬셋은 원하는 복제본 수라는 개념이 없다. 파드 셀렉터와 일치하는 파드 하나가 각 노드에서 실행 중인지 확인하는 것이 데몬셋이 수행해야하는 역할이기 때문에 복제본 개념이 필요하지 않다.

 

누군가 실수로 파드 중에 하나를 삭제해 노드에 데몬셋의 파드가 없는 경우에도 마찬가지다. 레플리카셋과 마찬가지로 데몬셋을 그 안에 구성된 파드 템플릿으로 파드를 생성한다.

4.4.2 데몬셋을 사용해 특정 노드에서만 파드를 실행하기

파드가 노드의 일부에서만 실행되도록 지정하지 않으면 데몬셋은 클러스터의 모든 노드에 파드를 배포한다.

데몬셋의 정의의 일부인 파드 템플릿에서 node-Selector 속성을 지정하면 된다.

$ kubectl get po No resources found

노드에 disk=ssd 레이블을 추가하는 것을 잊었다.

$ kubectl label node minikube disk=ssd node “minikube” labeld

$ kubectl label node minikube disk=hdd --overwrite

 

LET ME) 데몬셋에 label 을 hdd로 변경하게 되면 당연히 label에 없기에 파드는 삭제된다.

4.5 완료 가능한 단일 태스크를 수행하는 파드 실행

작업을 완료한 후에는 종료 되는 태스크만 실행하려는 경우가 있을 것이다.

완료 가능한 태스크에서는 프로세스가 종료된 후에 다시 시작되지 않는다.

4.5.1 Job 리소스 소개

노드에 장애가 발생한 경우 해당 노드에 있던 잡이 관리하는 파드는 레플리카셋 파드와 같은 방식으로 다른 노드로 다시 스케줄링된다. 프로세스 자체에 장애가 발생한 경우 잡에서 컨테이너를 다시 시작할 것인지 설정할 수 있다.

4.5.2 Job 리소스 정리

파드 스펙specifcation에서는 컨테이너에서 실행 중인 프로세스가 종료될 때 Kubernetes 가 수행할 작업을 지정할 수 있다. 이 작업은 파드 속성인 restartPolicy로 수행되며 기본값을 Always이다. Job 파드는 무한정 실행하지 않으므로 기본 정책을 사용할 수 없다. 따라서 restartPolicy를 OnFailure나 Never로 명시적으로 설정해야 한다. 이 설정은 컨테이너가 종료될 때 재시작되지 않도록 하는 것이다.

4.5.4 Job에서 여러 파드 인스턴스 실행하기

Job은 두 개 이상의 파드 인스턴스를 생성해 병렬 또는 순차적으로 실행하도록 구성할 수 있다. 이는 Job 스펙에 completions와 parallelism 속성을 설정해 수행한다.

순차적으로 Job 파드 실행하기 <completions>

이 Job은 차례로 다섯 개의 파드를 실행한다. 파드 중 하나가 실패하면 잡이 새 파드를 생성하므로 Job이 전체적으로 다섯 개 이상의 파드를 생성할 수 있다.

병렬로 Job 파드 실행하기 <completions-parallelism>

parallelism(병행) 을 2로 설정하면 Job은 파드를 두 개 생성하고 병렬로 실행한다.

Job 스케일링

Job이 실행되는 동안 parallelism 속성을 변경할 수도 있다.

 

레플리카셋이나 레플리케이션컨트롤러를 스케일링하는 것과 유사하며, kubectl scale 명령을 사용해 수행할 수 있다.

$ kubectl scale job multi-completion-batch-job --replicas 3

4.5.5 Job 파드가 완료되는 데 걸리는 시간 제한하기

파드 스펙에 activeDeadlineSeconds 속성을 설정해 파드의 실행 시간을 제한할 수 있다. 이보다 오래 실행되면 시스템 종료를 시도하고 Job을 실패한 것으로 표시한다.

4.6.1 CronJob 생성하기

스케줄 설정하기

  • 요일

4.6.2 스케줄된 잡의 실행 방법 이해

Job이나 파드가 상대적으로 늦게 생성되고 실행될 수 있다. 예정된 시간을 너무 초과해 시작돼서는 안 된다는 엄격한 요구 사항을 갖는 경우도 있다. 이런 경우엔 크론잡 스펙의 startingDeadlineSeconds 필드를 지정해 데드라인을 설정할 수 있다.

잡이 예정된 실행 시간 중 하나는 10:30:00이다. 파드는 예정된 시간에서 늦어도 15초 내에 시작해야 한다.
어떤 이유에서든 10:30:15까지 시작하지 않으면 Job이 실행되지 않고 실패로 표시된다.

 

일반적인 상황에서 CronJob 스케줄에 설정한 각 실행에 항상 하나의 Job만 생성하지만 두 개의 Job이 동시에 생성되거나 전혀 생성되지 않을 수 있다. 첫 번째 문제를 해결하려면 Job이 멱등성(한 번 실행이 아니라 여러 번 실행해도 원치 않는 결과가 초래되지 않음) 가져야 한다. 두 번째 문제점의 경우 다음 번 Job이 실행이 이전의 (누락된) 실행에서 완료했어야 하는 작업을 수행하는지 확인해야 한다.

4.7 요약

  • 컨테이너가 더 이상 정상적이지 않으면 즉시 Kubernetes가 컨테이너를 다시 시작하도록 Liveness probe를 지정할 수 있다.
  • 파드는 실수로 삭제되거나 실행 중인 노드에 장애가 발생하거나 노드에서 퇴출되면 다시 생성되지 않기 때문에 파드를 직접 생성하면 안 된다.
  • 레플리케이션컨트롤러는 의도하는 수의 파드 복제복(replica)을 항상 실행 상태로 유지한다.
  • 파드를 수평으로 스케일링(확장)하려면, 쉽게 레플리케이션컨트롤러에 의도하는 레플레카 수를 변경하는 것만으로도 가능하다.
  • 파드는 레플리케이션컨트롤러가 소유하지 않으며, 필요한 경우 레플리케이션컨트롤러 간에 이동할 수 있다.
  • 레플리케이션컨트롤러는 파드 템플릿에서 새로운 파드를 생성한다. 템플릿을 변경해도 기존의 파드에는 영향을 미치지 않는다.
  • 레플리케이션컨트롤러는 레플리카셋과 디플로이먼트로 교체해야 하며, 레플리카 셋과 디플로이먼트는 동일한 기능을 제공하면서 추가적인 강력한 기능을 제공한다.
  • 레플리케이션컨트롤러와 레플리카 셋은 임의의 클러스터 노드에 파드를 스케줄링 하는 반면, 데몬셋은 모든 노드에 데몬셋이 정의한 파드의 인스턴스 하나만 실행되도록 한다.
  • 배치 작업을 수행하는 파드는 Kubernetes의 Job 리소스로 생성해야 하며, 직접 생성하거나 레플리케이션컨트롤러 또는 유사한 오브젝트로 생성하지 말아야 한다.
  • 나중에 언젠가 실행해야 하는 Job은 CronJob 리소스를 통해 생성할 수 있다.

댓글

💲 추천 글