gRPC 서비스에 health check 구현하기
문제 상황
사내 결제 시스템을 gRPC로 전환하면서 Kubernetes에서 서비스 상태를 체크할 방법이 필요했다. HTTP 서버와 달리 gRPC는 별도의 health check 엔드포인트가 없어서 pod이 정상인지 판단할 수 없었다.
gRPC Health Checking Protocol
gRPC에는 표준 health check 프로토콜이 정의되어 있다. grpc.health.v1.Health 서비스를 구현하면 된다.
syntax = "proto3";
package grpc.health.v1;
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
}
ServingStatus status = 1;
}
Node.js 구현
grpc-health-check 패키지를 사용했다.
const grpc = require('@grpc/grpc-js');
const health = require('grpc-health-check');
const server = new grpc.Server();
const healthImpl = new health.Implementation({
'': health.servingStatus.SERVING,
'payment.PaymentService': health.servingStatus.SERVING,
});
server.addService(health.service, healthImpl);
// DB 연결 실패 시 상태 변경
db.on('error', () => {
healthImpl.setStatus('payment.PaymentService',
health.servingStatus.NOT_SERVING);
});
Kubernetes 설정
grpc-health-probe를 사용해 liveness/readiness probe를 구성했다.
apiVersion: v1
kind: Pod
spec:
containers:
- name: payment-service
image: payment:latest
livenessProbe:
exec:
command: [
"/bin/grpc-health-probe",
"-addr=:50051"
]
initialDelaySeconds: 10
readinessProbe:
exec:
command: [
"/bin/grpc-health-probe",
"-addr=:50051",
"-service=payment.PaymentService"
]
결과
배포 시 DB 마이그레이션이 완료될 때까지 pod이 NOT_SERVING 상태로 대기하도록 구현했다. 트래픽이 준비되지 않은 pod으로 가는 문제가 해결되었고, 무중단 배포가 안정적으로 동작하게 되었다.