许多人正在使用容器包装他们的Spring Boot应用程序,而构建容器并不是一件容易的事。这是针对Spring Boot应用程序开发人员的指南,容器对于开发人员而言并不总是一个很好的抽象-它们迫使您学习和思考非常低级的问题-但是有时您会被要求创建或使用容器,因此有必要了解这些基本要素。在这里,我们旨在向您展示一些您需要创建自己的容器时可以做出的选择。

我们将假定您知道如何创建和构建基本的Spring Boot应用程序。如果你不这样做,去到一个入门指南 ,例如关于构建一个REST服务 。从此处复制代码,并使用以下一些想法进行练习。

Docker上也有一个入门指南,这也是一个很好的起点,但是它没有涵盖我们在此所做的选择范围,也没有详细介绍。

基本的Dockerfile

Spring Boot应用程序很容易转换为可执行的JAR文件。所有入门指南都这样做,从Spring Initializr下载的每个应用程序都将具有一个构建步骤来创建可执行的JAR。使用Maven可以./mvnw install ,使用Gradle可以./mvnw install ./gradlew build 。然后,在项目的顶层,运行该JAR的基本Dockerfile如下所示:

Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

所述JAR_FILE可以在作为的一部分被传递docker命令(这将是Maven和摇篮不同)。例如Maven:

