当前位置: 首页 > 知识库问答 >
问题:

在调用docker-compose build命令时执行Spring buildpacks

怀洛华
2023-03-14

我正在使用Spring Boot 2.3.0.m1引入的Spring buildpacks来创建基于Spring的应用程序的Docker映像。一切进展顺利,我可以通过执行./gradlew bootbuildimageGradle任务为每个应用程序创建docker图像,将docker-compose文件指向创建的图像(例如image:spring-test:lates),最后成功运行所有应用程序(docker-compose up)。

尽管我有一个bash脚本来自动化构建过程,但我希望去掉这个额外的步骤,使Spring buildpacks任务在运行docker-compose up-build命令时自动执行,这样每个应用程序的docker映像将被构建并上传到主机的本地docker存储库中,由docker Compose从那里接管。

我的第一次尝试是为每个在主机上执行bootbuildImage任务的应用程序创建一个虚拟Dockerfile,但这需要从docker到主机的SSH连接,甚至不确定是否能正确工作。

另一个想法是使用类似的方法,唯一的变化是首先挂载或复制应用程序的源代码到docker,配置构建包将图像存储到主机的本地docker图像repo(可能是SSH连接),最后在docker上执行构建包。

我想知道是否没有一个更好,更优雅的解决方案。

共有1个答案

巫马磊
2023-03-14

这个问题真的把我逼疯了,因为我已经玩Spring Boot&Paketo构建包很长一段时间了--我真的很喜欢Docker-Compose的简单性。所以这些问题已经在我的脑海中,但后来你问了它:)

我没有找到100%完美的解决方案,但我想a有一些想法。让我们假设一个包含多个Spring Boot应用程序的示例项目,这些应用程序由Maven多模块设置组成(我知道您使用的是Gradle,但在great Spring.io guides中有一个关于使用Gradle进行多模块设置的指南):github.com/jonashackt/cxf-spring-cloud-netflix-docker。我创建了一个新的分支buildpacks-paketo,包含所有我们需要的内容,并从相应的Spring Boot应用程序中删除了所有dockerfiles。因为我们不应该再使用云原生构建包了(这是他们的设计目标)。

TLDR:我的想法是使用spring-boot-maven-plugin(或者它等价于Gradle)在每个“normaldocker-compose up”之前发出新的Paketo构建,如下所示:

mvn clean spring-boot:build-image && docker-compose up

示例项目父级pom.xml如下所示(缩短):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.jonashackt</groupId>
    <artifactId>cxf-spring-cloud-netflix-docker-build-all</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
    </parent>


    <modules>
        <module>eureka-serviceregistry</module>
        <module>spring-boot-admin</module>
        <module>zuul-edgeservice</module>
        <module>weatherbackend</module>
        <module>weatherservice</module>
        <module>weatherclient</module>
    </modules>

</project>

示例projectsdocker-compose.yml看起来很简单,并使用了由Paketo生成的容器图像(由Maven插件触发)-这些图像的名称如下:eureka-serviceRegistry:0.0.1-snapshot。以下是所有Spring Boot服务的完整docker-compose.yml

version: '3.3'

services:

  eureka-serviceregistry:
    image: eureka-serviceregistry:0.0.1-SNAPSHOT
    ports:
     - "8761:8761"
    tty:
      true
    restart:
      unless-stopped

  spring-boot-admin:
    image: spring-boot-admin:0.0.1-SNAPSHOT
    ports:
     - "8092:8092"
    environment:
      - REGISTRY_HOST=eureka-serviceregistry
    tty:
      true
    restart:
      unless-stopped

  # no portbinding here - the actual services should be accessible through Zuul proxy
  weatherbackend:
    image: weatherbackend:0.0.1-SNAPSHOT
    ports:
     - "8090"
    environment:
      - REGISTRY_HOST=eureka-serviceregistry
    tty:
      true
    restart:
      unless-stopped

  # no portbinding here - the actual services should be accessible through Zuul proxy
  weatherservice:
    image: weatherservice:0.0.1-SNAPSHOT
    ports:
     - "8095"
    environment:
      - REGISTRY_HOST=eureka-serviceregistry
    tty:
      true
    restart:
      unless-stopped

  zuul-edgeservice:
    image: zuul-edgeservice:0.0.1-SNAPSHOT
    ports:
     - "8080:8080"
    environment:
      - REGISTRY_HOST=eureka-serviceregistry
    tty:
      true
    restart:
      unless-stopped

===可能的增强======================

version: '3.3'

services:

  paketo-build:
    image: maven:3.6-openjdk-15
    command: "mvn clean spring-boot:build-image -B -DskipTests --no-transfer-progress" # build all apps
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro" # Mount Docker from host into build container for Paketo to work
      - "$HOME/.m2:/root/.m2" # Mount your local Maven repository into build container to prevent repeated downloads
      - "$PWD:/workspace" # Mount all Spring Boot apps into the build container
    working_dir: "/workspace"

我首先在docker-compose.yml中集成了这个服务。运行docker-compose up paketo-build实现了我所期望的:在Compose设置中构建所有的Spring Boot应用程序:

