일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- CI/CD
- opensearch
- Kopf
- nginx ingress
- gitops
- Litmus
- argocd
- serving
- opentelemetry
- 오퍼레이터
- gitea
- keda
- Model Serving
- argo rollout
- knative
- CANARY
- Kubernetes
- MLflow
- Pulumi
- Kubeflow
- Continuous Deployment
- tekton
- Kubernetes 인증
- Argo
- 카오스 엔지니어링
- mlops
- kubernetes operator
- blue/green
- seldon core
- operator
- Today
- Total
Kubernetes 이야기
컨테이너 환경에서 JVM Memory 설정 본문
일반적으로 Java App에서 Heap Space를 조절하기 위해서는 JAVA OPT 를 Xms, Xmx로 설정이 일반적이다.
java -Xms512m -Xmx512m test.jar
하지만 Kubernetes의 Container 환경에서는 사이즈를 고정하는 부분은 많은 고민이 필요하다. 왜냐하면 Kubernetes에서 Pod 를 생성시에는 resource 를 설정할 수 있기 때문이다.
containers:
- name: tomcat
image: tomcat:9
env:
- name: JAVA_OPTS
value: "-Xms1024m -Xmx1024m"
resources:
requests:
memory: "500Mi"
limits:
memory: "500Mi"
위와 같이 Container에 memory 제한을 설정하고, Tomcat memory설정에는 최대 1024m 로 설정하는 OOMKiller에 의해 Container가 재기동 될 수 있다.
Container resource에 제한이 없는 경우 물리적인 메모리가 1G 이상이라면 정상적으로 운영될 수는 있을 것이다.
Container에 가급적 resource 제한을 설정하는 것을 권장하기 때문에 일반적으로 설정하는 JAVA_OPTS의 -Xms와 -Xmx는 Kubernetes환경에서는 맞지 않는다.
그래서, OpenJDK에서는 UseContainerSupport 옵션이 지원된다. ( 기본값 True )
그럼 Container 환경에서 Java application의 메모리 설정방법을 알아보자.
-XX:InitialRAMPercentage
'-XX:InitialRAMPercentage'는 '-Xms' JVM 인수가 전달되지 않은 경우에만 초기 힙 크기를 설정하는데 사용된다.
'-Xms' JVM 인수가 설정되면 이 옵션은 무시한다.
-XX:MaxRAMPercentage, -XX:MinRAMPercentage
컨테이너에 1GB의 메모리를 할당했다고 가정하고 -XX:MaxRAMPercentage=50을 구성하면 약 512GB(1GB의 1/2)가 Java 힙 크기에 할당된다.
'-XX:MaxRAMPercentage' 및 '-XX:MinRAMPercentage'는 모두 최대 Java 힙 크기를 결정하는 데 사용된다.
'-XX:MinRAMPercentage' JVM 인수는 물리적 서버(또는 컨테이너)에서 사용 가능한 전체 메모리 크기가 약 250MB 미만인 경우에만 Java 힙 크기를 계산하는 데 사용된다. -XX:MinRAMPercentage=50을 구성하고 전체 물리적 메모리(또는 컨테이너) 메모리가 100MB라고 가정하면 Java 애플리케이션의 최대 힙 크기는 50MB(즉, 100MB의 50%)로 설정된다.
'-XX:MaxRAMPercentage' JVM 인수는 물리적 서버(또는 컨테이너)에서 사용 가능한 전체 메모리 크기가 250MB(대략) 이상인 경우에만 Java 힙 크기를 계산하는 데 사용된다. -XX:MaxRAMPercentage=75를 구성하고 전체 물리적 서버(또는 컨테이너) 메모리가 1GB라고 가정하면 Java 애플리케이션의 최대 힙 크기는 750MB(즉, 1GB의 75%)로 설정된다.
-XX:MaxRAMPercentage, -XX:MinRAMPercentage 옵션은 OpenJDK8 u191 이상에서만 지원된다.
'-Xms' JVM 인수가 설정되면 이 옵션들은 무시된다.
그럼 한번 설정을 해보자.
# cat <<EOF | kubectl create -f -
apiVersion: batch/v1
kind: Job
metadata:
name: openjdk
spec:
template:
spec:
containers:
- name: openjdk
image: docker.io/openjdk:10
command: ["java", "-XX:InitialRAMPercentage=25", "-XX:MaxRAMPercentage=50", "-XshowSettings:all", "-version"]
restartPolicy: Never
backoffLimit: 4
EOF
# kubectl logs openjdk-j674q
[root@master ~]# k logs openjdk-dr4fm
VM settings:
Max. Heap Size (Estimated): 7.56G
Using VM: OpenJDK 64-Bit Server VM
...
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Debian-2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-2, mixed mode)
# free -h
total used free shared buff/cache available
Mem: 15Gi 1.8Gi 10Gi 41Mi 3.3Gi 13Gi
위의 정보를 보면 MaxRAMPercentage=50으로 설정했다. jvm 정보를 보면 7.56G 가 최대 Heap Size로 설정되었다. 이유는 노드의 메모리가 15Gi이기 때문에 15G의 50%로 설정된 것이다.
이제 kubernetes에 resource 설정을 한 후 테스트해보자.
# cat <<EOF | kubectl create -f -
apiVersion: batch/v1
kind: Job
metadata:
name: openjdk
spec:
template:
spec:
containers:
- name: openjdk
image: docker.io/openjdk:10
command: ["java", "-XX:InitialRAMPercentage=25", "-XX:MaxRAMPercentage=50", "-XshowSettings:all", "-version"]
resources:
limits:
memory: "1000Mi"
requests:
memory: "1000Mi"
restartPolicy: Never
backoffLimit: 4
EOF
# kubectl logs openjdk-55tgd
VM settings:
Max. Heap Size (Estimated): 483.38M
Using VM: OpenJDK 64-Bit Server VM
...
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Debian-2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-2, mixed mode)
위와 같이 최대 메모리를 1G 로 Resource를 제한하면 Java의 Heap Memory는 50%인 500M 정도 설정됨을 확인할 수 있다.
결론
Java에서는 Heap Memory외에 non-heap ( GC, Metaspce, Code ... )의 영역이 있기 때문에 Resource 의 limit 값보다 적게 설정되어야 한다. ( JNI를 사용하는 경우는 JNI 영역에 필요한 메모리를 별도 계산해야 한다. )
그래서 보통 limit의 70~80% 정도로 heap memory 설정을 하면 OOM Killer가 작동하지 않고 운영될 수 있다.
참고
https://www.ibm.com/docs/en/sdk-java-technology/8?topic=options-xx-usecontainersupport
https://songrgg.github.io/operation/how-to-setup-java-application-memory-limit-in-kubernetes/
https://dzone.com/articles/best-practices-java-memory-arguments-for-container
https://github.com/docker-library/openjdk/issues/245
https://blog.softwaremill.com/docker-support-in-new-java-8-finally-fd595df0ca54
'Kubernetes > 일반' 카테고리의 다른 글
Pod Disruption Budget (0) | 2022.05.19 |
---|---|
Kubernetes Ephemeral Containers를 사용하여 debug 하기 (0) | 2022.05.11 |
nginx ingress controller 를 helm chart로 배포하기 (0) | 2022.05.09 |
Kubernetes + containerd 설치 ( centos8 ) (0) | 2022.05.09 |
올바른 Kubernetes manifest 작성하기 (0) | 2022.05.05 |