【问题标题】:Container Portability and Java Language [closed]容器可移植性和 Java 语言
【发布时间】:2021-07-17 14:23:59
【问题描述】:

我是 Docker 新手,并且阅读了很多关于它的内容。但是当我从 Java 应用程序的角度来看它时,我不确定它在“打包依赖项”方面做了什么增值,这是他们文档中提到的重要因素之一。

Java 已经是一种可以使用 JVM 层抽象在多个操作系统上运行的语言。构建一次,随处运行并不是新概念。 Docker 容器确实允许我将我的 JRE 版本与我的应用程序代码一起发布。所以我看到了这种好处,但我还有其他好处吗,特别是当我的环境(主机环境)不会改变时。即我将使用 Linux 机器进行部署。

fat jar 文件与使用 maven build 打包所有依赖项一样好。我知道容器确实有助于在 Kubernetes 等平台上部署,但是如果我必须从包装问题上严格判断容器,jar 包还不够吗?我可能仍然需要将其容器化以从运行轻量级进程中受益,而不是在 VM 上运行它们。

JRE 层是否在所有其他容器中被重用?这类似于在我的 VM 机器上安装 JRE。盒子上的所有应用程序都将使用相同的 JRE 版本。除非,我需要为我的应用程序运行不同版本的 JRE,这是极不可能的。

【问题讨论】:

标签: java docker kubernetes


【解决方案1】:

JVM/JRE 不会被重用。您可能会觉得在应用服务器环境中运行会更好。与在 JSSE 上运行相比,Docker 的开销会更高

与此相比,只是运行 Docker 的优势越来越小。
一些优势可能是:

  • 测试
    • 在不同的 JRE 版本上快速测试您的代码
    • 自动测试。使用 dockerfile,您的 CI/CD 管道可以检查代码、编译代码、启动 docker 映像、运行测试并输出 junit 格式的测试报告。
  • 拥有一致的环境(依赖注入(如 JKS、配置等)、操作系统版本、JRE 等)
  • 环境配置。
    • 您不必花时间安装操作系统、JRE 等,这是您选择的源代码控制系统中的配置文件。
    • 这使得灾难恢复更加容易
    • 简化了迁移(部分)

在编排环境 PaaS 中运行的优势,例如仅使用 kubernetes、openshift 或类似的东西(除了基础 docker):

  • 可以进行金丝雀部署
  • 在同一台或多台机器上进行路由、扩展和负载平衡,以优化基于机器的使用(对于某些操作,JRE 性能会滞后于甜蜜点)

【讨论】:

    【解决方案2】:

    一个胖 jar 文件就像一个包装可以捆绑所有 使用 maven 构建的依赖项

    它没有得到的那么好。

    您的应用程序可能有一堆依赖项:Spring、Tomcat 等等。在任何企业应用程序中,最终工件的大小将由 99% 的依赖项和 1% 的代码组成。这些依赖关系可能很少更改,只有当您添加一些功能或决定升级版本时,您的代码更改非常频繁。

    胖 JAR 意味着每次部署、每次推送到 repo 主机(例如 Nexus)时,您都在浪费时间上传或下载每次 99% 相同的内容。这只是一个愚蠢的 zip 文件。

    Docker 是一种更智能的格式。它具有层的概念,因此您可以(并被鼓励)将一层用于依赖​​关系,另一层用于代码。这意味着如果依赖层没有改变,你不必再次部署它,或者在你的部署中再次更新它。

    因此,您可以更快地构建 CI,在您的 repo 主机中需要更少的磁盘空间,并且可以更快地安装。您还可以使用这些层更轻松地验证您的假设,即只有业务代码发生了变化。

    【讨论】:

    • 有道理。你是说如果我有一个 service:1.0 docker 文件然后只是业务逻辑发生了变化,那么在构建图像 service:2.0 时构建时间会减少,但是将新图像上传到 nexus 仍然需要相同的时间是'是吗?和下载一样吗?它只是节省了 docker 构建时间?
    【解决方案3】:

    如果您有一个使用成熟技术的有效部署系统,那么您绝对应该继续使用它,即使有一些更新和更闪亮的东西。 Java 应用服务器空间非常成熟和成熟,如果您有一个纯 JVM 应用程序和一个工作设置,即使现在存在 Docker 容器,保持该设置也没有错。

    如您所见,Docker 映像包含一个 JVM、一个应用程序服务器、库依赖项和应用程序。如果您有多个图像,它们被正确分层,并且这些细节完全匹配,那么它们可以被共享,但也有可能一个图像具有稍微更新的 JVM 补丁版本或基础 Linux 发行版比另一个发行版。一般来说,我会说 Docker 生态系统广泛假设应用程序“仅”使用数十兆字节的磁盘或内存并不是显着的开销。这与经典 Java 生态系统的主要区别在于,经典 Java 生态系统将在单个进程内的单个共享 JVM 上运行多个应用程序。

    # This base image will be shared between derived images; _if_ the
    # version/build matches exactly
    FROM tomcat:10-jdk11
    
    # These libraries will be shared between derived images; _if_ the
    # _exact_ set of files match _exactly_, and Tomcat is also shared
    COPY target/libs/*.jar /usr/local/tomcat/lib
    
    # This jar file presumably won't be shared
    COPY target/myapp.jar /usr/local/tomcat/webapps
    

    如果您还需要将非 JVM 服务合并到您的整个系统中,我会开始研究容器。如果你有一个 Java 组件、一个 Node 组件和一个 Python 组件,并且它们都通过 HTTP 进行通信,那么 Docker 将使它们也都以相同的方式部署,而哪些部分使用哪种语言并不重要。尝试留在 JVM 生态系统中(如果 Java/Kotlin/Groovy/Scala 等 JVM 原生语言不能满足您的需求,则可能使用基于 JVM 的语言实现,如 JRuby 或 Jython)对您描述的方式是有意义的当前设置。

    【讨论】:

    • 谢谢。它在博客中得到推广的方式真的让我觉得额外的优势更少了。当然,在 kubernrtes 中运行可以让我自我修复,减少对 Netflix jar 用于服务发现等的依赖。但如果 Kubernetes 不可用,我不会转向容器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    相关资源
    最近更新 更多