天天看點

「Spring」Boot Docker 認證指南(下)

建構插件

如果你不想docker在你的建構中直接調用,有一套豐富的 Maven 和 Gradle 插件可以為你完成這項工作。這裡僅僅是少數。

Spring Boot Maven 和 Gradle 插件

您可以使用Maven和Gradle的 Spring Boot 建構插件來建立容器映像。docker build這些插件使用Cloud Native Buildpacks建立一個 OCI 映像(與建立的格式相同) 。您不需要Dockerfile,但您确實需要 Docker 守護程式,可以在本地(使用 docker 建構時使用)或通過DOCKER_HOST環境變量遠端進行。預設建構器針對 Spring Boot 應用程式進行了優化,并且圖像像上面的示例一樣有效地分層。

以下示例在不更改pom.xml檔案的情況下使用 Maven:

./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=myorg/myapp複制      

以下示例适用于 Gradle,無需更改build.gradle檔案:

./gradlew bootBuildImage --imageName=myorg/myapp複制      

第一次建構可能需要很長時間,因為它必須下載下傳一些容器鏡像和 JDK,但後續建構應該很快。

然後您可以運作映像,如以下清單所示(帶輸出):

docker run -p 8080:8080 -t myorg/myapp
Setting Active Processor Count to 6
Calculating JVM memory based on 14673596K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx14278122K -XX:MaxMetaspaceSize=88273K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 14673596K, Thread Count: 50, Loaded Class Count: 13171, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=6 -XX:MaxDirectMemorySize=10M -Xmx14278122K -XX:MaxMetaspaceSize=88273K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true
....
2015-03-31 13:25:48.035  INFO 1 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-03-31 13:25:48.037  INFO 1 --- [           main] hello.Application複制      

您可以看到應用程式正常啟動。您可能還注意到 JVM 記憶體需求是在容器内計算并設定為指令行選項的。這與多年來在 Cloud Foundry 建構包中使用的記憶體計算相同。它代表了對一系列 JVM 應用程式(包括但不限于 Spring Boot 應用程式)的最佳選擇的重要研究,結果通常比 JVM 的預設設定好得多。您可以自定義指令行選項并通過設定環境變量覆寫記憶體電腦,如Paketo buildpacks 文檔中所示。

Spotify Maven 插件

Spotify Maven 插件是一個受歡迎的選擇。它要求您編寫 aDockerfile然後docker為您運作,就像您在指令行上執行它一樣。docker 鏡像标簽和其他東西有一些配置選項,但它使您的應用程式中的 docker 知識集中在一個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 插件

Palantir Gradle 插件與 a 一起使用,Dockerfile并且還可Dockerfile以為您生成 a。然後它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"])
}複制      

在本例中,我們選擇将 Spring Boot fat JAR 解壓到build目錄中的特定位置,該位置是 docker build 的根目錄。Dockerfile然後早期顯示的多層(不是多階段)起作用。

Jib Maven 和 Gradle 插件

Google 有一個名為Jib的開源工具,它相對較新,但出于多種原因非常有趣。可能最有趣的是您不需要 docker 來運作它。Jib 使用與您獲得的相同标準輸出來建構映像,docker build但除非您要求它,否則它不會使用docker,是以它可以在未安裝 docker 的環境中工作(在建構伺服器中很常見)。您也不需要Dockerfile(無論如何都會被忽略)或任何東西pom.xml來獲得在 Maven 中建構的圖像(Gradle 将要求您至少在 中安裝插件build.gradle)。

DockerfileJib 的另一個有趣的特性是它對層有意見,并且它以與上面建立的多層略有不同的方式優化它們。與胖 JAR 中一樣,Jib 将本地應用程式資源與依賴項分開,但它更進一步,還将快照依賴項放入單獨的層,因為它們更有可能發生變化。有用于進一步自定義布局的配置選項。

以下示例在不更改 Maven 的情況下使用pom.xml:

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

myorg要運作該指令,您需要具有在存儲庫字首下推送到 Dockerhub 的權限。如果您已docker在指令行上進行了身份驗證,則可以在本地~/.docker配置中使用。~/.m2/settings.xml您還可以在您的(id存儲庫的重要)中設定 Maven“伺服器”身份驗證:

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 '1.8.0'
}複制      