$ docker build --build-arg=target/*.jar -t myorg/myapp .

对于Gradle:

$ docker build --build-arg=build/libs/*.jar -t myorg/myapp .

当然,一旦选择了构建系统,就不需要ARG您只需对jar位置进行硬编码即可。例如Maven:

Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

然后我们可以简单地用

$ docker build -t myorg/myapp .

并像这样运行它:

$ docker run -p 8080:8080 myorg/myapp
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.2.RELEASE)

Nov 06, 2018 2:45:16 PM org.springframework.boot.StartupInfoLogger logStarting
INFO: Starting Application v0.1.0 on b8469cdc9b87 with PID 1 (/app.jar started by root in /)
Nov 06, 2018 2:45:16 PM org.springframework.boot.SpringApplication logStartupProfileInfo
...

如果要在图像内部四处浏览,可以像这样打开其中的外壳(基本图像没有bash ):

$ docker run -ti --entrypoint /bin/sh myorg/myapp
/ # ls
app.jar  dev      home     media    proc     run      srv      tmp      var
bin      etc      lib      mnt      root     sbin     sys      usr
/ #

到目前为止,docker配置非常简单,并且生成的映像不是很有效。docker映像只有一个文件系统层,其中包含胖子罐,我们对应用程序代码进行的每一次更改都会更改该层,该层可能为10MB或更多(对于某些应用程序甚至可能为50MB)。我们可以通过将JAR分为多个层来改善这一点。

较小的图像

请注意,上面示例中的基本映像是openjdk:8-jdk-alpinealpine映像比Dockerhub的标准openjdk库映像 。尚无Java 11的正式高山图像(AdoptOpenJDK已有一段时间,但不再出现在其Dockerhub页面上 )。您还可以使用“ jre”标签而不是“ jdk”在基本映像中节省大约20MB。并非所有的应用程序都可以与JRE一起使用(而不是JDK),但是大多数的应用程序都可以,并且确实有些组织会强制执行每个应用程序必须遵循的规则,因为存在滥用某些JDK功能(例如编译)的风险。

可以使您缩小图像的另一个技巧是使用JLink ,它与OpenJDK 11捆绑在一起。JLink允许您从完整JDK中的模块子集构建自定义JRE分发,因此在基本映像中不需要JRE或JDK。原则上,与使用openjdk官方docker映像相比,这将使您具有较小的总映像大小。实际上,您还不能(在)JDK 11上使用alpine基础图像,因此您对基础图像的选择将受到限制,并且最终结果可能会更大。另外,您自己的基本映像中的自定义JRE无法在其他应用程序之间共享,因为它们将需要不同的自定义。因此,对于您所有的应用程序来说,它们的映像可能都较小,但是它们的启动时间仍然较长,因为它们无法从缓存JRE层中受益。

最后一点突出了图像构建者的一个真正重要的担忧:目标不一定总是要构建尽可能小的图像。较小的图像通常是一个好主意,因为它们只需要花费较少的时间就可以上传和下载,但是前提是它们中的所有层都没有被缓存。如今,图像注册表非常复杂,通过尝试巧妙地构建图像,您很容易失去这些功能的优势。如果使用公共基础层,则图像的总大小将不再是问题,随着注册管理机构和平台的发展,图像的总大小可能甚至会减少。话虽如此,尝试和优化我们的应用程序映像中的各层仍然是重要且有用的,但是目标始终应该是将变化最快的东西放置在最高层中,并共享尽可能多的大型低层。其他应用程序尽可能地使用层。

更好的Dockerfile

由于罐子本身的包装方式,Spring Boot胖子罐子自然具有“层”。如果我们先拆包,它将已经分为内部和外部依赖关系。为了在Docker构建中一步一步做到这一点,我们需要首先解压jar。例如(坚持使用Maven,但Gradle版本非常相似):

$ mkdir target/dependency
$ (cd target/dependency; jar -xf ../*.jar)
$ docker build -t myorg/myapp .

与此Dockerfile

Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

现在有3层,所有应用程序资源都位于后面的2层中。如果应用程序依存关系不变,那么第一层(来自BOOT-INF/lib )将不会改变,因此构建会更快,因此只要基础层已经存在,容器在运行时的启动也将更快已缓存。

我们使用了硬编码的主应用程序类hello.Application 。对于您的应用程序,这可能会有所不同。如果需要,可以使用另一个ARG对其进行参数化。您还可以将Spring Boot胖子JarLauncher复制到映像中,然后使用它来运行应用程序-它可以工作,并且您不需要指定主类,但是启动时会慢一些。

调整

如果您想尽快启动应用程序(大多数人都这样做),则可以考虑一些调整。这里有一些想法:

  • 使用spring-context-indexer链接到docs )。对于小型应用程序而言,它不会增加太多,但对您有所帮助。

  • 如果负担不起,请不要使用执行器

  • 使用Spring Boot 2.1和Spring 5.1。

  • 使用spring.config.location (命令行参数或System属性等)修复Spring Boot配置文件的位置。

  • 使用spring.jmx.enabled=false关闭JMX-您可能不需要在容器中使用它

  • 使用-noverify运行JVM。还要考虑-XX:TieredStopAtLevel=1 (这将在以后降低JIT速度,但会节省启动时间)。

  • 使用Java 8的容器内存提示: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 。对于Java 11,默认情况下是自动的。

您的应用程序在运行时可能不需要完整的CPU,但需要多个CPU才能尽快启动(至少2、4个更好)。如果您不介意启动速度较慢,则可以将CPU速度控制在4以下。如果您被迫从少于4个CPU开始,则可能会有助于设置-Dspring.backgroundpreinitializer.ignore=true因为它会阻止Spring Boot创建可能无法使用的新线程(这适用于Spring Boot 2.1.0及更高版本)。

多阶段构建

上面的Dockerfile假设胖JAR已在命令行上构建。您也可以使用多阶段构建在Docker中执行此步骤,将结果从一个映像复制到另一个映像。使用Maven的示例:

Dockerfile

FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src

RUN ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

第一个图像标记为“ build”,它用于运行Maven并构建胖罐,然后解压缩它。拆包也可以由Maven或Gradle完成(这是《入门指南》中采用的方法)-确实没有太大区别,只是必须编辑构建配置并添加插件。

请注意,源代码已分为4层。后面的层包含构建配置和应用程序的源代码,而前面的层包含构建系统本身(Maven包装器)。这是一个很小的优化,这也意味着我们不必将target目录复制到Docker映像,即使是用于构建的临时目录也是如此。

因为必须在第一个RUN部分中重新创建Maven缓存,所以每个更改源代码的构建都会很慢。但是您拥有一个完全独立的构建,只要拥有docker,任何人都可以运行它来使您的应用程序运行。在某些环境中,例如在需要与不懂Java的人共享代码的环境中,这很有用。

实验功能

Docker 18.06带有一些“实验性”功能 ,其中包括一种缓存构建依赖项的方法。要打开它们,您需要在守护程序中使用一个标志( dockerd ),并且在运行客户端时还需要一个环境变量,然后可以在Dockerfile添加第一行魔术:

Dockerfile

# syntax=docker/dockerfile:experimental

然后RUN指令接受一个新的标志--mount 。这是一个完整的示例:

Dockerfile

# syntax=docker/dockerfile:experimental
FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src

RUN --mount=type=cache,target=/root/.m2 ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

然后运行它:

$ DOCKER_BUILDKIT=1 docker build -t myorg/myapp .
...
 => /bin/sh -c ./mvnw install -DskipTests              5.7s
 => exporting to image                                 0.0s
 => => exporting layers                                0.0s
 => => writing image sha256:3defa...
 => => naming to docker.io/myorg/myapp

使用实验性功能,您可以在控制台上获得不同的输出,但是可以看到,一旦缓存变热,Maven构建现在只需要几秒钟而不是几分钟。

虽然这些功能在实验阶段,接通buildkit和关闭选项取决于版本docker所使用。检查你有版本的文档(上面的例子是正确的docker 18.0.6)。

安全方面

就像在传统的VM部署中一样,不应使用root权限运行进程。相反,映像应包含运行该应用程序的非root用户。

Dockerfile ,这可以通过添加另一层来添加(系统)用户和组,然后将其设置为当前用户(而不是默认用户root)来实现:

Dockerfile

FROM openjdk:8-jdk-alpine

RUN addgroup -S demo && adduser -S demo -G demo
USER demo

...

如果有人设法突破您的应用程序并在容器内运行系统命令,这将限制他们的功能(最小特权原则)。

一些其他的Dockerfile命令仅以root身份运行,因此也许您必须将USER命令进一步向下移动(例如,如果您计划将更多软件包安装到仅以root身份运行的容器中)。
不使用Dockerfile其他方法可能更合适。例如,在稍后描述的buildpack方法中,大多数实现默认情况下将使用非root用户。

构建插件

如果您不想直接在构建中调用docker ,则可以使用Maven和Gradle丰富的插件集来为您工作。这里仅仅是少数。

Spotify Maven插件

Spotify Maven插件是一个受欢迎的选择。它需要应用程序开发人员编写Dockerfile ,然后运行docker为你,就好像你在做它的命令行上。docker image标签和其他内容有一些配置选项,但它使应用程序中的Dockerfile知识集中在Dockerfile ,这是许多人喜欢的。

对于真正的基本用法,它无需额外配置即可直接使用:

$ mvn com.spotify:dockerfile-maven-plugin:build
...
[INFO] Building Docker context /home/dsyer/dev/demo/workspace/myapp
[INFO]
[INFO] Image will be built without a name
[INFO]
...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.630 s
[INFO] Finished at: 2018-11-06T16:03:16+00:00
[INFO] Final Memory: 26M/595M
[INFO] ------------------------------------------------------------------------

这将构建一个匿名docker镜像。我们现在可以在命令行上使用docker对其进行标记,或者使用Maven配置将其设置为repository 。示例(不更改pom.xml ):

$ mvn com.spotify:dockerfile-maven-plugin:build -Ddockerfile.repository=myorg/myapp

或在pom.xml

pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>dockerfile-maven-plugin</artifactId>
            <version>1.4.8</version>
            <configuration>
                <repository>myorg/${project.artifactId}</repository>
            </configuration>
        </plugin>
    </plugins>
</build>

Palantir Gradle插件

真知晶球摇篮插件工作与Dockerfile ,它也能产生Dockerfile你,然后它运行docker ,如果你是在命令行中运行它。

首先,您需要将插件导入到build.gradle

build.gradle

buildscript {
    ...
    dependencies {
        ...
        classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0')
    }
}

然后最后应用插件并调用其任务:

build.gradle

apply plugin: 'com.palantir.docker'

group = 'myorg'

bootJar {
    baseName = 'myapp'
    version =  '0.1.0'
}

task unpack(type: Copy) {
    dependsOn bootJar
    from(zipTree(tasks.bootJar.outputs.files.singleFile))
    into("build/dependency")
}
docker {
    name "${project.group}/${bootJar.baseName}"
    copySpec.from(tasks.unpack.outputs).into("dependency")
    buildArgs(['DEPENDENCY': "dependency"])
}

在此示例中,我们选择在build目录中的特定位置解压缩Spring Boot胖子罐,该目录是docker构建的根目录。然后,上面的多层(不是多阶段) Dockerfile将起作用。

Jib Maven和Gradle插件

Google有一个名为Jib的开源工具,它相对较新,但出于多种原因却很有趣。可能最有趣的事情是您不需要docker来运行它-它使用与从docker build获得的相同的标准输出来构建映像,但是除非您要求,否则不使用docker因此它可以在以下环境中工作没有安装docker(在构建服务器中并不罕见)。您也不需要Dockerfile (无论如何都会被忽略)或pom.xml任何内容来获取在Maven中构建的映像(Gradle要求您至少将插件安装在build.gradle )。

Jib的另一个有趣的功能是,它对层有Dockerfile ,并且以与上面创建的多层Dockerfile稍有不同的方式优化了它们。就像在胖子罐中一样,Jib将本地应用程序资源与依赖项分离开来,但它走得更远,而且还将快照依赖项放入一个单独的层中,因为它们更容易发生变化。有一些配置选项可用于进一步自定义布局。

Maven的示例(不更改pom.xml ):

$ mvn com.google.cloud.tools:jib-maven-plugin:build -Dimage=myorg/myapp

要运行上述命令,您将需要具有在myorg存储库前缀下推送到Dockerhub的权限。如果您有认证docker在命令行上,将从您的本地工作~/.docker配置。您也可以在~/.m2/settings.xml Maven“服务器”身份验证(存储库的id很重要):

settings.xml

    <server>
      <id>registry.hub.docker.com</id>
      <username>myorg</username>
      <password>...</password>
    </server>

还有其他的选择,比如,你可以对一个码头工人守护本地构建(就像跑docker在命令行),使用dockerBuild目标,而不是build 。还支持其他容器注册表,对于每个容器注册表,您将需要通过docker或Maven设置来设置本地身份验证。

该插件的Gradle也有类似的功能,一旦你拥有了它在你build.gradle ,如

build.gradle

plugins {
  ...
  id 'com.google.cloud.tools.jib' version '0.9.11'
}

或使用入门指南中使用的较旧样式:

build.gradle

buildscript {
    repositories {
      maven {
        url "https://plugins.gradle.org/m2/"
      }
      mavenCentral()
    }
    dependencies {
        classpath('org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE')
        classpath('com.google.cloud.tools.jib:com.google.cloud.tools.jib.gradle.plugin:0.9.11')
    }
}

然后您可以用

$ ./gradlew jib --image=myorg/myapp

由于与Maven构建,如果已经使用认证docker在命令行上,图像推将从本地认证~/.docker配置。

持续集成

如今(或应该如此),自动化已成为每个应用程序生命周期的一部分。人们用来实现自动化的工具往往非常擅长从源代码调用构建系统。因此,如果您得到一个docker映像,并且构建代理中的环境与开发人员自己的环境充分对齐,则可能就足够了。向Docker注册表进行身份验证可能是最大的挑战,但是所有自动化工具中都有一些功能可以帮助实现这一点。

但是,有时最好将容器创建完全留给自动化层,在这种情况下,可能不需要污染用户的代码。容器创建非常棘手,开发人员有时并不真正在意它。如果用户代码更干净,则其他工具更有可能“做正确的事”,应用安全修复程序,优化缓存等。有多种自动化选项,并且这些天它们都具有与容器相关的某些功能。我们只看几个。

大堂

Concourse是基于管道的自动化平台,可用于CI和CD。它在Pivotal内部大量使用,该项目的主要作者在那里工作。除CLI外,Concourse中的所有内容都是无状态的,并且所有内容都在容器中运行。由于运行容器是自动化管道的主要业务顺序,因此很好地支持创建容器。如果它是容器映像,则Docker Image Resource负责使构建的输出状态保持最新。

这是一个示例管道,为上面的示例构建一个docker映像,假设它位于myorg/myapp github中,并且在根目录下有一个Dockerfile ,并且在src/main/ci/build.yml具有一个构建任务声明:

resources:
- name: myapp
  type: git
  source:
    uri: https://github.com/myorg/myapp.git
- name: myapp-image
  type: docker-image
  source:
    email: {{docker-hub-email}}
    username: {{docker-hub-username}}
    password: {{docker-hub-password}}
    repository: myorg/myapp

jobs:
- name: main
  plan:
  - task: build
    file: myapp/src/main/ci/build.yml
  - put: myapp-image
    params:
      build: myapp

管道的结构非常具有声明性:您定义“资源”(输入或输出或两者),以及“作业”(使用并向资源应用操作)。如果任何输入资源发生更改,则会触发新的构建。如果作业期间任何输出资源发生更改,则将对其进行更新。

可以在与应用程序源代码不同的位置定义管道。对于通用构建设置,任务声明也可以集中或外部化。如果这是滚动的方式,则可以将开发和自动化之间的关注点分离开。

詹金斯

Jenkins是另一种流行的自动化服务器。它具有广泛的功能,但此处最接近其他自动化示例的功能是管道功能。这是一个Jenkinsfile ,它使用Maven构建Spring Boot项目,然后使用Dockerfile构建映像并将其推送到存储库:

Jenkinsfile

node {
    checkout scm
    sh './mvnw -B -DskipTests clean package'
    docker.build("myorg/myapp").push()
}

对于需要在构建服务器验证的(现实的)泊坞窗库,你可以添加凭据docker使用上述目的docker.withCredentials(…​)

构建包

Cloud Foundry多年来一直在内部使用容器,用于将用户代码转换为容器的技术的一部分是Build Packs,该思想最初是从Heroku借来的。当前的buildpacks(v2)生成通用二进制输出,该输出由平台组装到容器中。新一代的buildpack (v3)是Heroku与其他公司(包括Pivotal)之间的合作,可以直接且显式地构建容器映像。这对于开发人员和运营商来说非常有趣。开发人员不需要太在乎如何构建容器的细节,但是如果需要,他们可以轻松地创建一个容器。Buildpacks还具有许多用于缓存生成结果和依赖项的功能,因此,Buildpack的运行速度要比本地Docker构建快得多。操作员可以扫描容器以审核其内容并进行转换以修补它们以进行安全更新。您可以在本地(例如,在开发人员机器上或在CI服务中)或在Cloud Foundry之类的平台上运行构建包。

buildpack生命周期的输出是一个容器映像,但是您不需要DockerfileDockerfile ,因此它是CI和自动化友好的。输出映像中的文件系统层由buildpack控制,通常,将进行许多优化而无需开发人员知道或关心它们。在较低层(如包含操作系统的基础映像)与较高层(如包含中间件和特定于语言的依赖关系)之间还有一个应用程序二进制接口 。如果存在安全更新,则Cloud Foundry这样的平台可以修补较低的层,而不会影响应用程序的完整性和功能。

为了让您了解buildpack的功能,这里是一个从命令行使用Pack CLI的示例(它将与我们在本指南中使用的示例应用程序一起使用,不需要Dockerfile或任何特殊的构建配置) :

$ pack build myorg/myapp --builder=cloudfoundry/cnb:bionic --path=.
2018/11/07 09:54:48 Pulling builder image 'cloudfoundry/cnb:bionic' (use --no-pull flag to skip this step)
2018/11/07 09:54:49 Selected run image 'packs/run' from stack 'io.buildpacks.stacks.bionic'
2018/11/07 09:54:49 Pulling run image 'packs/run' (use --no-pull flag to skip this step)
*** DETECTING:
2018/11/07 09:54:52 Group: Cloud Foundry OpenJDK Buildpack: pass | Cloud Foundry Build System Buildpack: pass | Cloud Foundry JVM Application Buildpack: pass
*** ANALYZING: Reading information from previous image for possible re-use
*** BUILDING:
-----> Cloud Foundry OpenJDK Buildpack 1.0.0-BUILD-SNAPSHOT
-----> OpenJDK JDK 1.8.192: Reusing cached dependency
-----> OpenJDK JRE 1.8.192: Reusing cached launch layer

-----> Cloud Foundry Build System Buildpack 1.0.0-BUILD-SNAPSHOT
-----> Using Maven wrapper
       Linking Maven Cache to /home/pack/.m2
-----> Building application
       Running /workspace/app/mvnw -Dmaven.test.skip=true package
...
---> Running in e6c4a94240c2
---> 4f3a96a4f38c
---> 4f3a96a4f38c
Successfully built 4f3a96a4f38c
Successfully tagged myorg/myapp:latest
$ docker run -p 8080:8080 myorg/myapp
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.5.RELEASE)

2018-11-07 09:41:06.390  INFO 1 --- [main] hello.Application: Starting Application on 1989fb9a00a4 with PID 1 (/workspace/app/BOOT-INF/classes started by pack in /workspace/app)
...

--builder是运行buildpack生命周期的--builder映像-通常,它将是所有开发人员或单个平台上所有开发人员的共享资源。您可以在命令行上设置默认构建器(在~/.pack创建一个文件),然后从后续构建中省略该标志。

cloudfoundry/cnb:bionic器还知道如何从可执行jar文件构建映像,因此您可以先使用mvnw进行构建,然后将--path指向jar文件以得到相同的结果。

基尼特语

容器和平台领域的另一个新项目是Knative 。Knative有很多东西,但是如果您不熟悉Knative,则可以将其视为构建无服务器平台的基础。它基于Kubernetes构建,因此最终它会使用容器映像,并在平台上将它们转换为应用程序或“服务”。但是,它的主要功能之一是能够使用源代码并为您构建容器,从而使其对开发人员和操作员更友好。Knative Build是执行此操作的组件,它本身就是一个将用户代码转换为容器的灵活平台-您几乎可以按照自己喜欢的任何方式进行操作。一些模板提供了常见的模式,例如Maven和Gradle构建,以及使用Kaniko的多阶段docker构建。还有一个使用Buildpacks的模板,这对我们来说很有趣,因为buildpacks一直对Spring Boot具有良好的支持。用户还可以使用RiffPivotal Function Service在Knative上进行构建包选择,以将用户功能转换为运行的无服务器应用程序。

闭幕

本指南提供了许多用于为Spring Boot应用程序构建容器映像的选项。所有这些都是完全有效的选择,现在由您决定需要哪一个。您的第一个问题应该是“我真的需要构建容器映像吗?如果答案是“是”,那么您的选择可能会受到效率和可缓存性以及关注点分离的影响。您是否希望使开发人员不必过多地了解如何创建容器映像?当需要修补操作系统和中间件漏洞时,是否要让开发人员负责更新映像?也许开发人员需要对整个过程进行完全控制,并且他们拥有所需的所有工具和知识。