나의 공부기록

[Kubernetes] 08. Container Health Check(컨테이너 헬스체크) - livenessProbe, readinessProbe 본문

CS/Kubernetes

[Kubernetes] 08. Container Health Check(컨테이너 헬스체크) - livenessProbe, readinessProbe

나의 개발자 2025. 4. 17. 17:46

Container Health Check (컨테이너 헬스체크)

1️⃣ livenessProbe

  • livenessProbe가 실패 시, 컨테이너를 재시작
    ➡️ 컨테이너에 이상이 있다고 간주

2️⃣ readinessProbe

readinessProbe 예시

  • 실패해도 정상동작하지만, 서비스에서 해당 Pod로 트래픽을 인가하지 않음
  • 보통 livenessProbe보다 readinessProbe를 많이 사용함

httpGet을 통한 probe

더보기

1. 디렉토리 생성

root@master-250410:~/mani# mkdir -p 250417/probe
root@master-250410:~/mani# cd 250417/probe/
root@master-250410:~/mani/250417/probe#

 

2. pod 컨테이너 정의

  • periodSeconds : 헬스체크 주기
  • initialDelaySeconds : 부팅 대기 시간
  • 처음에 2초 대기 후, 5초에 한 번씩 curl localhost/와 비슷하다고 생각하면 좋음
root@master-250410:~/mani/250417/probe# vi pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx
    # 일반적인 Pod의 컨테이너 정의
    readinessProbe:
      httpGet:
        path: /
        port: 80
      periodSeconds: 5
      initialDelaySeconds: 2

 

3. Pod 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f pod.yml 
pod/nginx-pod created

 

4. 결과 확인

  • 컨테이너 정상 작동 확인
root@master-250410:~/mani/250417/probe# kubectl get pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP            NODE             NOMINATED NODE   READINESS GATES
nginx-pod   1/1     Running   0          10s   10.244.1.14   worker1-250410   <none>           <none>
  • Readiness 결과 확인
root@master-250410:~/mani/250417/probe# kubectl describe pod nginx-pod
  • health check에 1번 성공 / 3번 실패 ➡️ delay 시간을 늘려주면 성공이 늘것 같음

 

5. Health Check 실패 경우 확인

5-1. 실패하는 Pod 정의

root@master-250410:~/mani/250417/probe# cp pod.yml rf-pod.yml

root@master-250410:~/mani/250417/probe# vi rf-pod.yml 

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx
    readinessProbe:
      httpGet:
        path: /
        port: 800
      periodSeconds: 5
      initialDelaySeconds: 2

 

5-2. 실패하는 Pod 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f rf-pod.yml 
pod/rf-nginx-pod created

 

5-3. Pod 접속 실패 확인

 

 

6. Service

  • ClusterIP 타입(기본값)으로 svc 생성

6-1. Service 정의

root@master-250410:~/mani/250417/probe# vi svc.yml 

apiVersion: v1
kind: Service
metadata:
  name: svc-test
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80

 

6-2. Service 반영

root@master-250410:~/mani/250417/probe# kubectl apply -f svc.yml 
service/svc-test unchanged

 

6-3. Service 생성 확인

 

6-4. 접속 거부 확인

 

6-5. SVC에 Endpoint에 포함되지 않음을 확인

  • 컨테이너가 준비가 되지 않았지만, 커네이너가 작동이 잘 되는 것을 확인 가능
  • rf-nginx-pod 포트 수정
root@master-250410:~/mani/250417/probe# vi rf-pod.yml 

apiVersion: v1
kind: Pod
metadata:
  name: rf-nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx
    #일반적인 pod의 컨테이너 정의


    readinessProbe:
      httpGet:
        path: /
        port: 80
      periodSeconds: 5
      initialDelaySeconds: 2

 

6-6. 컨테이너 삭제 & 시작

root@master-250410:~/mani/250417/probe# kubectl delete -f rf-pod.yml 
pod "rf-nginx-pod" deleted
root@master-250410:~/mani/250417/probe# vi rf-pod.yml 
root@master-250410:~/mani/250417/probe# kubectl apply -f rf-pod.yml
pod/rf-nginx-pod created

 

7. 결과 확인

 

실습 - 01

문제

61.254.18.30:5000/nginx 이미지로 httpGet 으로 /test경로에 80요청이 성공하도록 만들어보세요!
➡️ configMap으로 index파일을 만들어서 컨테이너에 /usr/share/nginx/html/test 경로에 넣어줄 예정 

풀이

더보기

1. Manifest file 정의

root@master-250410:~/mani/250417/probe# vi test.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-index
data:
  index.html: |
    readiness success
--- 
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
    - name: nginx
      image: 61.254.18.30:5000/nginx
      volumeMounts:
        - name: vol-index
          mountPath: /usr/share/nginx/test
      readinessProbe:
        httpGet:
          path: /test
          port: 80
        initialDelaySeconds: 3
        periodSeconds: 5
  volumes:
    - name: vol-index
      configMap:
        name: cm-index

 

2. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f test.yml 
configmap/cm-index unchanged
pod/test-pod configured

 

3. 결과 확인

 

실습 - 02

문제

실패하는 livenessProbe를 구성해보세요.
이후에 kubectl get pod --watch 같은 옵션을 통해 어떤 현상이 발생하는지 한 번 확인해보세요.

풀이

더보기

 1. 컨테이너 정의

root@master-250410:~/mani/250417/probe# vi lf-pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: lf-nginx-pod
  labels:
    app: lf-nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx
    livenessProbe:
      httpGet:
        path: /fail #curl localhost:80/fail
        port: 80
      periodSeconds: 5
      initialDelaySeconds: 5

 

2. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f lf-pod.yml 
pod/lf-nginx-pod created

 

3. 결과 확인

  • 무한 재부팅 ➡️ livenessProbe가 실패했기 때문에, 계속 재부팅

 

4. yml파일 수정 ➡️ 정상

root@master-250410:~/mani/250417/probe# vi lf-pod.yml 

apiVersion: v1
kind: Pod
metadata:
  name: lf-nginx-pod
  labels:
    app: lf-nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx
    livenessProbe:
      httpGet:
        path: / #curl localhost:80/
        port: 80
      periodSeconds: 5
      initialDelaySeconds: 5

 

5. manifest file 반영

root@master-250410:~/mani/250417/probe# kubectl apply -f lf-pod.yml 
pod/lf-nginx-pod created

 

6. 결과 확인

  • 컨테이너 재시작을 안할것

 

tcpSocket을 통한 Probe

  • MySQL 같은 앱은 httpGet같은 요청으로는 응답을 주지 않음
    ➡️ 따라서, MySQL의 기본 포트인 3306으로 tcpSocket이 유효한지를 검증하여 probe하는 방식
더보기

1.컨테이너 정의

root@master-250410:~/mani/250417/probe# vi redis.yml

apiVersion: v1
kind: Pod
metadata:
  name: redis
  labels:
    app: redis
spec:
  containers:
  - name: redis
    image: 61.254.18.30:5000/redis
    readinessProbe:
      tcpSocket:
        port: 6379
      initialDelaySeconds: 5
      periodSeconds: 3

 

2. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f redis.yml 
pod/redis created

 

3. 컨테이너 생성 확인

💡컨테이너 정상 작동 확인 명령어

  • $? : 직전에 실행한 명령이 어떻게 종료되었는지 종료코드를 조회
    • 정상종료 = 0 반환, 비정상종료 = 1 또는 2 반환

정상 작동
비정상 작동

  • 0을 반환 ➡️ readinessProbe 성공
  • 1, 2 반환 ➡️ readinessProbe 실패

Command를 통한 probe

더보기

1. 임시 컨테이너 생성

root@master-250410:~/mani/250417/probe# vi cmd-mysql.yml

apiVersion: v1
kind: Pod
metadata:
  name: mysql
spec:
  containers:
  - name: mysql
    image: 61.254.18.30:5000/mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"

 

2. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f cmd-mysql.yml 
pod/mysql created

 

3. 컨테이너 정상 작동 확인

 

4. 컨테이너 진입 & 정상 작동 명령어 확인

  • 어떤 명령이 수행됐을 때, 0을 반환하는지 모르기 때문에, 컨테이너 안으로 들어가서 확인

 

5. 컨테이너 삭제

root@master-250410:~/mani/250417/probe# kubectl delete -f cmd-mysql.yml

 

6. 컨테이너 수정

root@master-250410:~/mani/250417/probe# vi cmd-mysql.yml 

apiVersion: v1
kind: Pod
metadata:
  name: mysql
spec:
  containers:
  - name: mysql
    image: 61.254.18.30:5000/mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    readinessProbe:
      exec:
        command: ["mysqladmin","ping","-ppassword"]
      initialDeplaySeconds: 10
      periodSeconds: 3

 

6. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f cmd-mysql.yml 
pod/mysql created

 

7. 컨테이너 정상 작동 확인

 

실습 - 03

문제


이 readinessProbe가 성공하는 pod 매니페스트 파일을 작성해보세요.

풀이

💡 방법

1️⃣ pv-pvc로 호스트에 존재하는 파일 넣어주기 - 별로

2️⃣ configMap - 세련됨 ✅

3️⃣ ⚠️command - 금지 

  • command 명령 = Dockerfile CMD, CMD가 무시된
  • 컨테이너 정상 작동 ❌

4️⃣ Dockerfile을 통한 이미지빌드 - 귀찮

더보기

1. 컨테이너 정의

root@master-250410:~/mani/250417/probe# vi cmd-txt.yml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx

 

2. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f cmd-txt.yml 
pod/nginx created

 

3. 컨테이너 내부 진입 & 정상 작동 확인

 

4. 컨테이너 삭제

root@master-250410:~/mani/250417/probe# kubectl delete -f cmd-txt.yml 
configmap "cm-test" deleted
pod "nginx" deleted

 

5. 컨테이너 정의 - 수정

  • ConfigMap과 VolumeMount를 사용해서 경로 & 파일 생성
root@master-250410:~/mani/250417/probe# vi cmd-txt.yml 

apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-test
data:
  test.txt: |
    test
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: 61.254.18.30:5000/nginx
    volumeMounts:
    - name: config-volume
      mountPath: /test
    readinessProbe:
      exec:
        command: ["cat","/test/test.txt"]
      initialDelaySeconds: 10
      periodSeconds: 3
  volumes:
  - name: config-volume
    configMap:
      name: cm-test

 

6. 컨테이너 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f cmd-txt.yml 
configmap/cm-test created
pod/nginx created

 

 7. 결과 확인 - 정상 작동


Kubernetes Resource

StatefulSet

  • 우리가 deployment를 통해 pod를 여러 개 띄우면 pod의 이름이 우리가 예상할 수 없는 형태의 랜덤한 이름이 부여
    ➡️ 딱히 내가 앱을 배포할 때, pod의 이름이 크게 중요하지 않고 빠르게 배포하고 싶다면 아래와 같이 생성
    👉 하지만, 때에 따라서는 pod의 이름을 신경써야하는 경우도 존재
  • 예시) mysql을 구성하는데, 하나는 master로 구성하고 다른 하나는 slave로 구성하는 경우, 첫 번째 리소스가 항상 mysql-0으로 생성되고, 두번째 리소스는 항상 mysql-1로구성된다면, mysql-0 = master / mysql-1 = slave로 구성하면 됨
    👉 이렇게 일정한 이름을 갖도록 구성되는 리소스 ➡️ StatefulSet

StatefulSet 실습

더보기

1. 리소스 정의

root@master-250410:~/mani/250417/probe# cat sts.yml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sts-mysql
spec:
  serviceName: "mysql" #반드시 svc를 이 이름으로 만들어줘야한다
  replicas: 3
  selector:
    matchLabels:
      app: sts-mysql
  template:
    metadata:
      labels:
        app: sts-mysql
    spec:
      containers:
      - name: sts-mysql
        image: 61.254.18.30:5000/mysql
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"

 

2. 리소스 배포

root@master-250410:~/mani/250417/probe# kubectl apply -f sts.yml 
statefulset.apps/sts-mysql created

 

3. 결과 확인 - Pod의 이름이 일정함을 확인 가능

DaemonSet

  • Docker-swarm에서 deploy.mode.global: 옵션과 비슷
  • 각 노드마다 무조건 한개씩만 파드를 띄우고 싶을 때
  • 모니터링 시스템처럼 모든 노드에 자원을 수입할 exporter들을 배치하고 싶은 경우 사용
  • 예시
    • kube-system의 kube-proxy, metallb-system의 speaker 같은 리소스에 해당

metallb-system의 speaker

DaemonSet 실습

더보기

1. 리소스 정의

root@master-250410:~/mani/250417/probe# vi kube-ds.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-nginx
spec:
  selector:
    matchLabels:
      app: ds-nginx
  template:
    metadata:
      labels:
        app: ds-nginx
    spec:
      containers:
      - name: ds-nginx
        image: 61.254.18.30:5000/nginx

 

2. 리소스 생성

root@master-250410:~/mani/250417/probe# kubectl apply -f kube-ds.yml 
daemonset.apps/ds-nginx created

 

3. 결과 확인