以下清單使用入門指南中使用的舊 Gradle 樣式:

build.gradle

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

然後,您可以通過運作以下指令來建構映像:

./gradlew jib --image=myorg/myapp複制      

與 Maven 建構一樣,如果您已docker在指令行上進行了身份驗證,則圖像推送将從您的本地~/.docker配置進行身份驗證。

持續內建

如今,自動化(或應該是)是每個應用程式生命周期的一部分。人們用來進行自動化的工具往往非常擅長從源代碼調用建構系統。是以,如果這為您提供了一個 docker 映像,并且建構代理中的環境與開發人員自己的環境充分一緻,那可能就足夠了。對 docker 系統資料庫進行身份驗證可能是最大的挑戰,但所有自動化工具中都有一些功能可以幫助解決這個問題。

但是,有時最好将容器建立完全留給自動化層,在這種情況下,可能不需要污染使用者的代碼。容器建立很棘手,開發人員有時不需要真正關心它。如果使用者代碼更幹淨,則不同的工具更有可能“做正确的事”(應用安全修複、優化緩存等)。自動化有多種選擇,如今它們都帶有一些與容器相關的功能。我們将看一對夫婦。

大廳

Concourse是一個基于管道的自動化平台,可用于 CI 和 CD。它在 VMware 内部使用,該項目的主要作者在那裡工作。Concourse 中的所有内容都是無狀态的,并且在容器中運作,CLI 除外。由于運作容器是自動化管道的主要業務順序,是以很好地支援建立容器。Docker Image Resource負責保持建構的輸出狀态是最新的,如果它是一個容器鏡像的話。

以下示例管道為前面顯示的示例建構了一個 docker 映像,假設它位于 github 中myorg/myapp,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 項目,然後使用 aDockerfile建構一個鏡像并将其推送到存儲庫:

Jenkinsfile

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

對于需要在建構伺服器中進行身份驗證的(實際)docker 存儲庫,您可以docker使用docker.withCredentials(…​).

建構包

packSpring Boot Maven 和 Gradle 插件使用建構包的方式與CLI 在以下示例中的使用方式完全相同。給定相同的輸入,生成的圖像是相同的。

Cloud Foundry在内部使用容器已經很多年了,用于将使用者代碼轉換為容器的部分技術是 Build Packs,這個想法最初是從Heroku借來的。目前一代的 buildpacks (v2) 生成由平台組裝到容器中的通用二進制輸出。新一代建構包(v3) 是 Heroku 與其他公司(包括 VMware)的合作,它直接明确地建構容器鏡像。這對開發人員和營運商來說很有趣。開發人員不需要太關心如何建構容器的細節,但如果需要,他們可以輕松建立一個。Buildpacks 還具有許多用于緩存建構結果和依賴項的功能。通常,建構包的運作速度比原生 Docker 建構快得多。操作員可以掃描容器以稽核其内容并将其轉換為修補它們以進行安全更新。此外,您可以在本地(例如,在開發人員機器或 CI 服務中)或在 Cloud Foundry 等平台中運作建構包。

buildpack 生命周期的輸出是容器映像,但您不需要Dockerfile. 輸出映像中的檔案系統層由 buildpack 控制。通常,許多優化都是在開發人員不必知道或關心它們的情況下進行的。在較低層(例如包含作業系統的基礎映像)和較高層(包含中間件和語言特定依賴項)之間還有一個應用程式二進制接口。這使得 Cloud Foundry 等平台可以在有安全更新的情況下修補較低層,而不會影響應用程式的完整性和功能。

為了讓您了解 buildpack 的功能,以下示例(顯示其輸出)從指令行使用Pack CLI(它可以與我們在本指南中使用的示例應用程式一起使用 - 不需要Dockerfile或任何特殊的建構配置):

