这个问题真的让我发疯了,因为我玩 Spring Boot 和 Paketo Buildpacks 已经有一段时间了——而且我真的很喜欢 Docker-Compose 的简单性。所以问题已经在我的脑海里了,但后来你问了:)
我没有找到 100% 完美的解决方案,但我认为有一些想法。让我们假设一个由多个 Spring Boot 应用程序组成的示例项目,这些应用程序由 Maven 多模块设置组成(我知道您正在使用 Gradle,但是在出色的 spring.io 指南中有关于使用 Gradle 进行多模块设置的指南) :
github.com/jonashackt/cxf-spring-cloud-netflix-docker。我创建了一个buildpacks-paketo
包含我们需要的所有内容的新分支 - 并Dockerfiles
从相应的 Spring Boot 应用程序中删除了所有内容。因为我们不再需要使用Cloud Native Buildpacks(这是他们的设计目标)。
TLDR:我的想法是使用spring-boot-maven-plugin
(或它的 Gradle 等效项)在每个“正常”之前发布一个新的 Paketo 构建,docker-compose up
如下所示:
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>
示例项目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
服务完成它的工作并构建所有图像。但是正如 Docker 文档告诉我们的那样,我们需要与 Compose 中做出的设计决策相抗衡才能实现这一目标!我也找到了这个很好的答案,Max 解释说,用仅用于构建的容器来“污染”“生产”并不是一个好的设计。docker-compose.yml
之后,我将paketo-build
服务提取到它自己的 Compose 文件中 -build.yml
在示例项目中调用。有了它,我们现在可以运行 Paketo 构建,而无需依赖主机安装 Maven - 并且仅使用 Docker-Compose:
docker-compose -f build.yml up && docker-compose up
记住不要与第一个容器分离,-d
因为完整的 Paketo 构建必须在我们开始之前完成docker-compose.yml
。使用这种方法,我们也绝对不需要Dockerfile
. 但与此同时,我想到了完全消除对单独构建容器的需求,只需在 TLDR 中已经描述up
的类似连接之前使用 Maven(或 Gradle):&&
mvn clean spring-boot:build-image && docker-compose up
希望这对您有所帮助。很高兴听到您的反馈!这里还有一个完整的 GitHub 操作构建,展示了 Cloud CI 服务器上的所有“魔法”。
现在没有办法docker-compose up --build
使用 Paketo Buildpacks 触发所有 Spring Boot 应用程序的全新映像构建。