千家信息网

如何在Docker里跑Java

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,本篇内容介绍了"如何在Docker里跑Java"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!背景:众
千家信息网最后更新 2026年11月04日如何在Docker里跑Java

本篇内容介绍了"如何在Docker里跑Java"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

背景:众所周知,当我们执行没有任何调优参数(如"java-jar mypplication-fat.jar")的 Java 应用程序时,JVM 会自动调整几个参数,以便在执行环境中具有最佳性能。

但是许多开发者发现,如果让 JVM ergonomics (即JVM人体工程学,用于自动选择和行为调整)对垃圾收集器、堆大小和运行编译器使用默认设置值,运行在 Linux 容器(docker,rkt,runC,lxcfs 等)中的 Java 进程会与我们的预期表现严重不符。

懒人超精简阅读版:

a.JVM 做不了内存限制,一旦超出资源限制,容器就会出错

b.即使你多给些内存资源,也没什么卵用,只会错上加错

c.解决方案:用 Dockfile 中的环境变量来定义 JVM 的额外参数

d.更进一步:使用由 Fabric8 社区提供的基础 Docker 镜像来定义 Java 应用程序,将始终根据容器调整堆大小

详细全文:

我们往往把容器当虚拟机,让它定义一些虚拟 CPU 和虚拟内存。其实容器更像是一种隔离机制:它可以让一个进程中的资源(CPU,内存,文件系统,网络等)与另一个进程中的资源完全隔离。Linux 内核中的 cgroups 功能用于实现这种隔离。

然而,一些从执行环境收集信息的应用程序已经在 cgroups 存在之前就被执行了。"top","free","ps",甚至 JVM 等工具都没有针对在容器内执行高度受限的 Linux 进程进行优化。

1.存在的问题

为了演示,我用"docker-machine create -d virtualbox -virtualbox-memory '1024' docker1024"在1GB RAM 的虚拟机中创建了 docker daemon。接下来,在一个虚拟内存为100MB 的容器里面跑三个不同的Linux distribution,执行 "free -h"命令,结果是:它们都显示了995MB 的总内存。

即使在 Kubernetes / OpenShift 集群中,结果也类似。

我在一个15GB 内存的集群中跑一个 Kubernetes Pod ,并将 Pod 的内存限制为512M (通过"kubectl run mycentos -image=centos -it -limits='memory=512Mi'"命令实现),最后显示的总内存却是14GB。

