![[Docker] 컨테이너 리소스 사용량 제한](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkxsqo%2FbtsNX24oS1w%2FPNyyvAzCaFuRV7ODlPqg41%2Fimg.webp)
이 글은 인프런의 개발자를 위한 쉬운도커(데브위키) 강의를 수강하고 개인적으로 정리하는 글임을 알립니다.
- 기업에서는 수평적 확장보다 수직적 확장이 더 효율적인 경우가 많다.
- 성능이 좋은 고사양 서버를 구매하고 이를 도커 컨테이너나 가상화 기술을 통해 논리적으로 여러 대의 서버로 분할하면 되기 때문이다.
- 이는 실제로 물리적 서버를 여러 대 구매하고 관리하는 수평적 확장의 복잡성과 비용을 줄이면서도 유사한 효과를 얻을 수 있는 전략이다.
이때 컨테이너에 리소스 사용량 제한을 두지 않으면 실행되는 컴퓨터의 최대 리소스를 사용하게 된다.
이는 하나의 성능이 좋은 컴퓨터를 논리적으로 여러 대의 컴퓨터로 운영하는 도커의 장점을 무색하게 만들 수 있다. 리소스 제한을 설정하지 않은 하나의 컨테이너가 CPU나 메모리를 과도하게 점유하면 다른 컨테이너들의 성능이 저하되거나 장애가 발생할 수 있으며, 특히 프로덕션 환경에서는 서비스 전체의 안정성을 해치는 결과를 초래한다.
따라서 --cpus, --memory 옵션이나 Docker Compose의 deploy 설정을 통해 각 컨테이너가 사용할 수 있는 리소스 상한선을 명확히 정의하여 컨테이너 간 리소스 균형을 유지하고 시스템의 안정적인 운영을 보장하는 것이 중요하다.
컨테이너 리소스 사용량 제한
# CPU 2코어, 메모리 1GB로 제한
docker run --cpus=2 --memory=1g nginx
# CPU 0.5코어, 메모리 512MB, 스왑 512MB 추가 허용(총 1024MB)
docker run --cpus=0.5 --memory=512m --memory-swap=1024m mysql
메모리 제한 초과 시 (OOM)
- 컨테이너가 --memory=512m로 지정된 메모리 한도를 초과하면, 스왑 메모리(--memory-swap=1024m - --memory=512m = 512MB의 스왑)를 사용하기 시작한다.
- 스왑 메모리까지 모두 소진하면(총 1GB), OOM(Out Of Memory) Killer가 작동하여 컨테이너 내 프로세스를 강제 종료한다.
결과적으로 컨테이너가 종료(Exit)된다. - 이 상태는 docker ps -a에서 Exit 코드 137(128 + SIGKILL의 signal number 9)로 확인할 수 있다.
CPU 제한 초과 시
- 컨테이너가 지정된 CPU 사용량을 초과하려고 하면, 도커는 스로틀링(throttling)을 적용한다.
- 컨테이너는 종료되지 않고 계속 실행되지만, CPU 시간이 제한되어 성능이 저하된다.
- 실행 속도가 느려질 뿐, 오류나 종료가 발생하지 않는다.
- 이는 docker stats나 cAdvisor와 같은 모니터링 도구에서 CPU 제한 도달로 확인할 수 있다.
컨테이너 리소스 사용량 조회
docker stats [컨테이너명/ID]
위 명령어는 해당 컨테이너의 리소스 사용량을 조회 할 수 있다.
JVM 사용량 제한
자바 애플리케이션이 사용할 수 있는 메모리 영역인 힙(Heap) 메모리를 별도로 관리해야 한다.
위 그림에서 도커 컨테이너의 메모리를 16기가로 제한했는데 JVM이 4기가로 다시 제한한다면 의도한만큼의 퍼포먼스가 발생하지 않을 수 있다.
자바8 이전에는 사용자가 아래와 같이 컨테이너를 인식하도록 설정했어야 했지만, java 10 부터는 이런 환경 변수를 추가할 필요가 없게 되었다.
Dockerfile
ENV JAVA_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" |
하지만 최적화는 필요하다. 자동 힙 크기 설정은 여전히 최적이 아닐 수 있다.
메모리 제한이 있는 컨테이너에서 기본 설정은 1/4만 힙으로 할당하기 때문이다.
-XX:MaxRAMPercentage=75.0 # 또는 -XX:InitialRAMPercentage=50.0 |
- 2GB 메모리 제한이 있는 컨테이너에서, 기본 설정은 1/4 (약 500MB)만 힙으로 할당
- -XX:MaxRAMPercentage=75.0을 사용하면 약 1.5GB를 할당
이런 비율 기반 설정을 통해 컨테이너 메모리를 효율적으로 활용할 수 있다.
힙메모리 사용량을 제한하는 이유
JVM은 동적 메모리 외에 정적 메모리가 전체 메모리의 15-25%를 차지한다. 실제 운영 환경에서 75%가 안정성과 성능의 균형점으로 확인되었다 대부분의 스프링부트 애플리케이션에 적합한 비율이다.
Dockerfile
참고로 위와 같이 프로덕션 환경, 특히 마이크로서비스나 컨테이너 환경에서는 초기 힙과 최대 힙을 비슷하게 설정하는 것이 성능과 안정성에 좋다.
ENV JAVA_OPTS="-XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=75.0"
결론은 Java 10 이상에서는 컨테이너 인식이 자동화되었지만, 최적의 성능과 안정성을 위해서는 여전히 힙 메모리 설정을 명시적으로 조정하는 것이 좋다.
특히 프로덕션 환경에서는 메모리 비율 설정과 GC 튜닝이 중요하다.
'DevOps > Docker' 카테고리의 다른 글
[Docker] Dockerfile (0) | 2025.05.14 |
---|---|
[Docker] 볼륨 (Volume) (0) | 2025.05.14 |
[Docker] 자주 사용하는 명령어 정리 (1) | 2025.05.13 |
[Docker] 애플리케이션 종료시 Compose 자동시작 (1) | 2024.10.13 |
[Docker + SpringBoot] 스프링부트 로그 파일 남기기 (1) | 2024.10.11 |