무중단으로 배포되고 운영되는 시나리오라면, Pod의 문제가 생기게 되면, 그 Pod를 새로이 생성하고 서비스를 해야되는 상황이 발생할 것이다.
이 경우 몇가지 문제가 있다.
Pod 내부의 어플리케이션 정상 서비스 여부를 알 수 있을까?
결국 두 가지 모두 내부의 서비스에 대한 이상 여부를 체크해야 한다.
쿠버네티스의 가장 큰 장점은 스스로 어플리케이션에 대한 동작을 체크해주고, 지속적인 헬스 체크로 고품질의 서비스 상태를 유지한다는 것이다.
Health check는 어플리케이션에 문제가 있는지 확인 할 수 있는 가장 간단한 방법이다. 만약 정상적으로 동작하지 않는다면, 요청을 보내서는 안되고, 정상적인 상태로 기존의 Pod를 내리고 새로운 Pod를 올려야 한다. ( 신규 Pod에 대해서도 체크를 수행)
kubernetes에서는 두 가지 헬스 체크 기능을 제공한다.
각 컨테이너의 상태를 주기적으로 체크해서, 문제가 있는 컨테이너를 자동으로 재시작하거나 또는 문제 있는 컨테이너를 서비스에서 제외시킬 수 있다. 이러한 기능을 헬스 체크라고 하며 컨테이너가 살아 있는지 아닌지를 체크하는
Liveness probe
, 컨테이너가 서비스가 가능한 상태인지를 체크하는Readiness probe
가 있다.
Readniness probe는 Container 안의 어플리케이션이 서비스 할 준비가 되면 쿠버네티스에게 알리도록 설계 되어 있다. 서비스가 Pod로 트래픽을 보내기 전에 Readiness probe 검사 단계가 통과되어야만 해당 pod로 트래픽을 보내는 것을 의미한다.
Liveness probe는 배포된 애플리케이션의 상태가 정상인지 비정상인지 여부를 판단하여 Kubernetes에 알리도록 설계되어 있다. 만약 어플리케이션에 문제가 발생하면 kubernetes는 문제가 발생한 Pod를 제거하고 새로운 Pod를 시작하게 된다.
Probe는 kubelet에 의해 주기적으로 수행되는데, 아래의 3가지 타입으로 Container에 구현된 Handle을 호출함으로써 Health Check를 수행한다.
HTTP probe는 가장 일반적으로 사용되는 liveness probe 타입이다. 어플리케이션의 HTTP 서버로 probe에 설정한 트래픽을 보내 200~400 의 응답코드를 받으면 정상, 그 이외의 응답코드를 받으면 비정상으로 마킹한다.
command probe는 Container안에서 해당 command를 수행한 결과가 정상인지 여부를 체크하는 probe타입으로 만약 command 수행결과 코드가 0이 리턴시 정상, 그렇지 않으면 비정상으로 마킹한다. 어플리케이션에 HTTP 서버를 실행할 수 없는 경우 유용하다.
TCP probe 타입은 Kubernetes가 지정된 포트로 TCP 연결을 시도해 연결에 성공하면 정상, 연결할 수 없다면 비정상으로 마킹하게 된다. TCP probe는 HTTP probe나 command probe를 사용할 수 없을 경우에 유용, 대표적인 유형으로 gRPC나 FTP service가 있다.
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: k8s.gcr.io/liveness
args:
- /server
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
위의 내용을 살펴본다.
periodSeconds: 3
initialDelaySeconds: 3
초기 지연 시간을 적절하게 설정함으로써, 애플리케이션이 구동되는 시간을 확보해야 한다. 만약 초기 지연시간이 너무 짧은 상태로 liveness probe가 동작되는 경우 Pod가 정상 수행하지 않는 것으로 판단하고 Pod를 내리고 신규 Pod를 올리는 일을 반복 수행한다.
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
/healthz
path 에 요청을 보낼 것이다. success code 리턴시 정상 동작 마킹, failure code 리턴시 Container를 제거하고 다시 시작 할 것이다. apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
periodSeconds
: 수행 주기 설정initialDelaySeconds
: Pod 생성되고 Container 시작 이후 최초 probe가 수행되기 전 Delay 주는 시간initialDelaySeconds 이후 kubelet은 Container 안에서
cat /tmp/healthy
명령을 수행 할 것이다. 그 결과 리턴된 코드가 0이면 정상 그렇지 않으면 비정상을 마킹하게 되고 Container를 재시작한다.
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:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
애플리케이션 시작시 어느 정도의 시간이 소요될 수 있다. 어떤 애플리케이션은 초기 시작시 데이터의 로딩 시간이 필요할 수 있고, 외부의 어떤 서비스와 연동되기 위한 시간이 필요할 수 있다. 이런 경우에 정상적으로 서비스가 레디가 되는 것을 체크하는데 사용되어 질 수 있는 것이 readiness probe이다.
Readiness probe의 설정은 liveness probe를 설정하는 방법과 동일하다.
Probes
는 보다 정확한 health 체크를 위해 많은 설정 필드를 가지고 있다.
initialDelaySeconds
: Pod 생성되고 Container 시작된 이후 최초 probe가 수행되기 전 Delay를 주는 시간periodSeconds
: probe의 수행 주기 설정timeoutSeconds
: probe 수행 응답을 기다리는 timeout 시간 설정successThreshold
: probe가 최소 몇번을 성공해야 성공으로 마킹할 것인지 설정하는 필드failureThreshold
: probe가 최소 몇번 실패해야 실패로 마킹할 것인지 설정하는 필드 (Pod가 시작되고 Probe가 실패하면 kubernetes는 failure Threshold에 설정된 만큼 다시 probe를 시도할 것이다. 다만 failure Threshold의 숫자만큼 실패시 실패로 마킹되고 probe를 시도하지 않고 포기하게 된다.)Http probes
는 추가적으로 아래와 같은 필드를 더 설정할 수 있다.
host
: 연결하려는 Host Name, default는 pod ipscheme
: HTTP or HTTPS, defaults to HTTPpath
: HTTP server에 접근하려는 경로httpHeaders
: Custom header 설정값port
: Container에 접근하려는 portResource requests and limit은 kubernetes가 CPU 및 메모리와 같은 리소스를 제어하는 매커니즘이다.
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
container를 명세할 때 위와 같이 각각의 Container에서 필요한 CPU와 RAM을 CPU Milicore 단위로 Memory는 Mbyte 단위로 리소스의 requests와 limits이라는 측면에서 정의할 수 있다.
Container가 리소스를 Request 하면 Kubernetes는 리소스를 제공할 수 있는 노드에서만 스케쥴링이 되고, Limit은 Container가 특정 리소스를 초과하지 않도록 제한한다.
cpu 요청과 관련해서 고려해야 할 사항 중 한가지는 Node의 CPU core 수보다 큰 값을 입력하면 Pod가 스케쥴링 되지 않는다는 것이다. 예로 Kubernetes 클러스터는 dual core VM으로 구성되어 잇는데 Pod에는 4개의 core를 입력했다면 Pod가 스케쥴링 되지 않는다는 것이다.
특별한 경우가 아니라면 CPU 요청은 1 이하로 하고 Replica에 의해 오토 스케일링 되는 것을 염두해서 Pod를 설계해야 한다. 시스템을 보다 유연하고 신뢰성 있게 구성할 수 있다.
Node의 메모리보다 더 큰 요청을 셋팅하게 되면 Pod는 스케쥴링 되지 않는다. 또한 메모리는 CPU와 달리 kubernetes에서 메모리 사용량을 조절 할 수 없으므로 Container가 메모리 제한을 초과하게 되면 애플리케이션이 종료되는데, Pod가 Deployment, StatefulSet, DaemonSet 또는 다른 유형의 컨트롤러에 의해 관리되는 경우, 기존 Pod는 종료되고 새로운 Pod가 시작된다.
클러스터는 Namespace로 구성될 수 있는데, 만약 그 중 한 Namespace가 과도한 요청이 있을 경우 전체 클러스터에 영향을 미칠 수 있다. 따라서 이러한 경우를 제한하기 위해 Namespace 레벨에서 ResourceQuotas와 LimitRanges를 설정하는 것이 중요하다 .
ResourceQuotas: Namespace를 생성한 후, ResourceQuota를 통해 Namespace의 CPU 및 메모리를 제한 할 수 있다.
LimitRange: ResourceQuotas는 NameSpace 전체 영역에 대한 리소스의 제한을 정의하는 반면, limitRange는 개별 컨테이너 단위의 리소스에 대한 제약이다.
Namespace
네임스페이스란 쿠버네티스 클러스터 내의 논리적인 분리 단위이다. 쿠버네티스 클러스터 내의 대부분의 리소스들은 네임스페이스로 논리적인 분리가 가능하다. 물리적인 클러스터를 논리적으로 여러개로 나눠서 개별적으로 서로 다른 역할을 하는 클러스터로 나눌 수 있다.
kubernets의 namespace 소개 및 사용법