pack build myorg/myapp --builder=paketobuildpacks/builder:base --path=.
base: Pulling from paketobuildpacks/builder
Digest: sha256:4fae5e2abab118ca9a37bf94ab42aa17fef7c306296b0364f5a0e176702ab5cb
Status: Image is up to date for paketobuildpacks/builder:base
base-cnb: Pulling from paketobuildpacks/run
Digest: sha256:a285e73bc3697bc58c228b22938bc81e9b11700e087fd9d44da5f42f14861812
Status: Image is up to date for paketobuildpacks/run:base-cnb
===> DETECTING
7 of 18 buildpacks participating
paketo-buildpacks/ca-certificates   2.3.2
paketo-buildpacks/bellsoft-liberica 8.2.0
paketo-buildpacks/maven             5.3.2
paketo-buildpacks/executable-jar    5.1.2
paketo-buildpacks/apache-tomcat     5.6.1
paketo-buildpacks/dist-zip          4.1.2
paketo-buildpacks/spring-boot       4.4.2
===> ANALYZING
Previous image with name "myorg/myapp" not found
===> RESTORING
===> BUILDING

Paketo CA Certificates Buildpack 2.3.2
  https://github.com/paketo-buildpacks/ca-certificates
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_ca-certificates/helper/exec.d/ca-certificates-helper

Paketo BellSoft Liberica Buildpack 8.2.0
  https://github.com/paketo-buildpacks/bellsoft-liberica
  Build Configuration:
    $BP_JVM_VERSION              11              the Java version
  Launch Configuration:
    $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation
    $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation
    $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation
    $JAVA_TOOL_OPTIONS                           the JVM launch flags
  BellSoft Liberica JDK 11.0.12: Contributing to layer
    Downloading from https://github.com/bell-sw/Liberica/releases/download/11.0.12+7/bellsoft-jdk11.0.12+7-linux-amd64.tar.gz
    Verifying checksum
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jdk
    Adding 129 container CA certificates to JVM truststore
    Writing env.build/JAVA_HOME.override
    Writing env.build/JDK_HOME.override
  BellSoft Liberica JRE 11.0.12: Contributing to layer
    Downloading from https://github.com/bell-sw/Liberica/releases/download/11.0.12+7/bellsoft-jre11.0.12+7-linux-amd64.tar.gz
    Verifying checksum
    Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
    Adding 129 container CA certificates to JVM truststore
    Writing env.launch/BPI_APPLICATION_PATH.default
    Writing env.launch/BPI_JVM_CACERTS.default
    Writing env.launch/BPI_JVM_CLASS_COUNT.default
    Writing env.launch/BPI_JVM_SECURITY_PROVIDERS.default
    Writing env.launch/JAVA_HOME.default
    Writing env.launch/MALLOC_ARENA_MAX.default
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/active-processor-count
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/java-opts
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/link-local-dns
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/openssl-certificate-loader
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/security-providers-configurer
    Creating /layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/security-providers-classpath-9
  JVMKill Agent 1.16.0: Contributing to layer
    Downloading from https://github.com/cloudfoundry/jvmkill/releases/download/v1.16.0.RELEASE/jvmkill-1.16.0-RELEASE.so
    Verifying checksum
    Copying to /layers/paketo-buildpacks_bellsoft-liberica/jvmkill
    Writing env.launch/JAVA_TOOL_OPTIONS.append
    Writing env.launch/JAVA_TOOL_OPTIONS.delim
  Java Security Properties: Contributing to layer
    Writing env.launch/JAVA_SECURITY_PROPERTIES.default
    Writing env.launch/JAVA_TOOL_OPTIONS.append
    Writing env.launch/JAVA_TOOL_OPTIONS.delim

