TroubleShooting : OOM in Pod
- 프로그래밍 삽질 / 디버깅
- 2025. 4. 3.
반응형
상황
- 플랫폼 A의 k8s에서 플랫폼 B의 k8s로 옮기는 작업 도중에 발생함.
- Pod A에서는 컨테이너 A1, A2가 존재함.
- 컨테이너 A1 : 메인 컨테이너. CLI Management를 위한 컨테이너다. 그리고 파이썬 Daemon Process가 하나 가동중이다.
- 컨테이너 A2 : 인증정보를 업데이트 하기 위한 Sidecar
문제
$ k get pod
NAME READY STATUS RESTARTS AGE
my-pod 1/2 OOMKilled 0 44s
# 플랫폼 B의 k8s
$ kubectl tops pod --containers | grep my-pod
my-pod container A1 1000m 24335Mi
my-pod container A2 1m 8Mi
# 플랫폼 A의 k8s
$ kubectl tops | grep my-pod
my-pod 3m 199Mi
- 기존 플랫폼 A k8s에서는 문제없이 동작중이었음. 그러나 동일한 Pod를 플랫폼 B k8s에 띄었을 때, 1분 이내에 OOMKilled가 발생함.
- Container A1에서 1 Core와 24GB의 메모리를 사용중이었고, 이 때문에 OOMKilled가 발생한 것을 확인함.
- 이 때, CPU Usage가 1 Core 이상으로 올라가지 않았기 때문에 파이썬 관련 프로세스일 것으로 판단함.
- 파이썬 데몬 프로세스쪽이 문제인지 확인작업 진행
- 파이썬 데몬 프로세스를 끄니 메모리 사용량이 플랫폼 A와 동일해짐.
- 파이썬 데몬 프로세스를 Foreground 프로세스로 기동해봄. 동일한 프로세스를 Foreground로 돌렸을 때는 문제 발생하지 않는 것을 확인함.
- 위 작업을 통해 파이썬 어플리케이션을 데몬프로 돌렸을 때 문제가 발생한다는 것으로 범위를 좁힘.
- 파이썬 데몬 프로세스쪽이 문제인지 확인작업 진행
$ py-spy top --pid=701
...
%Own %Total OwnTime TotalTime Function (filename)
100.00% 100.00% 32.00s 32.00s _b (a/a.py)
0.00% 100.00% 0.000s 32.00s a (a/a.py)
...
- py-spy를 이용해서 callstack을 확인함. (pip install py-spy)
- _b(...) 함수가 모든 CPU를 점유한 것을 확인함. (OwnTime = 32.00s)
def _b(...):
...
(__, hard_limit) = resource.getrlimit(resource.RLIMIT_NOFILE)
set(range(0, hard_limit)).differecne(...)
...
- _b(...) 함수는 내부적으로 resource.getrlimit(...)를 호출한다. 여기서 얻은 hard_limit을 이용해서 존재할 수 있는 모든 FiledDescriptor 번호로 파이썬 Set을 만든다.
- 실제로 문제가 되었던 부분은 set(range(0, hard_limit)) 부분이었다.
- 플랫폼 A에서는 ulimit이 1,000,000수준, 플랫폼 B에서는 ulimit이 10,000,000,00 수준이었다. 0 ~ 10억까지의 번호를 가지는 Set을 만들려고 했기 때문에 CPU + 메모리 관점에서 문제가 발생했다.
해결방법
- Helm Template을 이용해 Pod Entrypoint에 플랫폼 B인 경우 ulimit -n <적절한 숫자>가 조건문으로 실행되도록 수정함.
- Worker Node 레벨, Container Runtime에서는 수정할 권한이 없었음.
- 해당 라이브러리의 최신 버전에서는 문제 코드가 수정된 것으로 보임. 필요하다면 라이브러리 업그레이드 고려가 필요함.
알게된 점
- 파드 내에 여러 개의 컨테이너가 있는 경우, 각 컨테이너마다 PID, 마운트, 유저, UTS 등 모든 네임 스페이스를 각각 사용한다.
- 따라서 초기화 컨테이너에서 ulimit을 설정하더라도, 메인 컨테이너에는 적용이 안된다.
- k8s container는 Node의 영향을 여전히 받는다.
'프로그래밍 삽질 > 디버깅' 카테고리의 다른 글
Spring Batch : JpaItemReader + @StepScope NullPointException (0) | 2022.03.19 |
---|---|
Spring Batch : JDBC Reader Id값 맵핑 안될 때 (0) | 2022.03.19 |
No serializer found for class 에러 상황 (0) | 2022.01.17 |
@RequestBody 바인딩이 안될 때 (0) | 2022.01.15 |
Spring MVC : View 랜더링이 안될 때 (0) | 2022.01.11 |