본문 바로가기
Spring

Kubernetes 에서 안전하게 힙 덤프 수행하기

by 초보개발자96 2024. 6. 13.

운영 중인 서비스를 모니터링 하다보면 메모리 사용량이 비정상적인 경우가 있다. 메모리 사용량이 지속적으로 우상향하여 누수 현상이 의심되거나 객체가 비정상적으로 많이 할당된다는 생각이 들면 힙 덤프를 분석하여 원인을 진단할 수 있다.

힙 덤프는 어떤 프로세스의 특정 순간의 메모리 스냅샵이다. 분석하려는 서버에 접근하여 힙 덤프를 생성하고 MAT 과 같은 도구로 이를 분석하면 유의미한 결과를 얻을 수도 있다. 자바에서는 JDK 와 함께 번들로 제공되는 jmap 명령을 이용하면 쉽게 생성할 수 있다.

다만, 머신 입장에서 힙 덤프는 쉽게 생성할 수 있는 파일이 아니다. 어플리케이션에 할당된 메모리 양이 클수록 힙 덤프 수행시간도 오래걸리고, 힙 덤프를 생성하기 전에 필요없는 객체를 없애도록 Full GC 를 수행할 수도 있다. 즉, 실제 요청을 받고 있는 서버에 접근하여 힙 덤프를 생성하면 요청 처리에 영향을 주게 된다. 따라서 특정 서버의 메모리 상태를 확인하고 싶으면 대상 서버는 요청을 받지 못하도록 격리하고 힙 덤프를 수행해야 한다.

 

레이블 조정으로 파드 격리하기

쿠버네티스는 파드에 문제가 발생하면 해당 파드를 곧바로 종료(terminate)하고 새로운 파드를 만든다. 각 파드는 상호 연결되어 있을 수 있는데, 실시간으로 생성되는 파드를 연결하는 작업을 수동으로 하는 것은 매우 어렵다.

쿠버네티스의 서비스는 파드 간 네트워크 연결을 담당하는 리소스로, 파드 간 연결을 자동으로 가능하게 해준다. 서비스는 필요한 파드를 선택하기 위해 셀렉터(Selector) 옵션을 이용하고, 셀렉터는 내부적으로 레이블(label)을 기준으로 리소스를 선택한다.

 

# Deployment
labels:
  app: heapdump-test
 
 
# Service
selector:
  app: heapdump-test

 

만약 파드의 레이블을 임의의 값으로 조정하면 서비스는 파드를 선택할 수 없게 되고, 어떠한 서비스에게도 선택받지 못한 파드는 격리된 것으로 볼 수 있다. 레이블 수정은 아래 명령으로 간단히 수행할 수 있다 (Deployment 는 replicaCount 를 유지하기 위해 파드 하나를 새로 생성한다).

 

kubectl label pod <pod-name> <label-key>=<label-value> --overwrite

 

파드가 격리되면 외부 요청을 받지 않으므로, 파드에 접근하여 힙 덤프를 마음껏 생성할 수 있다 (아래는 명령어 예시이다).

 

# 파드 접근
kubectl exec -n <네임스페이스> -it <파드 이름> -- bash


# jmap 이 없는 경우 설치
apt-get update
apt-get install openjdk-17-jdk


# jmap 수행 후 파일 copy
jmap -dump:format=b,file=<파일 이름>.hprof <ps>
kubectl cp -n <네임스페이스> <파드 이름>:/<파일 이름>.hprof <파일 이름>.hprof