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

标签 spring docker docker-compose buildpack paketo

我正在使用 Spring Boot 2.3.0.M1 引入的 Spring buildpacks用于创建基于 Spring 的应用程序的 Docker 镜像。一切顺利,我可以通过执行 ./gradlew bootBuildImage 为每个应用程序创建 docker 镜像Gradle 任务,将 docker-compose 文件指向创建的图像(例如 image: spring-test:latest ),最后成功运行所有应用程序( docker-compose up )。
即使我有一个 bash 脚本来自动化构建过程,我还是想摆脱这个额外的步骤,让 Spring buildpacks 任务在我运行时自动执行 docker-compose up --build命令,因此每个应用程序的 docker 镜像将被构建并上传到主机的本地 docker 存储库,从那里它将被 docker compose 接管。
我的第一次尝试是为每个执行 bootBuildImage 的应用程序创建一个虚拟 Dockerfile。主机上的任务,但这需要从 docker 到主机的 SSH 连接,甚至不确定是否可以正常工作。
另一个想法是使用类似的方法,唯一的变化是首先将应用程序的源代码挂载或复制到 docker,配置 buildpacks 以将图像存储到主机的本地 docker image repo(可能是 SSH 连接),最后在 docker 上执行 buildpacks。
我想知道是否没有更好,更优雅的解决方案。

最佳答案

这个问题真的把我逼疯了,因为 I've been playing around with Spring Boot & Paketo Buildpacks for quite a while now - 和 我真的很喜欢 Docker-Compose 的简单性 .所以问题已经在我的脑海里了,但后来你问了:)
我没有找到 100% 完美的解决方案,但我认为有一些想法。让我们假设一个由多个 Spring Boot 应用程序组成的示例项目,这些应用程序由 Maven 多模块设置组成(我知道您正在使用 Gradle,但是在出色的 spring.io 指南中有 a guide on doing multi module setups with Gradle):
github.com/jonashackt/cxf-spring-cloud-netflix-docker .我创建了一个新分支 buildpacks-paketo包含我们需要的所有内容 - 并删除了所有 Dockerfiles来自各自的 Spring Boot 应用程序。因为我们不再需要它们了,使用 Cloud Native Buildpacks (这是他们的设计目标)。
TLDR:我的想法是使用 spring-boot-maven-plugin (或等效的 Gradle)在每个“正常 docker-compose up 之前发布一个新的 Paketo 构建,如下所示:

mvn clean spring-boot:build-image && docker-compose up
The example projects parent 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>
example projects docker-compose.yml 看起来很简单,并使用 Paketo 生成的容器镜像(由 Maven 插件触发)——它们的命名如下:eureka-serviceregistry:0.0.1-SNAPSHOT .这是完整的docker-compose.yml对于所有 Spring Boot 服务:
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
=== 可能的改进 ======================
这个想法让我也有“在单个 docker-compose.yml 上,并且只使用你要求的 docker-compose up - 没有额外的命令。因此我创建了另一个“Docker Compose 构建服务”,它应该只构建这样的服务镜像:
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服务做到了并构建所有图像。 BUT as the Docker docs tell us ,我们将需要反对 Compose 中做出的设计决策才能实现这一目标!还有did I find this great answer , Max 解释说 “污染”“生产”不是一个好的设计docker-compose.yml使用仅用于构建的容器。
之后我提取了 paketo-build服务到它自己的 Compose 文件中 - 称为 build.yml inside the example project .有了它,我们现在能够运行 Paketo 构建,而无需依赖主机安装 Maven - 并且仅使用 Docker-Compose:
docker-compose -f build.yml up && docker-compose up
请记住不要使用 -d 与第一个容器分离因为在我们开始我们的 docker-compose.yml 之前必须完成完整的 Paketo 构建。 .使用这种方法,我们也绝对不需要 Dockerfile .但与此同时,我想到了完全不需要单独的构建容器,只需使用 Maven(或 Gradle)up 之前由 && 连接就像 TLDR 中已经描述的那样:
mvn clean spring-boot:build-image && docker-compose up
希望这对您有所帮助。很高兴听到您的反馈! Here's also a full GitHub actions build显示 Cloud CI 服务器上的所有“魔法”。
现在没有办法使用 docker-compose up --build使用 Paketo Buildpacks 触发所有 Spring Boot 应用程序的全新镜像构建。

关于spring - 调用 docker-compose build 命令时执行 Spring buildpacks,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65325129/

相关文章:

java - 连接 Mongo 时出现身份验证错误

java - ajax与Spring

java - 如何检测docker容器是否崩溃

python - 如何在基于 Alpine 镜像的 Docker 化应用程序中启用 WebSocket 连接(WebSocketAddressException : [Errno -3])?

jenkins - Docker:Jenkins 容器无法在 QNAP 设备上访问互联网

docker - Docker撰写-services.vulcain.ports包含无效的类型,应为数字或对象

java - 如何从静态主方法依赖注入(inject)运行时参数

java.lang.IllegalStateException : Cannot load configuration class : com. 项目.config

php - Docker Compose - 部署中的符号链接(symbolic link)

wordpress - WordPress默认docker镜像如何将文件复制到主机系统中?