如果想知道为什么会发生这种情况,建议您阅读博客"Memoryinside Linux containers - Or why don't free and top work in a Linux container?"(https://fabiokung.com/2014/03/13/memory-inside-linux-containers/)

docker switches(-m,-memory和-memory-swap)和kubernetes switch(-limits)在进程超过限制的情况下,会指示 Linux 内核杀死该进程;但 JVM 是完全不知道限制,所以在进程超过限制的时候,糟糕的事情就发生了!

为了模拟在超过指定的内存限制后被杀死的进程,我们可以通过"docker run -it -name mywildfly -m=50m jboss/wildfly" 命令在50MB 内存限制的容器中跑WildFly应用 server,用 "dockerstats" 命令来检查容器限制。

但是在几秒钟之后,Wildfly 的容器执行将被中断并显示:*** JBossAS process (55) received KILL signal ***

"docker inspect mywildfly -f '{{json.State}}'" 命令显示由于 OOM(内存不足),该容器已被杀死。注意容器 "state" 中的OOMKilled = true。

2.JAVA的应用程序是如何被影响的?

在docker daemon里用 Dockerfile 中定义的参数-XX:+ PrintFlagsFinal和-XX:+ PrintGCDetails起一个 java 应用。

其中 machine:1GB RAM 容器内存:限制为150M (对于这个Spring Boot应用,似乎够用)

这些参数允许我们读取初始JVM人机工程学参数,并了解有关垃圾收集(GC)执行的详细信息。

动手试一下:

我已经在"/ api / memory /"上准备了一个端点,它使用 String 对象加载 JVM 内存来模拟消耗大量内存的操作。我们来调用一次:

此端点将回复"分配超过80%(219.8 MiB)的最大允许 JVM 内存大小(241.7 MiB)"

在这里我们可以提至少两个问题:

  • 为什么JVM最大允许内存241.7 MiB?

  • 如果这个容器将内存限制为150MB,那为什么它允许Java分配近220MB?

首先,我们需要回顾一下 JVM 人机工程学页面上关于"最大堆大小"的内容:是物理内存的1/4。由于 JVM 不知道它在一个容器内执行,所以允许最大堆大小将接近260MB。鉴于我们在容器初始化期间添加了-XX:+ PrintFlagsFinal标志,我们可以检查这个值:

其次,我们需要了解,当我们在 docker 命令行中使用参数"-m 150M"时,docker daemon将在RAM中限制150M ,在 Swap 中限制为150M。因此,该过程可以分配300M。这就解释了为什么我们的进程没有被杀死。

docker 命令行中的内存限制(-memory)和swap(-memory-swap)之间的更多组合可以在这里(https://docs.docker.com/engine/reference/run/#example-run-htop-inside-a-container)找到。

3.提供更多内存是否靠谱?

不了解问题的开发者往往认为环境不能为执行 JVM 提供足够的内存。所以通常的解决办法是提供更多内存,这实际上会使事情变得更糟。

我们假设将 daemon 从1GB 更改为8GB (使用"docker-machinecreate -d virtualbox -virtualbox-memory '8192' docker8192"创建),并将容器内存从150M 更改为800M :

请注意这次, "curl http://`docker-machine ipdocker8192`:8080/api/memory" 命令甚至没有执行完,因为在8GB 环境中计算的 JVM 的MaxHeapSize 为2092957696字节(〜2GB)。检查 "docker logs mycontainer|grep -i MaxHeapSize"

该应用将尝试分配超过1.6GB 的内存,这超出了此容器的限制(RAM 中的800MB + Swap中的800MB),并且该进程将被杀掉。

很显然,用增加内存且让 JVM 自定义参数的方式在容器里跑Java,不是什么好主意。 在容器内部运行 Java 应用程序时,我们应该根据应用程序需求和容器限制设置最大堆大小(-Xmx参数)。

4.解决方案

Dockerfile 的一个细微变化允许用户指定一个环境变量来定义 JVM 的额外参数。 检查以下行:

现在我们可以使用 JAVA_OPTIONS 环境变量来通知 JVM 堆的大小。对于这个应用程序,300M 就够了。稍后可以检查日志并获取314572800字节(300MBi)的值

对于docker,您可以使用"-e"switch指定环境变量。

在Kubernetes中,您可以使用switch "-env = [key = value]"设置环境变量:

再进一步

如果可以根据容器限制自动计算堆的值,该怎么做?

使用由Fabric8社区提供的基础Docker镜像,就可以搞定。这个镜像 fabric8 / java-jboss-openjdk8-jdk 使用一个脚本来计算容器限制,并使用50%的可用内存作为上限。 请注意,这个50%的内存比可以被复写。 您还可以使用此镜像来启用/禁用调试,诊断等。

下面一起看看 Dockerfile 是如何作用于这个 Spring Boot 应用程序:

搞定!现在,无论容器内存限制是多少,我们的 Java 应用程序将始终根据容器调整堆大小,而不是根据 daemon 调整堆大小。

"如何在Docker里跑Java"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

内存 容器 限制 应用 参数 进程 大小 应用程序 环境 程序 命令 变量 更多 检查 调整 资源 镜像 分配 内容 大堆 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 湖北九亚互联网络科技有限公司 北京互联网科技有限公司 奇酷互联网科技 融势互联网科技 互联网科技股午盘股票涨跌 北京三清互联网科技 广州优美互联网科技 字节跳动和互联网科技 重庆威客帮互联网科技 宁夏众和广鑫互联网科技有限公司 厦门比较好的科技互联网公司 青岛科技大学互联网大赛研究生 河南住房之家互联网科技 伍佰万互联网科技怎么赚钱 云南省自由互联网科技有限公司 本届互联网大会上的黑科技 下一代互联网重大应用科技园 西安左小互联网科技有限公司 科技互联网经济论坛 互联网科技创业计划的风险分析 互联网科技垄断 紫鲸互联网科技 互联网科技的英文 伴你行互联网科技有限公司 互联网之后的科技是什么 互联网经济与金融科技 上海京穆互联网科技有限公司 萌小萌互联网科技河南有限公司 普陀区互联网教育科技管理办法 北京瑞云互联网科技有限公司
0