每个Docker映像都应包含一个JDK吗?

时间:2018-10-17 07:10:07

标签: java docker spring-boot microservices

因此,我是Docker的新手。让我解释一下问题的背景。

  1. 我有10到20个Spring Boot微服务应用程序,每个应用程序都在本地计算机上的不同端口上运行。

  2. 但是要迁移到Docker,根据我的经验,每个服务必须位于不同的Docker容器中,以便快速部署或制作副本。

  3. 对于每个Docker容器,我们需要创建一个新的Docker映像。

  4. 每个Docker映像都必须包含一个JRE,Spring Boot应用程序才能运行。最大值约为200 MB。这意味着每个docker映像最大为350 MB。 另一方面,在我的本地PC上,我只有一个200 MB的JRE,每个应用程序仅占用几个MB的空间。

  5. 基于此,我的本地系统上需要600 MB,但所有Docker映像都需要7 GB。

这种方法正确吗?是否应将DockerHub的“ OpenJDK”添加到每个映像?

即使目标PC可能已经拥有JDK,为什么图像的尺寸也很大?

4 个答案:

答案 0 :(得分:26)

您的理解不正确。

Docker映像由层组成;参见下图:

在映像中安装JRE时,假设下一张图片中的校验和为91e54dfb1179,它将真正占用您的磁盘。

但是,如果所有容器都基于同一图像,并且将不同的微服务应用程序添加到瘦R / W层,那么所有容器都将共享91e54dfb1179,因此它不会是n * m关系。

您需要注意所有Java应用程序都尽可能使用相同的基础映像,并在瘦R / W层中添加不同的内容。

Enter image description here

答案 1 :(得分:4)

其他答案很好地涵盖了Docker分层,所以我只想为您添加问题的详细信息

这种方法正确吗?是否应将DockerHub的“ OpenJDK”添加到每个映像?

是的。如果它不在图像中,则它将不在容器中。尽管可以通过重复使用尽可能多的图层来节省磁盘空间。因此,尝试将您的Dockerfile从“可能性最小”更改为“可能性最大”。因此,在构建映像时,看到“使用缓存”的频率越高,效果越好。

即使目标PC可能已经拥有JDK,为什么图像的尺寸也很大?

Docker希望与主机的关系尽可能少。 Docker甚至不想处理主机。它要做的第一件事是创建一个隐藏的VM。Docker映像假定主机提供的唯一内容是空的ram,磁盘和CPU。因此,每个Docker映像还必须包含其自己的OS /内核。 (这就是您最初的FROM所做的,选择要使用的基本OS映像)因此,最终映像大小实际上是OS +工具+应用程序。不过,图像大小有点误导,因为它是所有层的总和,可在图像之间重复使用。

(暗示)每个应用程序/微服务都应该放在自己的容器中吗?

理想上是。通过将您的应用程序转换为隔离的模块,可以更轻松地替换/平衡该模块。

在实践中,也许不(对您来说)。 Spring Boot不是一个轻量级的框架。实际上,它是用于对代码进行模块化的框架(有效地在模块控制系统内部运行模块控制系统)。现在您要托管10-20个?那可能无法在单个服务器上运行。 Docker将强制Spring启动每个应用将其自身加载到内存中;而且对象现在无法在各个模块之间重用,因此这些对象也需要多实例化!而且,如果您只能使用1个生产服务器,则不能选择水平扩展。 (每个Spring Boot您将需要约1GB的HEAP(RAM),根据您的代码库来确定里程数)。对于10-20个应用程序,进行重构以减轻Docker部署的负担可能不可行/在预算内。更不用说,如果您不能在本地运行用于测试的最小设置(RAM不足),开发工作将获得更多的“乐趣”。

Docker不是一把金锤。尝试一下,自己评估优点和缺点,然后确定优点对您和您的团队是否有价值。

答案 2 :(得分:2)

Lagom's answer很不错,但我想补充一点,Docker容器的大小应尽可能地小以简化传输和存储。

因此,有很多基于Alpine Linux分布的容器,这些容器确实很小。尝试使用它们。

此外,请勿将所有可以想象得到的工具添加到您的容器中,例如你通常可以不用wget ...

答案 3 :(得分:0)

基于此,我在本地系统上需要600 MB,但需要7 GB 用于所有Docker映像。

这种方法正确吗?是否应将DockerHub的“ OpenJDK”添加到 每个图像?

是正确的。虽然您可能想知道JRE是否还不够。

即使目标PC可能已经大了,为什么图像的尺寸也很大 有JDK吗?

您将无法比较的事物进行比较本地环境(仅生产机器)与VS 集成/生产环境。

在集成/生产环境中,应用程序的负载可能很高,通常建议在应用程序之间进行隔离。因此,在这里,您希望按机器(裸机,VM或容器)托管最少数量的应用程序(ui /服务),以防止应用程序之间的副作用:共享库不兼容,软件升级的副作用,资源匮乏,应用程序之间的连锁故障。 ..

在本地环境中,应用程序的负载非常低,并且应用程序之间的隔离通常不是一个严重的问题。因此,在这里您可以在本地计算机上托管多个应用程序(ui / services),还可以共享操作系统提供的一些常见库/依赖项。 虽然可以做到,但在本地混合和共享所有内容真的是一个好习惯吗? 我不认为是因为:
1)本地计算机不是垃圾桶:您整天都在工作。越是干净,您的开发效率就越高。例如:在本地托管的应用程序之间,JDK / JRE可能有所不同,该应用程序使用的某些文件夹可能具有相同的位置,数据库版本可能有所不同,应用程序可以具有不同的已安装Java服务器(Tomcat,Netty,Weblogic)和(或)不同。版本...
多亏了容器,这不是问题:所有组件都可以根据您的要求进行安装和删除。

2)环境(从本地到产品)应该尽可能地,以简化整个集成部署链并尽早发现问题,而不仅仅是在生产中。

请注意,要在本地实现该功能,您需要开发人员使用的真实计算机。


所有项目都有成本,但实际上并不昂贵

除了隔离(硬件和软件资源)之外,容器还具有其他优点,例如快速部署/取消部署,可伸缩性和故障转移友好(例如:Kubernetes依赖于容器)。
隔离,牢固性,可伸缩性和鲁棒性是有代价的:不在容器(OS,库,JVM等)之间物理上共享任何资源。

这意味着,即使您在应用程序中使用确切的OS,库,JVM,每个应用程序也必须在其映像中包含它们。
这个很贵吗 ? 并非完全如此:官方映像通常依赖Alpine(轻型Linux操作系统,有局限性,但可以根据需要进行定制),而从成本的角度来看,它代表的是350 MB映像(您所引用的值是真实的值)?
实际上,这确实很便宜。 在集成/生产中,您的所有服务很可能不会托管在同一台计算机上,因此,将容器的350 MB与传统VM用于集成/生产的VM所使用的资源进行比较,其中传统VM包含一个完整的OS,并安装了多个其他程序。您了解容器的资源消耗不是问题。这甚至被认为是超越本地环境的优势。