k8s의 probe 설정 문서에 게제되어 있는 내용 기준으로 진행합니다.
테스트에 jq toole을 사용하였습니다.
필요 유틸리티
liveness probe with exec action
여러 문서들을 보다 보면
liveness probe가 실패 했을 때 pod가 재 시작 된다 container가 재 시작 된다 라는 말이 혼재 되어 있습니다.
liveness probe에 의해 재시작 되는 대상이 컨테이너 인지 pod인지 알아보기 위해
pod 네이밍에 랜덤값을 부여하는 deployment로 배포 하고, restartCount 가 증가할 때
- pod의 이름이 변경되는지
- container id가 변경되는지
확인합니다.
.yaml 준비
apiVersion: apps/v1
kind: Deployment
metadata:
name: liveness-exec
spec:
selector:
matchLabels:
app: liveness-exec
template:
metadata:
labels:
app: liveness-exec
spec:
containers:
- name: liveness-exec
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
컨테이너의 특정 상태를 확인하기 위해 컨테이너에 특정 실행 조건을 부여 합니다.
- 컨테이너가 시작하면서 bash shell로
- /tmp/healthy 파일을 생성하고
- 30초 뒤 /tmp/healthy 파일을 삭제 합니다.
- 600초 동안 대기 합니다.
liveness probe는
- 컨테이너가 시작된지 5초 후에
- /tmp/healthy의 내용을 출력하고
- 이 후 5초 마다
- /tmp/healthy의 내용을 출력합니다.
exec action에 의해 컨테이너가 실행되면 아래 명령어를 주기마다 실행합니다.
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
exec action은 cat /tmp/healthy 명령어가 성공하면 0을 반환하고, 0이 아니면 container를 종료 하고 pod를 다시 시작 합니다.
일정 시간을 시점으로 테스트 실패 케이스를 만드는 예제인 만큼 테스트 정확도는 시간과의 싸움입니다. -0-
restartCount가 증가 될 때 pod의 이름이 변경되는지 확인해 봅니다.
테스트 앱 배포 후 pod 이름 확인
kubectl apply -f liveness-exec.yaml
kubectl get pod -o wide
liveness-exec-7778664dbd-lhg8s 라는 이름으로 pod가 생성 중이구요
상태 확인
kubectl describe pod <pod name>
describe의 Events
정상 시작 되었구요. 이 상태가 다시 시작으로 바뀔 때 까지 describe 명령어를 반복 실행하다 보면 아래 처럼 재시작 기록이 확인 됩니다.
probe 실패로 인해 다시 시작 되었고, 이제 pod가 새로 생긴건지 pod의 이름을 확인 해 봅시다.
kubectl get pod -o wide
1회 재 시작 되었지만 pod의 이름은 변경되지 않았습니다.
container가 재 시작 되는지 확인 해 봅니다.
먼저 테스트 했던 deployment를 깨끗하게 제거 해줍니다.
kubectl delete -f liveness-exec.yaml
pod가 완전히 종료될 때까지 기다립니다.
kubectl get pod
.yaml 준비
pod이름이 변경되지 않는다는 것은 확인 하였으니 테스트 편의를 위해 deployment로 배포하지 않고 pod를 직접 배포 합니다.
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
pod 배포
kubectl apply -f liveness-exec-pod.yaml
컨테이너 id 확인
kubectl get pod liveness-exec -o json | jq .status.containerStatuses
restartCount 없고 container id 확인 후 restartCount가 증가 될 때까지 커맨드를 반복 실행 합니다.
restartCount가 증가 되었을 때의 결과물입니다.
container id가 변경되었고 lastState에 이전 container id 가 출력 됩니다.
결과
liveness probe는 컨테이너가 실행 중이더라도 probe 결과 값이 비 정상이면 pod는 변경되지 않고 container가 변경 됩니다.
정확하게는
- 실행중이였던 container를 kill 하면
- 컨테이너 재시작 정책에 의해
- pod가 다시 시작되면서 새로운 container가 생성되는 겁니다.
readiness probe with exec action
상태 프로브 관련 문서들을 보면 아래와 같이 설명되어 있습니다.
- liveness probe는 실행 중인 컨테이너의 상태를 확인, 비정상 시 컨테이너 재 시작 시킴
- readiness probe는 요청을 처리할 준비가 되었는지 확인, 비정상 시 연관된 서비스들의 엔드포인트에서 pod의 ip 제거
또 한 liveness와 readiness는 작성 방법은 동일하다고 되어 있었고,
liveness와 readiness는 어떤 차이가 있는지 확인해보기 위해,
liveness 테스트에서 사용했던 yaml파일에서 livenessProbe 를 readinessProbe로만 변경하여 테스트 진행합니다.
probe가 정상이다가 실패 했을 때 container가 재 시작 되는지 확인
.yaml 준비
apiVersion: apps/v1
kind: Deployment
metadata:
name: readiness-exec
spec:
selector:
matchLabels:
app: readiness-exec
template:
metadata:
labels:
app: readiness-exec
spec:
containers:
- name: readiness-exec
image: k8s.gcr.io/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
테스트 앱 배포 후 pod 이름 확인
kubectl apply -f readiness-exec.yaml
kubectl get pod -o wide
상태확인
kubectl describe pod <pod name>
정상 실행 되었구요, 비정상 상태가 될 때 까지 반복적으로 커맨드를 실행 합니다.
드디어 실패 상태가 확인 되었구요
아직 재시작 카운트는 오르지 않았습니다.
describe로 계속 pod를 관찰하고 있는데 Events에 restart 된다는 메세지는 없지만 pod restartCount가 1로 증가 했습니다.
liveness probe와 작성방법은 동일하지만 readiness probe는 다르게 동작하네요
liveness와 동일한 조건을 갖는 readiness이지만 restart 카운트 증가하는 시간이 liveness 보다 엄청 오래 걸리는 느낌이 있습니다.
음.... 조금 더 지켜 본 결과 liveness와는 다른 패턴을 알게 되었습니다.
결과
패턴 분석 결과
- readiness probe는 container를 재 시작 시켜주지 않습니다.
- 정상/비정상 상태를 파악하여 service의 endpoint에 pod를 등록/해지 만 시켜줍니다. (아래쪽에 별도 테스트 내용 있습니다.)
- pod restart count 가 증가한 이유는
- exec action에 의한 container의 실행 시간이 정해져(30초 + 600초) 있고 이 시간이 다 되어 container가 죽자 kubelet에 의해 다시 시작된 상황
- liveness는 재 시작 로직이 있기 때문에 630초 까지 진행되지 않고 그 전에 container가 재시작 됨
readiness probe 테스트에 사용된 container cmd
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
컨테이너가 시작되고 30초 대기 후 600초 대기
첫 번째 재시작 확인 시점 = 15분
두 번째 재시작 확인 시점 = 21분
21분에 두 번째 재 시작 당시 pod의 ready 상태는 정상이였지만 30초 뒤 exec action이 실패 하면서 ready 상태는 비정상으로 전환
(캡쳐는 25분 경에 되었습니다.)
readiness probe 상태에 따라 service endpoint 에 등록/해제 되는 pod 확인
그러면 readiness 프로브 성공/실패에 의해 service endport에 등록/제거 되는지 확인을 해야 합니다.
그전에 프로브가 정상일 때 pod가 서비스의 엔드포인트에 어떻게 등록되는지 확인하기 위해
정상 동작하는 tcp 앱을 구동시키고 endpoint를 확인해 봅니다.
.yaml 준비
apiVersion: v1
kind: Pod
metadata:
name: readiness-tcp
labels:
app: readiness-tcp
spec:
containers:
- name: readiness-tcp
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: readiness-tcp
spec:
selector:
app: readiness-tcp
ports:
- port: 8080
targetPort: 8080
type: LoadBalancer
샘플 앱 실행 후 pod 확인
kubectl apply -f readiness-tcp.yaml
kubectl get pod -o wide
pod 실행상태 확인 및 endpoint 등록 확인
kubectl get pod -o wide
kubectl describe svc readiness-tcp | find "Endpoints"
pod 실행상태 확인 및 endpoint 등록 확인
kubectl get pod -o wide
kubectl describe svc readiness-tcp | find "Endpoints"
아직은 서비스에 endpoint가 등록되지 않았지만
위 커맨드를 몇 초간 반복하다 보면 pod의 ip가 service endpoint에 등록되어 있습니다.
pod가 정상일 때 lb의 endpoint에 이렇게 착~! 달라 붙어 있군요
구조상으로는 알고 있었지만 실제로 확인은 처음 해봤습니다.
이제 상태가 오락가락 하는 앱이 있을 때 pod가 service endpoint에 붙었다 떨어졌다가 되는지 확인 해 보고 싶은데요
이를 위한 테스트 코드를 작성하고 싶진 않네요.... ㅜㅜ
.yaml 준비
k8s docs의 liveness http 샘플을 조금 변형 시킨 yaml 파일로 테스트 합니다.
- 샘플의 소스 코드는 컨테이너 시작 후 10초동안 정상(200)을 리턴하고 그 이 후에는 비정상(500)을 리턴합니다.
apiVersion: v1
kind: Pod
metadata:
name: readiness-http
labels:
app: readiness-http
spec:
containers:
- name: readiness-http
image: k8s.gcr.io/liveness
ports:
- containerPort: 8080
args:
- /server
readinessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: readiness-http
spec:
selector:
app: readiness-http
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
type: LoadBalancer
변형된 샘플을 실행 시켜 처음 10초동안 load balancer의 endpoint에 포함 되어 있다가 이 후 endpoint에서 제거 되는지 확인 합니다.
(처음 10초만 정상 적인 상태 이므로 이번 테스트도 시간과의 싸움입니다. -0-)
.yaml 배포
kubectl apply -f readiness-http.yaml
kubectl get pod -o wide
endpoint 상태 확인
kubectl get pod -o wide
kubectl describe svc readiness-http | find "Endpoints"
엔드포인트에 pod가 등록 되었구요
계속 endpoint상태 확인 커맨드 실행 하다 보면 준비상태가 바뀌면서 endpoint에서도 제외되는것을 확인할 수 있습니다.
결과
이 테스트로
readiness probe 실패 시 service endpoint 에서 제거 되는것은 확인 되었지만 app이 다시 정상화 되었을 때 endpoint에 다시 추가 되는지는 확인되지 않았습니다.
다만 많은 문서들의 설명에는 readiness만 사용되는 경우에 대한 언급은 없고 liveness와 같이 사용할 수 있다는 내용만 언급되는것을 보면 아래와 같이 정리가 될 것 같습니다.
readiness는 상태가 비정상인 경우 endpoint에서 제거만 해주는 역할이고
liveness에 의해 pod 재 시작( pod 재배포 아님 )으로 container를 재 배포 해주는 역할
startup은 따로 테스트 해보지 않을 거지만 conatainer 시작 직후 정해진(넉넉히 예상되는) 시간 안에 성공할 때까지 readiness, liveness가 시작하지 않도록 해주는 역할
'IT > Kubernetes' 카테고리의 다른 글
K8S Node 선택 컨트롤러 (0) | 2023.04.12 |
---|---|
K8S 리소스 제한 컨트롤러 (0) | 2023.04.12 |
상태 프로브(startup, liveness, readiness)란 무엇인가? (0) | 2023.04.12 |
하나의 Application Gateway에 여러 AGIC 사용하기 (0) | 2023.04.11 |
하나의 AGIC에 여러 Ingress 사용이 가능한가? (multi-namespace) (0) | 2023.04.11 |