StatCounter - Free Web Tracker and Counter

TroubleShooting : OOM in Pod

반응형

상황

  • 플랫폼 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 이상으로 올라가지 않았기 때문에 파이썬 관련 프로세스일 것으로 판단함. 
      • 파이썬 데몬 프로세스쪽이 문제인지 확인작업 진행
        1. 파이썬 데몬 프로세스를 끄니 메모리 사용량이 플랫폼 A와 동일해짐. 
        2. 파이썬 데몬 프로세스를 Foreground 프로세스로 기동해봄. 동일한 프로세스를 Foreground로 돌렸을 때는 문제 발생하지 않는 것을 확인함. 
        3. 위 작업을 통해 파이썬 어플리케이션을 데몬프로 돌렸을 때 문제가 발생한다는 것으로 범위를 좁힘.

 

$ 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 + 메모리 관점에서 문제가 발생했다. 

 


해결방법

  1. Helm Template을 이용해 Pod Entrypoint에 플랫폼 B인 경우 ulimit -n <적절한 숫자>가 조건문으로 실행되도록 수정함.
    • Worker Node 레벨, Container Runtime에서는 수정할 권한이 없었음. 
  2. 해당 라이브러리의 최신 버전에서는 문제 코드가 수정된 것으로 보임. 필요하다면 라이브러리 업그레이드 고려가 필요함. 

 


알게된 점

  • 파드 내에 여러 개의 컨테이너가 있는 경우, 각 컨테이너마다 PID, 마운트, 유저, UTS 등 모든 네임 스페이스를 각각 사용한다.
    • 따라서 초기화 컨테이너에서 ulimit을 설정하더라도, 메인 컨테이너에는 적용이 안된다.
  • k8s container는 Node의 영향을 여전히 받는다. 

댓글

Designed by JB FACTORY