...
paketo-build_1  | [INFO] --- spring-boot-maven-plugin:2.4.1:build-image (default-cli) @ eureka-serviceregistry ---
paketo-build_1  | [INFO] Building image 'docker.io/library/eureka-serviceregistry:0.0.1-SNAPSHOT'
paketo-build_1  | [INFO]
paketo-build_1  | [INFO]  > Pulling builder image 'docker.io/paketobuildpacks/builder:base' 100%
paketo-build_1  | [INFO]  > Pulled builder image 'paketobuildpacks/builder@sha256:3cff90d13d353ffdb83acb42540dae4ce6c97d55c07fb01c39fe0922177915fa'
paketo-build_1  | [INFO]  > Pulling run image 'docker.io/paketobuildpacks/run:base-cnb' 100%
paketo-build_1  | [INFO]  > Pulled run image 'paketobuildpacks/run@sha256:f393fa2927a2619a10fc09bb109f822d20df909c10fed4ce3c36fad313ea18e3'
paketo-build_1  | [INFO]  > Executing lifecycle version v0.10.1
paketo-build_1  | [INFO]  > Using build cache volume 'pack-cache-9d8694845b92.build'
paketo-build_1  | [INFO]
paketo-build_1  | [INFO]  > Running creator
paketo-build_1  | [INFO]     [creator]     ===> DETECTING
...
paketo-build_1  | [INFO]     [creator]
paketo-build_1  | [INFO]     [creator]     Paketo Spring Boot Buildpack 3.5.0
paketo-build_1  | [INFO]     [creator]       https://github.com/paketo-buildpacks/spring-boot
paketo-build_1  | [INFO]     [creator]       Creating slices from layers index
...
paketo-build_1  | [INFO]     [creator]     Adding label 'io.buildpacks.project.metadata'
paketo-build_1  | [INFO]     [creator]     Adding label 'org.opencontainers.image.title'
paketo-build_1  | [INFO]     [creator]     Adding label 'org.opencontainers.image.version'
paketo-build_1  | [INFO]     [creator]     Adding label 'org.springframework.boot.spring-configuration-metadata.json'
paketo-build_1  | [INFO]     [creator]     Adding label 'org.springframework.boot.version'
paketo-build_1  | [INFO]     [creator]     Setting default process type 'web'
paketo-build_1  | [INFO]     [creator]     *** Images (7efae8be1167):
paketo-build_1  | [INFO]     [creator]           docker.io/library/eureka-serviceregistry:0.0.1-SNAPSHOT
paketo-build_1  | [INFO]
paketo-build_1  | [INFO] Successfully built image 'docker.io/library/eureka-serviceregistry:0.0.1-SNAPSHOT'
...

但由于一系列原因,这感觉不对。其中之一是,您需要以某种方式等待所有其他Compose服务的启动,直到paketo-build服务完成它的工作并构建所有映像。但是正如Docker文档告诉我们的那样,我们将需要与在Compose中做出的设计决策背道而驰,以实现这一目标!我也找到了这个很好的答案,Max解释说,用只用于构建的容器“污染”“生产”docker-compose.yml不是一个好的设计。

在此之后,我将paketo-build服务提取到它自己的Compose文件中,在示例项目中称为build.yml。因此,我们现在可以运行Paketo构建,而不依赖于安装Maven的主机--并且只使用Docker-compose:

docker-compose -f build.yml up && docker-compose up
mvn clean spring-boot:build-image && docker-compose up

希望这对你有帮助。很高兴听到你的反馈!这里还有一个完整的GitHub actions构建,展示了云CI服务器上的所有“魔力”。

现在还没有办法使用docker-compose up-build对所有使用Paketo构建包的Spring Boot应用程序进行新的映像构建。

 类似资料:
  • outputs/exec 插件的运用也非常简单,如下所示,将 logstash 切割成的内容作为参数传递给命令。这样,在每个事件到达该插件的时候,都会触发这个命令的执行。 output { exec { command => "sendsms.pl \"%{message}\" -t %{user}" } } 需要注意的是。这种方式是每次都重新开始执行一次命令并退

  • 我在Docker中执行触摸命令时遇到问题。 'touch'不被识别为内部或外部命令、可操作程序或批处理文件。

  • 假设一个docker容器用'docker run'运行,然后用'docker stop'停止。“docker start”之后会执行“cmd”命令吗?

  • 问题内容: 我想做这样的事情,我可以依次运行多个命令。 问题答案: 想通了,使用 。 例: 多行中的相同示例: 要么:

  • 问题内容: 这是一个通过 shell-form指令运行多个命令的愚蠢示例。我更喜欢使用 exec-form ,但是我不知道如何连接指令。 壳形式: 执行表格: 有人可以提供 exec-form 的等效语法吗? 问题答案: 简短的答案是,您不能将 exec形式的 命令链接在一起。 是Shell的功能,用于将命令链接在一起。实际上,当您在Dockerfile中使用此语法时,实际上是在利用Shell功能

  • 我想做这样的事情,我可以在以下代码中运行多个命令: 我如何执行多个命令? 谢了。