Paketo Maven Buildpack 5.3.2
  https://github.com/paketo-buildpacks/maven
  Build Configuration:
    $BP_MAVEN_BUILD_ARGUMENTS  -Dmaven.test.skip=true package  the arguments to pass to Maven
    $BP_MAVEN_BUILT_ARTIFACT   target/*.[jw]ar                 the built application artifact explicitly.  Supersedes $BP_MAVEN_BUILT_MODULE
    $BP_MAVEN_BUILT_MODULE                                     the module to find application artifact in
    Creating cache directory /home/cnb/.m2
  Compiled Application: Contributing to layer
    Executing mvnw --batch-mode -Dmaven.test.skip=true package

[ ... Maven build output ... ]

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  53.474 s
[INFO] Finished at: 2021-07-23T20:10:28Z
[INFO] ------------------------------------------------------------------------
  Removing source code

Paketo Executable JAR Buildpack 5.1.2
  https://github.com/paketo-buildpacks/executable-jar
  Class Path: Contributing to layer
    Writing env/CLASSPATH.delim
    Writing env/CLASSPATH.prepend
  Process types:
    executable-jar: java org.springframework.boot.loader.JarLauncher (direct)
    task:           java org.springframework.boot.loader.JarLauncher (direct)
    web:            java org.springframework.boot.loader.JarLauncher (direct)

Paketo Spring Boot Buildpack 4.4.2
  https://github.com/paketo-buildpacks/spring-boot
  Creating slices from layers index
    dependencies
    spring-boot-loader
    snapshot-dependencies
    application
  Launch Helper: Contributing to layer
    Creating /layers/paketo-buildpacks_spring-boot/helper/exec.d/spring-cloud-bindings
  Spring Cloud Bindings 1.7.1: Contributing to layer
    Downloading from https://repo.spring.io/release/org/springframework/cloud/spring-cloud-bindings/1.7.1/spring-cloud-bindings-1.7.1.jar
    Verifying checksum
    Copying to /layers/paketo-buildpacks_spring-boot/spring-cloud-bindings
  Web Application Type: Contributing to layer
    Reactive web application detected
    Writing env.launch/BPL_JVM_THREAD_COUNT.default
  4 application slices
  Image labels:
    org.opencontainers.image.title
    org.opencontainers.image.version
    org.springframework.boot.version
===> EXPORTING
Adding layer 'paketo-buildpacks/ca-certificates:helper'
Adding layer 'paketo-buildpacks/bellsoft-liberica:helper'
Adding layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'
Adding layer 'paketo-buildpacks/bellsoft-liberica:jre'
Adding layer 'paketo-buildpacks/bellsoft-liberica:jvmkill'
Adding layer 'paketo-buildpacks/executable-jar:classpath'
Adding layer 'paketo-buildpacks/spring-boot:helper'
Adding layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'
Adding layer 'paketo-buildpacks/spring-boot:web-application-type'
Adding 5/5 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Adding label 'org.opencontainers.image.title'
Adding label 'org.opencontainers.image.version'
Adding label 'org.springframework.boot.version'
Setting default process type 'web'
Saving myorg/myapp...
*** Images (ed1f92885df0):
      myorg/myapp
Adding cache layer 'paketo-buildpacks/bellsoft-liberica:jdk'
Adding cache layer 'paketo-buildpacks/maven:application'
Adding cache layer 'paketo-buildpacks/maven:cache'
Successfully built image 'myorg/myapp'複制      

這--builder是一個運作 buildpack 生命周期的 Docker 鏡像。通常,它将是所有開發人員或單個平台上的所有開發人員的共享資源。您可以在指令行上設定預設建構器(在 中建立一個檔案~/.pack),然後從後續建構中省略該标志。

建構器

paketobuildpacks/builder:base還知道如何從可執行 JAR 檔案建構映像,是以您可以先使用 Maven 建構,然後将其指向--pathJAR 檔案以獲得相同的結果。

原生

容器和平台領域的另一個新項目是Knative。如果您不熟悉它,可以将其視為建構無伺服器平台的建構塊。它建立在Kubernetes 之上,是以最終它會使用容器鏡像并将它們轉化為平台上的應用程式或“服務”。不過,它的主要功能之一是能夠使用源代碼并為您建構容器,使其對開發人員和操作員更加友好。Knative Build是執行此操作的元件,它本身就是一個靈活的平台,用于将使用者代碼轉換為容器——您幾乎可以以任何您喜歡的方式進行操作。一些模闆提供了通用模式(例如 Maven 和 Gradle 建構)和多階段 docker 建構使用卡尼科。還有一個模闆使用了Buildpacks,這對我們來說很有趣,因為 buildpacks 一直對 Spring Boot 有很好的支援。

結束

本指南提供了許多用于為 Spring Boot 應用程式建構容器映像的選項。所有這些都是完全有效的選擇,現在由您決定您需要哪一個。您的第一個問題應該是“我真的需要建構容器映像嗎?” 如果答案是“是”,那麼您的選擇可能會受到效率、可緩存性和關注點分離的驅動。您是否想讓開發人員無需過多了解容器鏡像的建立方式?當需要修補作業系統和中間件漏洞時,您是否想讓開發人員負責更新映像?或者,開發人員可能需要完全控制整個過程,并且他們擁有所需的所有工具和知識。

#spring認證##java##spring##程式員#

文末備注: