- 출처: Kubernetes in action
- 레디니스 프로브
서비스의 레이블 셀렉터와 파드의 레이블이 일치하면 해당 파드는 서비스 관리대상(엔드포인트 리소스에서 IP 목록으로 유지함)이 된다. 요청이 서비스로 전송된 후에 서비스는 임의의 파드로 해당 요청을 전송하는데 만약 파드가 요청을 처리할 준비가 되지 않은 상황이라면 어떻게 해야 할까?
앞서 이와 비슷한 라이브니스 프로브를 알아본적이 있다. 라이브니스 프로브는 불안전한 컨테이너를 다시 시작해서 앱의 상태를 원활하게 유지한다. 레디니스 프로브도 주기적으로 호출되며 특정 파드가 클라이언트 요청을 수신할 수 있는지 여부를 판단한다. 이때 준비가됐다는 기준은 앱의 특성에 맞도록 개발자가 잘 정의해야 한다.
레디니스 프로브에도 3 가지 유형이 존재한다.
- Exec 프로브: 컨테이너 상태를 프로세스의 종료 상태 코드로 결정
- Http GET 프로브: GET 요청을 보내고 Http 응답 상태코드로 컨테이너 준비 여부 결정
- TCP 소켓 프로브: 컨테이너의 지정된 포트로 TCP 연결을 수행하여 연결 여부로 결정
레디니스 프로브도 라이브니스 프로브와 동일하게 첫번째 레디니스 프로브를 시작하기까지 지연시간을 설정할 수 있다. 그 이후에는 주기적으로 호출되며(Default 10초) 결과에 따라 동작한다.
라이브니스 프로브와 비슷한점이 많아 헷갈릴 수 있는데 가장 큰 차이점은 컨테이너의 재시작 여부이다.
- 라이브니스 프로브: 상태가 좋지 않은 컨테이너를 제거하고 새로운 컨테이너로 교체
- 레디니스 프로브: 실패한다고 해서 컨테이너 상태가 좋지 않은것이 아니라 아직 준비가 되지 않은 것이므로 컨테이너를 다시 시작하지는 않음
만약 클라이언트 요청이 서비스를 거쳐 엔드포인트 오브젝트를 조회한 후 파드로 전달 되다가 특정 파드에서 레디니스 프로브가 실패하면 해당 파드는 엔드포인트 오브젝트에서 제거된다. (레이블 셀렉터가 일치 하지 않는 것과 같은 효과가 나타난다.)
DB 서버에 의존하는 앱 서버가 있다고 가정해보자. 앱 서버중 1 대가 DB 서버에 접속이 불가능한 상태이다. 이때 레디니스가 실패하면 서비스는 해당 파드로 요청을 중지한다. 앱 개발자 및 관리자 입장에서는 문제 상황이긴 하지만 사용자측에는 시스템이 정상동작하는것처럼 보이게 한다.
- 레디니스 프로브 추가
ReplicationController 예제에서 파드 템플릿에 레디니스 프로브를 추가해보자.
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: ocwokocw/kubia
readinessProbe:
exec:
command:
- ls
- /var/ready
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8443
spec 하위의 readinessProbe 부분에 레디니스 프로브를 추가했다. 컨테이너 내부에서 ls /var/ready를 주기적으로 수행한다. ls 명령어는 파일이 존재하면 0 을 반환한다.
만약 파드가 생성된 상태에서 ReplicationController를 생성했다면 기존 파드를 제거해야 새로운 파드로 교체되면서 레디니스 프로브가 적용된다. 파드 상태를 한번 조회해보자.
아직 3개의 파드 중 /var/ready라는 파일이 생성된 파드가 없기 때문에 READY 상태가 1인 파드가 없다. 이제 특정 파드에서 /var/ready 파일을 만들어주자. "kubectl exec [파드명] -- touch /var/ready" 명령어를 수행한다.
곧바로 조회하면 여전히 READY 상태는 변함이 없다. 이는 아직 레디니스 프로브의 호출주기가 되지 않았기 때문이다. 기본 설정은 10초 이므로 조금 기다려준 후 다시 파드를 조회하면 1개의 파드가 READY 상태임을 알 수 있다. 만약 이 상태에서 엔드포인트를 조회하면 해당 파드의 IP만 엔드 포인트가 반환한다.
서비스에 요청을 여러 번 날려도 여러 파드로 로드 밸런싱이 되지 않고 /var/ready 파일이 존재하는(준비 상태가 된) 파드로만 요청이 간것을 확인할 수 있다.
- 레디니스 프로브가 해야할 것
항상 레디니스 프로브를 정의해야 한다. 파드에 레디니스 프로브를 정의하지 않으면 파드가 시작하는 즉시 서비스의 엔드포인트가 된다. 만약 레디니스 프로브를 설정하지 않은 상태에서 앱이 수신 연결을 시작하는데 너무 오래 걸리면(초기화가 오래 걸리면) 클라이언트 요청이 준비되지 않은 파드로 흘러간다.
또한 레디니스 프로브에 종료코드를 포함하지 말아야 한다. 파드 종료시 앱도 종료신호를 받자 마자 연결 수락을 중단한다. 이때 레디니스 프로브가 수행되어야 하지 않나라는 의문이 들 수 있다. 하지만 쿠버네티스는 파드를 삭제하자마자 모든 서비스에서 파드를 제거해서 해당 시점에 레디니스 프로브를 수행할 필요가 없다.
- 헤드리스 서비스
서비스를 연결하면 임의의 파드로 요청이 전달된다. 하지만 클라이언트에서 모든 파드에 연결해야 하거나 파드에서 다른 파드로 각각 연결해야 하는 경우가 존재할 수 있다. 이럴 경우에는 대응을 할 수 없는걸까?
쿠버네티스 API를 호출하면 파드와 해당 파드들의 IP 주소 목록을 알 수 있긴 하지만 앱은 쿠버네티스에 의존하면 안된다.
쿠버네티스에서는 클라이언트가 DNS 조회로 파드 IP를 찾을 수 있는 기능을 제공한다. 기본설정의 경우 서비스에 대한 DNS 조회를 수행하면 서비스의 클러스터 IP 하나만 반환한다.
서비스의 클러스터 IP가 필요하지 않다면 서비스 spec의 clusterIp를 None으로 설정하면 DNS 서버는 파드들의 IP를 반환한다.
- 헤드리스 서비스 생성
서비스 spec의 clusterIp를 None으로 설정하면 쿠버네티스는 클라이언트가 서비스의 파드에 연결할 수 있는 클러스터 IP를 할당하지 않아서 서비스가 "헤드리스(headless)" 상태가 된다.
apiVersion: v1
kind: Service
metadata:
name: kubia-headless
spec:
clusterIP: None
ports:
- port: 80
targetPort: 8080
selector:
app: kubia
위처럼 헤드리스 서비스를 생성하고 아까 생성한 레디니스 프로브 예제의 파드들에 /var/ready 파일을 생성해주자.
- DNS로 파드 찾기
kubia 컨테이너 이미지에는 nslookup이나 dig 같은 바이너리가 없기 대문에 DNS 조회를 테스트해볼 수 없다. DNS를 사용하기 위한 테스트 용도이기 때문에 yaml 파일을 생성하지 않고 DNS만 조회할 수 있게 아래 명령어로 실험한다.
이제 DNS 조회를 할 수 있는 환경이 되었으니 "nslookup kubia-headless"를 실행해보자.
파드 개수대로 IP를 반환함을 알 수 있다. 일반적인 서비스를 DNS 조회 하면 아래와 같이 하나의 서비스 클러스터 IP만 반환한다.
헤드리스 서비스가 일반서비스와 아주 특별하게 다른것 같이 보이지만 클라이언트 입장에서는 별 차이가 없다. 다만 헤드리스 서비스는 프록시대신 파드에 직접 연결하며, 파드간 로드밸런싱을 제공하지만 서비스 프록시 대신 DNS 라운드 로빈 매커니즘으로 동작한다는 차이만 있다.
- 서비스 트러블슈팅
서비스는 쿠버네티스에서 중요한 개념이다. 그래서 많은 개발자들이 서비스 IP, FQDN 으로 파드에 연결하지 못하는 이슈 해결에 많은 시간을 보내곤 한다. 서비스에서 파드로 액세스할 수 없다면 아래 사항을 확인하자.
- 클러스터 내에서 서비스의 클러스터 IP로 연결되는지 확인
- 레디니스 프로브가 성공하는지 확인
- 엔드포인트 오브젝트 조회를 통해 해당 파드가 서비스의 일부인지 확인
- FQDN으로 서비스 액세스가 동작하지 않으면 IP로는 접근되는지 확인
'Framework and Tool > Kubernetes' 카테고리의 다른 글
Kubernetes - Persistent storage (0) | 2022.11.12 |
---|---|
Kubernetes - Volume (0) | 2022.11.12 |
Kubernetes - ingress (0) | 2022.10.30 |
Kubernetes - External service, Service export (0) | 2022.10.24 |
Kubernetes - Service intro (0) | 2022.10.21 |
댓글