/////

docker-oom-kill-unset-mem-limit

운영 환경의 Node.js 컨테이너가 주기적으로 종료되고 Docker 상태에서 State.OOMKilled=true 또는 exit code 137이 관찰된다. 애플리케이션 로그에는 JavaScript 예외나 V8 stack trace가 남지 않을 수 있다.

/////

현상#

운영 환경의 Node.js 컨테이너가 주기적으로 종료되고 Docker 상태에서 State.OOMKilled=true 또는 exit code 137이 관찰된다. 애플리케이션 로그에는 JavaScript 예외나 V8 stack trace가 남지 않을 수 있다.

정정된 원인 모델#

이 장애를 docker-compose.yml에 mem_limit이 없어서 V8이 항상 1.5GB 기본 힙으로 잘못 추정했다`로 단정하면 안 된다.

더 안전한 설명은 다음과 같다.

  1. 컨테이너에 명시적 메모리 제한이 없으면, 해당 컨테이너는 Docker/호스트/상위 orchestrator가 허용하는 범위까지 메모리를 사용할 수 있다. 이 경우 한 프로세스의 RSS 증가가 호스트 또는 상위 cgroup의 메모리 압박으로 이어져 OOM killer의 대상이 될 수 있다.
  2. Node.js/V8의 기본 heap sizing과 cgroup 인식은 Node/V8 버전, cgroup v1/v2, Docker Engine, 베이스 이미지와 실행 환경에 따라 달라진다. 따라서 V8 기본 힙은 항상 1.5GB 또는 V8은 컨테이너 제한을 전혀 보지 못한다 같은 고정값·보편 명제는 피한다.
  3. --max-old-space-size는 V8 old generation heap 한도일 뿐, 전체 RSS 한도가 아니다. Buffer, native addon, libuv, mmap, 코드 영역, 스레드 stack, allocator overhead 등은 별도로 메모리를 사용한다.
  4. exit code 137은 OOM kill에서 흔하지만, 모든 137 종료가 동일한 원인은 아니다. docker inspect, Docker event, kernel log, cgroup 메트릭, 애플리케이션 메모리 지표를 함께 확인해야 한다.

확인 절차#

  1. docker inspect <container>에서 다음을 확인한다. - State.OOMKilled - State.ExitCode - HostConfig.Memory - HostConfig.MemorySwap - HostConfig.NanoCpus, CpuQuota, CpuPeriod, PidsLimit 등 관련 제한
  2. 컨테이너 내부/호스트에서 cgroup 메모리 값을 확인한다. - cgroup v2라면 memory.max, memory.current, memory.events 등 - cgroup v1이라면 memory limit/usage/failcnt 계열 파일
  3. Node.js 런타임에서 실제 관측값을 남긴다. - process.memoryUsage().rss - heapUsed, heapTotal, external, arrayBuffers - v8.getHeapStatistics()
  4. 커널 로그 또는 Docker events에서 OOM kill 시점과 프로세스명을 대조한다.

수정 가이드#

1. Compose에서 메모리 한도를 명시한다#

단일 호스트 docker compose up 운영이라면 서비스 레벨 제한을 우선 확인한다.

services:
  app:
    image: example/app:latest
    mem_limit: 1g
    memswap_limit: 1g
    environment:
      NODE_OPTIONS: --max-old-space-size=768

deploy.resources.limits.memory는 Compose/Swarm/Compose CLI 버전에 따라 적용 범위와 기대 동작을 확인해야 한다. 운영에서는 docker inspect로 실제 HostConfig.Memory에 반영됐는지 검증한다.

2. Node heap 한도는 RSS 예산에서 역산한다#

NODE_OPTIONS=--max-old-space-size=...는 컨테이너 전체 메모리보다 충분히 낮게 둔다. 단, “항상 10%만 남기면 된다”가 아니라 워크로드별 RSS 구성을 보고 정한다.

예시:

  • 컨테이너 메모리 한도: 1g
  • V8 old-space-size: 700~800MB부터 시작
  • Buffer/native/external memory가 큰 서비스라면 더 낮게 설정
  • 부하 테스트에서 RSS peak와 OOM event를 확인한 뒤 조정

3. swap 설정은 Docker/커널/cgroup 조건을 검증한다#

Docker의 memswap_limit 또는 --memory-swap은 memory+swap 총량을 제어한다. 일반적으로 memory와 memory-swap을 같은 값으로 두면 swap 사용을 막으려는 의도에 맞지만, 실제 의미는 Docker Engine, cgroup 버전, 호스트 swap 활성화 여부에 따라 검증해야 한다.

검증 없이 memswap_limit: mem_limit이 모든 환경에서 반드시 swap 우회를 금지한다고 단정하지 않는다.

4. healthcheck는 생존성 신호이고 메모리 관측은 별도 지표로 둔다#

healthcheck로 RSS 임계값 초과 시 unhealthy를 만들 수는 있지만, 메모리 누수 탐지의 주 수단은 메트릭과 알림이어야 한다.

권장 관측 항목:

  • container RSS / working set
  • cgroup memory current/max/events
  • Node process.memoryUsage()
  • GC pause/heap statistics
  • OOMKilled count와 restart count

핵심 교훈#

  • 컨테이너 메모리 한도는 Compose 설정만 믿지 말고 docker inspect와 cgroup 파일로 실제 반영 여부를 확인한다.
  • Node/V8의 기본 heap 동작은 버전 의존적이므로 고정된 1.5GB 규칙으로 설명하지 않는다.
  • --max-old-space-size는 전체 RSS 제한이 아니라 V8 old heap 제한이다.
  • memswap_limit은 의도와 실제 동작을 부하 테스트와 cgroup 관측으로 검증한다.
  • OOM kill 분석은 exit code 137 하나가 아니라 Docker 상태, kernel log, cgroup event, 런타임 메트릭을 함께 봐야 한다.

Sagwan Revalidation 2026-09-27T02:17:46Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 원인 설명의 백틱 오류로 문서 정리가 필요하다.

Sagwan Revalidation 2026-10-01T07:52:08Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 원인 설명의 백틱 오류가 남아 있어 수정이 필요하다.

Sagwan Revalidation 2026-10-04T03:05:22Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 원인 설명의 백틱 오류와 확인 절차의 목록 서식을 수정해야 한다.

Sagwan Revalidation 2026-10-07T04:29:15Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 원인 설명의 백틱 오류와 확인 절차의 목록 서식이 남아 있다.

Sagwan Revalidation 2026-10-10T01:30:52Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 백틱 오류와 확인 절차의 목록 서식이 남아 있다.

Sagwan Revalidation 2026-10-12T19:57:30Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 백틱 오류와 확인 절차의 목록 서식이 남아 있다.

Sagwan Revalidation 2026-10-15T15:34:10Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 원인 설명의 백틱 오류와 확인 절차의 목록 서식이 남아 있다.

Sagwan Revalidation 2026-10-18T12:36:19Z#

  • verdict: refresh
  • note: 기술 내용은 대체로 유효하지만 백틱 오류와 확인 절차의 목록 서식이 여전히 남아 있다.

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1