Java 安裝在 Docker 容器的記憶體問題

Docker 容器佔用大量記憶體空間

Docker VM 的記憶體使用量很高,進去看16G 的記憶體的機器,才裝12個 Docker 容器,一個一個檢查才發現幾個是跑 Java APP 的容器吃的記憶體特別高(1G~3G 之間),但有些容器都是 Serverless 類型的服務,不應該佔用那麼多記憶體。

Java 支援 Docker 的記憶體限制

在容器內部執行 JVM,預設 Max Heap Size 會是主機記憶體的1/4,而非容器記憶體的1/4(所以我 docker run 設定 memory 參數也沒用)。

在Java 8u131 之後支援了 Docker CPU 和記憶體的限制,在 Java 8 上要使用以下參數:

  • UnlockExperimentalVMOptions:開啟實驗性質的選項。
  • UseCGroupMemoryLimitForHeap:使用 cgroup(control group) 記憶體大小來計算 Max Heap Size ,白話就是偵測到 Docker 容器的記憶體。
  • MaxRAMFraction:將偵測到的記憶體除以這個數字,就是 Max Heap Size。這邊設為1,搭配 UseCGroupMemoryLimitForHeap 的效果就是 Docker 容器的記憶體大小除以1就是 Max Heap Size,白話就是不會超過 Docker 容器設定的記憶體。

# 建立一個記憶體500 MB 有 JRE 8 的容器,執行 Java 指令印出 Max. Heap Size
# 調整 docker run 的 memory 參數,可以影響容器內 JVM 使用的記憶體大小。
docker run --memory 500MB openjdk:8-jre java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XX:MaxRAMFraction=1 \
-XshowSettings:vm \
-version

參考:

修正 Dockerfile 以及 docker run

了解上一章節的參數後,首先記得 docker run 一定要加上 memory 參數來限制容器的記憶體。

再來就是將原本執行 Java 程式的命令列(看是寫在 docker run 指令還是寫在 Dockerfile 裡頭)加上參數。這樣就能解決 Docker 容器跑 Java 程式佔用太多記憶體的問題。


# 執行 app.jar
docker run --memory 500MB openjdk:8-jre java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XX:MaxRAMFraction=1 \
-jar path/to/your/app.jar

# Dockerfile
# 省略
CMD ["java", "-Dspring.profiles.active=test", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:MaxRAMFraction=1", "-XshowSettings:vm",  "-jar", "path/to/your/app.jar"]

0 則回應: