쿠버네티스

[클라우드] 8. Kubernetes Prob의 종류와 Resource 할당

트리스탄1234 2022. 9. 18. 16:08
728x90
반응형

앞에서 살펴봤던 Pod, Service, Deployment, replacaset을 다시 한번 정리를 해보면 Kubernetes에서 서비스를 위한 가장 작은 단위는 Pod 입니다 이 Pod에는 컨테이너가 들어가고 컨테이너 안에서 어플리케이션이 구동이 되어 서비스 요청을 처리를해 줍니다. Pod간의 통신은 Service라는 객체를 통해 통신을 하게 되고, Deployment 객체는 배포된 Pod들을 특정한 상태로 관리를 하는 객체로 생각을 하면 될것 같습니다.

Pod배포가되 되고 나서 장애가 나서 신규 Pod를 생성될때나 다음 경우를 보면 아래의 문제점이 존재 합니다.

  • 첫번째 문제는 Pod가 신규로 생성이 되면 Kubernetes는 Pod상태가 Run상태가 되면 바로 트래픽을 보내게 됩니다. 보통은 Pod는 컨테이너만 구동이 되면 Run 상태가 되고 어플리케이션이 제대로 구동이 되었는지는 확인하지 않습니다. 이경우에 Pod가 Run 상태가 되더라도 어플리케이션 구동까지 일정시간이 필요 합니다. 어플리케이션이 구동이 되기도 전에 요청 메세지를 Pod로 보내면 서비스 처리 실패가 발행하게 되어서 문제가 발생 합니다.
  • 두번째는 deadlock같이 컨테이너는 정상 동작을 하는데 어플리케이션이 deadlock이 걸려 있어도 service객체는 Pod가 Run 상태이기 때문에 서비스 요청을 해당 Pod로 보내게 됩니다 .이경우 어플리케이션이 락 상태이기 때문에 이때에도 서비스 처리 실패가 발생을 하게 됩니다.

이런 경우를 방지하기 위헤서 Container Prob를 사용을 하게 됩니다. Prob의 종류는 아래와 같이 2가지가 있습니다.

  • Readness Prob: Readness Prob는 Pod가 구동이 될때 어플리케이션이 서비스 처리를 할 준비가 되었는지를 Check를 하고 준비가 되면 Kubernetes에게 준비가 되었다고 알려 주는 역활을 합니다. 아래 그림과 같이 어플리케이션 로딩이 100%완료가 되면 서비스 처리준비가 완료되었다고 알려 주게 됩니다.

  • 두번째는 Liveness Prob가 있습니다. 이 Liveness는 Pod가 생성이되고 Readness Prob에서 준비가 완료되고난 후에 서비스 처리 중간 중간에 어플리케이션이 제대로 동작을 하는지 확인을 하고 어플리케이션에 실패가 발생할 경우 Kubernetes에게 통보를 해서 서비스 요청을 해당 Pod로 보내지 않게해 주는 Prob입니다.

위의 두가지 Prob는 어플리케이션의 Healthcheck를 통해서 fail과 ready를 판단을 하게 되는데 Health Check를 하는 방법에는 아래와 같이 3가지 종류가 있습니다.

  • HTTP probe는 가장 일반적으로 사용되는 liveness probe 타입입니다. 애플리케이션의 HTTP 서버로 probe 에 설정한 트래픽을 보내 200~400 의 응답코드를 받으면 정상, 그 이외의 응답코드를 받으면 비정상으로 마킹됩니다... 그럼 Prob는 Pod yaml을 배포할때 아래와 같은 파라메터를 정의하여 구현이 가능 합니다.

apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet: ==> health check 방식은 HTTP Get 메소를 이용
path: /healthz ==> 점검할 경로는 /healthz
port: 8080 ==> port는 8080을 이용
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3 ==> Pod가 구동되고 난후 3초 뒤에 점검 시작
periodSeconds: 3 ==> 초기 점검 후 매 3초마다 점검

  • command probe는 Container안에서 해당 command를 수행한 결과가 정상인지 여부를 체크하는 probe타입으로 만약 command 수행결과코드가 0이 리턴되면 정상, 그렇지 않타면 비정상으로 마킹됩니다. command probe 타입은 애플리케이션에 HTTP 서버를 실행할 수 없을 경우 유용하게 사용될 수 있습니다. 그럼 sample yaml을 살펴 봅시다.

apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args: ==> Pod가 구동된후 실행할 명령어.
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec: ==> 주기 적으로 실행할 명령어 정의
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5 ==> pod가 구동된 후 5초 뒤에 최초 점검 시작
periodSeconds: 5 ==> 최초 점검이 끝난 후 5초 마다 exec 파라메터 아래의 명령 수행

위의 예제에서 보면 5초 마다(periodSeconds) exec 파라메터 아래의 명령어(cat, /tmp/health)를 점검 하고 fail이 발생한 경우 Container 재 구동, 재구동을 하고나면 args 파라메터 아래의 명령어 실행을 하게 됩니다.

  • TCP probe 타입은 Kubernetes가 지정된 포트로 TCP연결을 시도해 연결에 성공하면 정상, 연결할 수 없다면 비정상으로 마킹하게됩니다. TCP Probe는 HTTP probe나 command probe를 사용할 수 없을 경우에 유용하며, 대표적인 유형으로 gRPC 나 FTP service가 있습니다.

그럼 sample yaml파일을 살펴 봅시다.

apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe: ==> readness prob정의
tcpSocket:
port: 8080
initialDelaySeconds: 5 ==>pod 구동후 5초 뒤에 최초 점검
periodSeconds: 10 ==> 초기 점검 후 매 10초 마다 점검
livenessProbe: ==> Liveness prob 정의
tcpSocket: ==> tcp socket 사용
port: 8080 ==> 연결포트 정의
initialDelaySeconds: 15 ==> 최초 구동후 15초 뒤에 최초 점검
periodSeconds: 20 ==> 최초 점검 후 매 20초 마다 점검

그럼 이제 Prob를 정의를 할때 사용가능한 파라메터들을 살펴 보겠습니다.

  • initialDelaySeconds: Pod가 생성되고 Conainer가 시작된 이후 최초 probe가 수행되기전에 Delay를 주는 시간
  • periodSeconds: probe의 수행주기를 설정. Default 10 seconds. Minimum value 1.
  • timeoutSeconds: probe 수행 응답을 기다리는 timeout 시간을 설정. Default 1 second. Minimum value 1.
  • successThreshold: probe가 최소 몇번을 성공해야 성공으로 마킹할 것인지를 설정하는 필드. Default 1. Minimum value 1.
  • failureThreshold: probe가 최소 몇번을 실패해야 실패로 마킹할 것인지를 설정하는 Pod가 시작되고 Pobe가 실패하면 Kubernetes는 failureThreshold에 설정된 만큼 다시 probe를 시도할 것입니다. 다만 failureThreshold의 숫자만큼 실패하면 실패로 마킹되고 다시 probe를 시도하지 않고 포기하게 됩니다. Defaults 3. Minimum value 1.

HTTP probes 는 추가적으로 아래와 같은 필드를 더 설정할 수 있습니다.

  • host: 연결하려는 Host Name, default는 pod IP.
  • scheme: HTTP or HTTPS. Defaults to HTTP.
  • path: HTTP server에 접근하려는 경로.
  • httpHeaders: Custom header 설정값.
  • port: container에 접근하려는 Port.

2. Resource 제한

그럼 이제 Resource 할당에 대해서 살펴 보겠습니다 어떤 어플리케이션이든 필요한 최소 resource가 있습니다. 예를 들면 CPU는 어떤거 이상. MEM은 얼마 이상. 디스크는 얼마 이상.. 이런 조건이 충족이 되지 않은 Pod에 해당 어플리케이션이 할당이 되면 동작이 되지 않을것 입니다.

이를 위해서 필요한 resource를 정의를 할수가 있는데요 .

구현하는 방법은 Pod yaml에 resource 파라메터 부분을 정의를해서 최소 필요 사양을 정의를 할수 있습니다. 그럼 yaml 파일을 하나 살펴 봅시다.

apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: wp
image: wordpress
resources: ==> resource에 관한 사항 정의
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

resource 파라메터는 Pod를 생성할때 필요한 최소 스펙을 정의를 하는데요. 만약에 운영 중인 여러개의 클러스터에서 특정 클러스터가 많은 리소스를 사용을 하게 되면 다른 클러스터에 영향을 주게 되는데요. 이런 경우를 막기 위해 ResourceQuotas를 사용을 합니다. resourcequota는 특정 namespace에서 사용가능한 리소스를 제한을 합니다. 아래 sample resource quota를 살펴 봅시다.

apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high ==> high level의 resource 정의
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium ==> med급 resource를 정의
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]

위의 빨간 부분에서 보듯이 3개 등급의 resource quota를 생성 하였습니다. 이제 Pod를 생성하는 yaml을 살펴 보겠습니다.

apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high

priorityClassName의 값이 high로 정의가 되어 있습니다. 이것은 resourcequata에서 scopeselector에서 정의한 high, med, low 3개중 high을 사용하겠다는 의미 입니다.

resourcequota를 namespce에 적용하는 방법은 아래와 같습니다.

'kubectl apply -f 리소크쿼터이름.yaml --namespaace=네임스페이스이름'

다음은 LimitRange에 대해서 알아 보겠습니다. ResourceQuotas는 Namespace 전체영역에 대한 리소스의 제한을 정의하는반면, LimitRange는 개별 컨테이너 단위의 리소스에 대한 제약입니다. 즉, 사용자들이 개별 컨테이너에 대한 리소스를 정의 할때 해당되는 범위를 제한하는 개념입니다. 이렇게 함으로써, 사용자들은 초소형 또는 초대형 컨테이너를 생성 할 수 없게 됩니다

resourcequota와 limitrange를 그림으로 살펴보면 위와 같습니다.

이 LimitRange는 클러스터(namespace)내의 모든 Pod의 제한값으로 동작을 합니다. sample limitrange yaml을 살펴 보겠습니다.

apiVersion: v1
kind: LimitRange ==>LimitRange 정의
metadata:
name: limit-range
namespace: phh-test-bo ==> 적용할 Namespce 정의
spec:
limits:
- type: Pod
max: ==> Pod가 가질수 있는 최대값
cpu: 1.2
memory: 2.5Gi
min: ==> Pod가 가질수 있는 최소값.
cpu: 0.5
memory: 1Gi

Pod의 yaml파일에도 request/limt라는 파라메터가 있고 이 값과 LimitRange과의 관계를 살펴 보면 아래와 같습니다.

  • Pod yaml에 Resource의 request / limit이 지정되지 않았다면, LimitRange의 limit의 defaultRequest와 max값을 지정합니다.
  • Pod yaml의 Request를 지정하였다면, Pod Resource Request값이 LimitRange limit의 min값 이상의 CPU/Memory값 인지 확인합니다.
  • pod yaml의 Limit을 지정하였다면, Pod Resource Limit값이 LimitRange limit의 max값 이하의 CPU/Memory값 인지 확인합니다.

 

728x90
반응형