mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Add support for build workspace option when building images
Closes gh-37478
This commit is contained in:
parent
d8576f319e
commit
4433fcd1f2
@ -77,6 +77,8 @@ public class BuildRequest {
|
||||
|
||||
private final List<ImageReference> tags;
|
||||
|
||||
private final Cache buildWorkspace;
|
||||
|
||||
private final Cache buildCache;
|
||||
|
||||
private final Cache launchCache;
|
||||
@ -102,6 +104,7 @@ public class BuildRequest {
|
||||
this.bindings = Collections.emptyList();
|
||||
this.network = null;
|
||||
this.tags = Collections.emptyList();
|
||||
this.buildWorkspace = null;
|
||||
this.buildCache = null;
|
||||
this.launchCache = null;
|
||||
this.createdDate = null;
|
||||
@ -111,8 +114,8 @@ public class BuildRequest {
|
||||
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,
|
||||
ImageReference runImage, Creator creator, Map<String, String> env, boolean cleanCache,
|
||||
boolean verboseLogging, PullPolicy pullPolicy, boolean publish, List<BuildpackReference> buildpacks,
|
||||
List<Binding> bindings, String network, List<ImageReference> tags, Cache buildCache, Cache launchCache,
|
||||
Instant createdDate, String applicationDirectory) {
|
||||
List<Binding> bindings, String network, List<ImageReference> tags, Cache buildWorkspace, Cache buildCache,
|
||||
Cache launchCache, Instant createdDate, String applicationDirectory) {
|
||||
this.name = name;
|
||||
this.applicationContent = applicationContent;
|
||||
this.builder = builder;
|
||||
@ -127,6 +130,7 @@ public class BuildRequest {
|
||||
this.bindings = bindings;
|
||||
this.network = network;
|
||||
this.tags = tags;
|
||||
this.buildWorkspace = buildWorkspace;
|
||||
this.buildCache = buildCache;
|
||||
this.launchCache = launchCache;
|
||||
this.createdDate = createdDate;
|
||||
@ -142,8 +146,8 @@ public class BuildRequest {
|
||||
Assert.notNull(builder, "Builder must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.runImage,
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildCache, this.launchCache,
|
||||
this.createdDate, this.applicationDirectory);
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,8 +158,8 @@ public class BuildRequest {
|
||||
public BuildRequest withRunImage(ImageReference runImageName) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, runImageName.inTaggedOrDigestForm(),
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildCache, this.launchCache,
|
||||
this.createdDate, this.applicationDirectory);
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,7 +171,7 @@ public class BuildRequest {
|
||||
Assert.notNull(creator, "Creator must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -184,8 +188,8 @@ public class BuildRequest {
|
||||
env.put(name, value);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
|
||||
Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildCache, this.launchCache,
|
||||
this.createdDate, this.applicationDirectory);
|
||||
this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,8 +203,8 @@ public class BuildRequest {
|
||||
updatedEnv.putAll(env);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
|
||||
Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging, this.pullPolicy,
|
||||
this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildCache,
|
||||
this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace,
|
||||
this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,7 +215,7 @@ public class BuildRequest {
|
||||
public BuildRequest withCleanCache(boolean cleanCache) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -223,7 +227,7 @@ public class BuildRequest {
|
||||
public BuildRequest withVerboseLogging(boolean verboseLogging) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -235,7 +239,7 @@ public class BuildRequest {
|
||||
public BuildRequest withPullPolicy(PullPolicy pullPolicy) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -247,7 +251,7 @@ public class BuildRequest {
|
||||
public BuildRequest withPublish(boolean publish) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -272,7 +276,7 @@ public class BuildRequest {
|
||||
Assert.notNull(buildpacks, "Buildpacks must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -297,7 +301,7 @@ public class BuildRequest {
|
||||
Assert.notNull(bindings, "Bindings must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
@ -310,7 +314,8 @@ public class BuildRequest {
|
||||
public BuildRequest withNetwork(String network) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
network, this.tags, this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -332,7 +337,21 @@ public class BuildRequest {
|
||||
Assert.notNull(tags, "Tags must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, tags, this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.network, tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an updated build workspace.
|
||||
* @param buildWorkspace the build workspace
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withBuildWorkspace(Cache buildWorkspace) {
|
||||
Assert.notNull(buildWorkspace, "BuildWorkspace must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -344,7 +363,8 @@ public class BuildRequest {
|
||||
Assert.notNull(buildCache, "BuildCache must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, buildCache, this.launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.network, this.tags, this.buildWorkspace, buildCache, this.launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,7 +376,8 @@ public class BuildRequest {
|
||||
Assert.notNull(launchCache, "LaunchCache must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, launchCache, this.createdDate, this.applicationDirectory);
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, launchCache, this.createdDate,
|
||||
this.applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -368,8 +389,8 @@ public class BuildRequest {
|
||||
Assert.notNull(createdDate, "CreatedDate must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, parseCreatedDate(createdDate),
|
||||
this.applicationDirectory);
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,
|
||||
parseCreatedDate(createdDate), this.applicationDirectory);
|
||||
}
|
||||
|
||||
private Instant parseCreatedDate(String createdDate) {
|
||||
@ -393,7 +414,8 @@ public class BuildRequest {
|
||||
Assert.notNull(applicationDirectory, "ApplicationDirectory must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network, this.tags, this.buildCache, this.launchCache, this.createdDate, applicationDirectory);
|
||||
this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache, this.createdDate,
|
||||
applicationDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -513,6 +535,10 @@ public class BuildRequest {
|
||||
return this.tags;
|
||||
}
|
||||
|
||||
public Cache getBuildWorkspace() {
|
||||
return this.buildWorkspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the custom build cache that should be used by the lifecycle.
|
||||
* @return the build cache
|
||||
|
@ -18,7 +18,9 @@ package org.springframework.boot.buildpack.platform.build;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.sun.jna.Platform;
|
||||
@ -70,9 +72,9 @@ class Lifecycle implements Closeable {
|
||||
|
||||
private final ApiVersion platformVersion;
|
||||
|
||||
private final VolumeName layersVolume;
|
||||
private final Cache layers;
|
||||
|
||||
private final VolumeName applicationVolume;
|
||||
private final Cache application;
|
||||
|
||||
private final Cache buildCache;
|
||||
|
||||
@ -101,17 +103,13 @@ class Lifecycle implements Closeable {
|
||||
this.builder = builder;
|
||||
this.lifecycleVersion = LifecycleVersion.parse(builder.getBuilderMetadata().getLifecycle().getVersion());
|
||||
this.platformVersion = getPlatformVersion(builder.getBuilderMetadata().getLifecycle());
|
||||
this.layersVolume = createRandomVolumeName("pack-layers-");
|
||||
this.applicationVolume = createRandomVolumeName("pack-app-");
|
||||
this.layers = getLayersBindingSource(request);
|
||||
this.application = getApplicationBindingSource(request);
|
||||
this.buildCache = getBuildCache(request);
|
||||
this.launchCache = getLaunchCache(request);
|
||||
this.applicationDirectory = getApplicationDirectory(request);
|
||||
}
|
||||
|
||||
protected VolumeName createRandomVolumeName(String prefix) {
|
||||
return VolumeName.random(prefix);
|
||||
}
|
||||
|
||||
private Cache getBuildCache(BuildRequest request) {
|
||||
if (request.getBuildCache() != null) {
|
||||
return request.getBuildCache();
|
||||
@ -130,11 +128,6 @@ class Lifecycle implements Closeable {
|
||||
return (request.getApplicationDirectory() != null) ? request.getApplicationDirectory() : Directory.APPLICATION;
|
||||
}
|
||||
|
||||
private Cache createVolumeCache(BuildRequest request, String suffix) {
|
||||
return Cache.volume(
|
||||
VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", "." + suffix, 6));
|
||||
}
|
||||
|
||||
private ApiVersion getPlatformVersion(BuilderMetadata.Lifecycle lifecycle) {
|
||||
if (lifecycle.getApis().getPlatform() != null) {
|
||||
String[] supportedVersions = lifecycle.getApis().getPlatform();
|
||||
@ -153,12 +146,7 @@ class Lifecycle implements Closeable {
|
||||
this.executed = true;
|
||||
this.log.executingLifecycle(this.request, this.lifecycleVersion, this.buildCache);
|
||||
if (this.request.isCleanCache()) {
|
||||
if (this.buildCache.getVolume() != null) {
|
||||
deleteVolume(this.buildCache.getVolume().getVolumeName());
|
||||
}
|
||||
if (this.buildCache.getBind() != null) {
|
||||
deleteBind(this.buildCache.getBind().getSource());
|
||||
}
|
||||
deleteCache(this.buildCache);
|
||||
}
|
||||
run(createPhase());
|
||||
this.log.executedLifecycle(this.request);
|
||||
@ -183,8 +171,8 @@ class Lifecycle implements Closeable {
|
||||
phase.withArgs("-process-type=web");
|
||||
}
|
||||
phase.withArgs(this.request.getName());
|
||||
phase.withBinding(Binding.from(this.layersVolume, Directory.LAYERS));
|
||||
phase.withBinding(Binding.from(this.applicationVolume, this.applicationDirectory));
|
||||
phase.withBinding(Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));
|
||||
phase.withBinding(Binding.from(getCacheBindingSource(this.application), this.applicationDirectory));
|
||||
phase.withBinding(Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE));
|
||||
phase.withBinding(Binding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE));
|
||||
if (this.request.getBindings() != null) {
|
||||
@ -200,10 +188,42 @@ class Lifecycle implements Closeable {
|
||||
return phase;
|
||||
}
|
||||
|
||||
private Cache getLayersBindingSource(BuildRequest request) {
|
||||
if (request.getBuildWorkspace() != null) {
|
||||
return getBuildWorkspaceBindingSource(request.getBuildWorkspace(), "layers");
|
||||
}
|
||||
return createVolumeCache("pack-layers-");
|
||||
}
|
||||
|
||||
private Cache getApplicationBindingSource(BuildRequest request) {
|
||||
if (request.getBuildWorkspace() != null) {
|
||||
return getBuildWorkspaceBindingSource(request.getBuildWorkspace(), "app");
|
||||
}
|
||||
return createVolumeCache("pack-app-");
|
||||
}
|
||||
|
||||
private Cache getBuildWorkspaceBindingSource(Cache buildWorkspace, String suffix) {
|
||||
return (buildWorkspace.getVolume() != null) ? Cache.volume(buildWorkspace.getVolume().getName() + "-" + suffix)
|
||||
: Cache.bind(buildWorkspace.getBind().getSource() + "-" + suffix);
|
||||
}
|
||||
|
||||
private String getCacheBindingSource(Cache cache) {
|
||||
return (cache.getVolume() != null) ? cache.getVolume().getName() : cache.getBind().getSource();
|
||||
}
|
||||
|
||||
private Cache createVolumeCache(String prefix) {
|
||||
return Cache.volume(createRandomVolumeName(prefix));
|
||||
}
|
||||
|
||||
private Cache createVolumeCache(BuildRequest request, String suffix) {
|
||||
return Cache.volume(
|
||||
VolumeName.basedOn(request.getName(), ImageReference::toLegacyString, "pack-cache-", "." + suffix, 6));
|
||||
}
|
||||
|
||||
protected VolumeName createRandomVolumeName(String prefix) {
|
||||
return VolumeName.random(prefix);
|
||||
}
|
||||
|
||||
private void configureDaemonAccess(Phase phase) {
|
||||
if (this.dockerHost != null) {
|
||||
if (this.dockerHost.isRemote()) {
|
||||
@ -255,6 +275,9 @@ class Lifecycle implements Closeable {
|
||||
return this.docker.container().create(config);
|
||||
}
|
||||
try {
|
||||
if (this.application.getBind() != null) {
|
||||
Files.createDirectories(Path.of(this.application.getBind().getSource()));
|
||||
}
|
||||
TarArchive applicationContent = this.request.getApplicationContent(this.builder.getBuildOwner());
|
||||
return this.docker.container()
|
||||
.create(config, ContainerContent.of(applicationContent, this.applicationDirectory));
|
||||
@ -266,8 +289,17 @@ class Lifecycle implements Closeable {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
deleteVolume(this.layersVolume);
|
||||
deleteVolume(this.applicationVolume);
|
||||
deleteCache(this.layers);
|
||||
deleteCache(this.application);
|
||||
}
|
||||
|
||||
private void deleteCache(Cache cache) throws IOException {
|
||||
if (cache.getVolume() != null) {
|
||||
deleteVolume(cache.getVolume().getVolumeName());
|
||||
}
|
||||
if (cache.getBind() != null) {
|
||||
deleteBind(cache.getBind().getSource());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteVolume(VolumeName name) throws IOException {
|
||||
|
@ -233,6 +233,22 @@ class BuildRequestTests {
|
||||
.withMessage("Tags must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBuildWorkspaceVolumeAddsWorkspace() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
BuildRequest withWorkspace = request.withBuildWorkspace(Cache.volume("build-workspace"));
|
||||
assertThat(request.getBuildWorkspace()).isNull();
|
||||
assertThat(withWorkspace.getBuildWorkspace()).isEqualTo(Cache.volume("build-workspace"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBuildWorkspaceBindAddsWorkspace() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
BuildRequest withWorkspace = request.withBuildWorkspace(Cache.bind("/tmp/build-workspace"));
|
||||
assertThat(request.getBuildWorkspace()).isNull();
|
||||
assertThat(withWorkspace.getBuildWorkspace()).isEqualTo(Cache.bind("/tmp/build-workspace"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBuildVolumeCacheAddsCache() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
|
@ -211,7 +211,8 @@ class LifecycleTests {
|
||||
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
|
||||
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
|
||||
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
|
||||
BuildRequest request = getTestRequest().withBuildCache(Cache.volume("build-volume"))
|
||||
BuildRequest request = getTestRequest().withBuildWorkspace(Cache.volume("work-volume"))
|
||||
.withBuildCache(Cache.volume("build-volume"))
|
||||
.withLaunchCache(Cache.volume("launch-volume"));
|
||||
createLifecycle(request).execute();
|
||||
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-cache-volumes.json"));
|
||||
@ -223,7 +224,8 @@ class LifecycleTests {
|
||||
given(this.docker.container().create(any())).willAnswer(answerWithGeneratedContainerId());
|
||||
given(this.docker.container().create(any(), any())).willAnswer(answerWithGeneratedContainerId());
|
||||
given(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));
|
||||
BuildRequest request = getTestRequest().withBuildCache(Cache.bind("/tmp/build-cache"))
|
||||
BuildRequest request = getTestRequest().withBuildWorkspace(Cache.bind("/tmp/work"))
|
||||
.withBuildCache(Cache.bind("/tmp/build-cache"))
|
||||
.withLaunchCache(Cache.bind("/tmp/launch-cache"));
|
||||
createLifecycle(request).execute();
|
||||
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-cache-bind-mounts.json"));
|
||||
|
@ -27,8 +27,8 @@
|
||||
"HostConfig": {
|
||||
"Binds": [
|
||||
"/var/run/docker.sock:/var/run/docker.sock",
|
||||
"pack-layers-aaaaaaaaaa:/layers",
|
||||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"/tmp/work-layers:/layers",
|
||||
"/tmp/work-app:/workspace",
|
||||
"/tmp/build-cache:/cache",
|
||||
"/tmp/launch-cache:/launch-cache"
|
||||
],
|
||||
|
@ -27,8 +27,8 @@
|
||||
"HostConfig": {
|
||||
"Binds": [
|
||||
"/var/run/docker.sock:/var/run/docker.sock",
|
||||
"pack-layers-aaaaaaaaaa:/layers",
|
||||
"pack-app-aaaaaaaaaa:/workspace",
|
||||
"work-volume-layers:/layers",
|
||||
"work-volume-app:/workspace",
|
||||
"build-volume:/cache",
|
||||
"launch-volume:/launch-cache"
|
||||
],
|
||||
|
@ -193,14 +193,22 @@ The value supplied will be passed unvalidated to Docker when creating the builde
|
||||
The values provided to the `tags` option should be full image references in the form of `[image name]:[tag]` or `[repository]/[image name]:[tag]`.
|
||||
|
|
||||
|
||||
| `buildWorkspace`
|
||||
|
|
||||
| A temporary workspace that will be used by the builder and buildpacks to store files during image building.
|
||||
The value can be a named volume or a bind mount location.
|
||||
| A named volume in the Docker daemon, with a name derived from the image name.
|
||||
|
||||
| `buildCache`
|
||||
|
|
||||
| A cache containing layers created by buildpacks and used by the image building process.
|
||||
The value can be a named volume or a bind mount location.
|
||||
| A named volume in the Docker daemon, with a name derived from the image name.
|
||||
|
||||
| `launchCache`
|
||||
|
|
||||
| A cache containing layers created by buildpacks and used by the image launching process.
|
||||
The value can be a named volume or a bind mount location.
|
||||
| A named volume in the Docker daemon, with a name derived from the image name.
|
||||
|
||||
| `createdDate`
|
||||
@ -420,7 +428,7 @@ The publish option can be specified on the command line as well, as shown in thi
|
||||
----
|
||||
|
||||
[[build-image.examples.caches]]
|
||||
=== Builder Cache Configuration
|
||||
=== Builder Cache and Workspace Configuration
|
||||
|
||||
The CNB builder caches layers that are used when building and launching an image.
|
||||
By default, these caches are stored as named volumes in the Docker daemon with names that are derived from the full name of the target image.
|
||||
@ -440,7 +448,10 @@ include::../gradle/packaging/boot-build-image-caches.gradle[tags=caches]
|
||||
include::../gradle/packaging/boot-build-image-caches.gradle.kts[tags=caches]
|
||||
----
|
||||
|
||||
The caches can be configured to use bind mounts instead of named volumes, as shown in the following example:
|
||||
Builders and buildpacks need a location to store temporary files during image building.
|
||||
By default, this temporary build workspace is stored in a named volume.
|
||||
|
||||
The caches and the build workspace can be configured to use bind mounts instead of named volumes, as shown in the following example:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
|
||||
.Groovy
|
||||
|
@ -9,6 +9,11 @@ tasks.named("bootJar") {
|
||||
|
||||
// tag::caches[]
|
||||
tasks.named("bootBuildImage") {
|
||||
buildWorkspace {
|
||||
bind {
|
||||
source = "/tmp/cache-${rootProject.name}.work"
|
||||
}
|
||||
}
|
||||
buildCache {
|
||||
bind {
|
||||
source = "/tmp/cache-${rootProject.name}.build"
|
||||
@ -24,6 +29,7 @@ tasks.named("bootBuildImage") {
|
||||
|
||||
tasks.register("bootBuildImageCaches") {
|
||||
doFirst {
|
||||
bootBuildImage.buildWorkspace.asCache().with { print "buildWorkspace=$source" }
|
||||
bootBuildImage.buildCache.asCache().with { println "buildCache=$source" }
|
||||
bootBuildImage.launchCache.asCache().with { println "launchCache=$source" }
|
||||
}
|
||||
|
@ -7,6 +7,11 @@ plugins {
|
||||
|
||||
// tag::caches[]
|
||||
tasks.named<BootBuildImage>("bootBuildImage") {
|
||||
buildWorkspace {
|
||||
bind {
|
||||
source.set("/tmp/cache-${rootProject.name}.work")
|
||||
}
|
||||
}
|
||||
buildCache {
|
||||
bind {
|
||||
source.set("/tmp/cache-${rootProject.name}.build")
|
||||
@ -22,6 +27,7 @@ tasks.named<BootBuildImage>("bootBuildImage") {
|
||||
|
||||
tasks.register("bootBuildImageCaches") {
|
||||
doFirst {
|
||||
println("buildWorkspace=" + tasks.getByName<BootBuildImage>("bootBuildImage").buildWorkspace.asCache().bind.source)
|
||||
println("buildCache=" + tasks.getByName<BootBuildImage>("bootBuildImage").buildCache.asCache().bind.source)
|
||||
println("launchCache=" + tasks.getByName<BootBuildImage>("bootBuildImage").launchCache.asCache().bind.source)
|
||||
}
|
||||
|
@ -69,6 +69,8 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
|
||||
private final String projectName;
|
||||
|
||||
private final CacheSpec buildWorkspace;
|
||||
|
||||
private final CacheSpec buildCache;
|
||||
|
||||
private final CacheSpec launchCache;
|
||||
@ -91,6 +93,7 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
getCleanCache().convention(false);
|
||||
getVerboseLogging().convention(false);
|
||||
getPublish().convention(false);
|
||||
this.buildWorkspace = getProject().getObjects().newInstance(CacheSpec.class);
|
||||
this.buildCache = getProject().getObjects().newInstance(CacheSpec.class);
|
||||
this.launchCache = getProject().getObjects().newInstance(CacheSpec.class);
|
||||
this.docker = getProject().getObjects().newInstance(DockerSpec.class);
|
||||
@ -222,6 +225,25 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
@Option(option = "network", description = "Connect detect and build containers to network")
|
||||
public abstract Property<String> getNetwork();
|
||||
|
||||
/**
|
||||
* Returns the build temporary workspace that will be used when building the image.
|
||||
* @return the cache
|
||||
*/
|
||||
@Nested
|
||||
@Optional
|
||||
public CacheSpec getBuildWorkspace() {
|
||||
return this.buildWorkspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the {@link CacheSpec} for the build temporary workspace using the given
|
||||
* {@code action}.
|
||||
* @param action the action
|
||||
*/
|
||||
public void buildWorkspace(Action<CacheSpec> action) {
|
||||
action.execute(this.buildWorkspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the build cache that will be used when building the image.
|
||||
* @return the cache
|
||||
@ -400,6 +422,9 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
}
|
||||
|
||||
private BuildRequest customizeCaches(BuildRequest request) {
|
||||
if (this.buildWorkspace.asCache() != null) {
|
||||
request = request.withBuildWorkspace((this.buildWorkspace.asCache()));
|
||||
}
|
||||
if (this.buildCache.asCache() != null) {
|
||||
request = request.withBuildCache(this.buildCache.asCache());
|
||||
}
|
||||
|
@ -343,7 +343,8 @@ class PackagingDocumentationTests {
|
||||
void bootBuildImageWithBindCaches() {
|
||||
BuildResult result = this.gradleBuild.script("src/docs/gradle/packaging/boot-build-image-bind-caches")
|
||||
.build("bootBuildImageCaches");
|
||||
assertThat(result.getOutput()).containsPattern("buildCache=/tmp/cache-gradle-[\\d]+.build")
|
||||
assertThat(result.getOutput()).containsPattern("buildWorkspace=/tmp/cache-gradle-[\\d]+.work")
|
||||
.containsPattern("buildCache=/tmp/cache-gradle-[\\d]+.build")
|
||||
.containsPattern("launchCache=/tmp/cache-gradle-[\\d]+.launch");
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,11 @@ java {
|
||||
bootBuildImage {
|
||||
builder = "projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.2"
|
||||
pullPolicy = "IF_NOT_PRESENT"
|
||||
buildWorkspace {
|
||||
bind {
|
||||
source = System.getProperty('java.io.tmpdir') + "/junit-image-pack-${rootProject.name}-work"
|
||||
}
|
||||
}
|
||||
buildCache {
|
||||
bind {
|
||||
source = System.getProperty('java.io.tmpdir') + "/junit-image-cache-${rootProject.name}-build"
|
||||
|
@ -11,6 +11,11 @@ java {
|
||||
bootBuildImage {
|
||||
builder = "projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.2"
|
||||
pullPolicy = "IF_NOT_PRESENT"
|
||||
buildWorkspace {
|
||||
volume {
|
||||
name = "pack-${rootProject.name}.work"
|
||||
}
|
||||
}
|
||||
buildCache {
|
||||
volume {
|
||||
name = "cache-${rootProject.name}.build"
|
||||
|
@ -202,12 +202,19 @@ The value supplied will be passed unvalidated to Docker when creating the builde
|
||||
The values provided to the `tags` option should be full image references in the form of `[image name]:[tag]` or `[repository]/[image name]:[tag]`.
|
||||
|
|
||||
|
||||
| `buildWorkspace`
|
||||
| A temporary workspace that will be used by the builder and buildpacks to store files during image building.
|
||||
The value can be a named volume or a bind mount location.
|
||||
| A named volume in the Docker daemon, with a name derived from the image name.
|
||||
|
||||
| `buildCache`
|
||||
| A cache containing layers created by buildpacks and used by the image building process.
|
||||
The value can be a named volume or a bind mount location.
|
||||
| A named volume in the Docker daemon, with a name derived from the image name.
|
||||
|
||||
| `launchCache`
|
||||
| A cache containing layers created by buildpacks and used by the image launching process.
|
||||
The value can be a named volume or a bind mount location.
|
||||
| A named volume in the Docker daemon, with a name derived from the image name.
|
||||
|
||||
| `createdDate` +
|
||||
@ -403,7 +410,7 @@ include::../maven/packaging-oci-image/docker-pom-authentication-command-line.xml
|
||||
----
|
||||
|
||||
[[build-image.examples.caches]]
|
||||
=== Builder Cache Configuration
|
||||
=== Builder Cache and Workspace Configuration
|
||||
|
||||
The CNB builder caches layers that are used when building and launching an image.
|
||||
By default, these caches are stored as named volumes in the Docker daemon with names that are derived from the full name of the target image.
|
||||
@ -416,7 +423,10 @@ The cache volumes can be configured to use alternative names to give more contro
|
||||
include::../maven/packaging-oci-image/caches-pom.xml[tags=caches]
|
||||
----
|
||||
|
||||
The caches can be configured to use bind mounts instead of named volumes, as shown in the following example:
|
||||
Builders and buildpacks need a location to store temporary files during image building.
|
||||
By default, this temporary build workspace is stored in a named volume.
|
||||
|
||||
The caches and the build workspace can be configured to use bind mounts instead of named volumes, as shown in the following example:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,attributes",tabsize=4]
|
||||
----
|
||||
|
@ -8,6 +8,11 @@
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<image>
|
||||
<buildWorkspace>
|
||||
<bind>
|
||||
<source>/tmp/cache-${project.artifactId}.work</source>
|
||||
</bind>
|
||||
</buildWorkspace>
|
||||
<buildCache>
|
||||
<bind>
|
||||
<source>/tmp/cache-${project.artifactId}.build</source>
|
||||
|
@ -24,6 +24,11 @@
|
||||
<configuration>
|
||||
<image>
|
||||
<builder>projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.2</builder>
|
||||
<buildWorkspace>
|
||||
<bind>
|
||||
<source>${java.io.tmpdir}/junit-image-cache-${test-build-id}-work</source>
|
||||
</bind>
|
||||
</buildWorkspace>
|
||||
<buildCache>
|
||||
<bind>
|
||||
<source>${java.io.tmpdir}/junit-image-cache-${test-build-id}-build</source>
|
||||
|
@ -24,6 +24,11 @@
|
||||
<configuration>
|
||||
<image>
|
||||
<builder>projects.registry.vmware.com/springboot/spring-boot-cnb-builder:0.0.2</builder>
|
||||
<buildWorkspace>
|
||||
<volume>
|
||||
<name>cache-${test-build-id}.work</name>
|
||||
</volume>
|
||||
</buildWorkspace>
|
||||
<buildCache>
|
||||
<volume>
|
||||
<name>cache-${test-build-id}.build</name>
|
||||
|
@ -69,6 +69,8 @@ public class Image {
|
||||
|
||||
List<String> tags;
|
||||
|
||||
CacheInfo buildWorkspace;
|
||||
|
||||
CacheInfo buildCache;
|
||||
|
||||
CacheInfo launchCache;
|
||||
@ -243,6 +245,9 @@ public class Image {
|
||||
if (!CollectionUtils.isEmpty(this.tags)) {
|
||||
request = request.withTags(this.tags.stream().map(ImageReference::of).toList());
|
||||
}
|
||||
if (this.buildWorkspace != null) {
|
||||
request = request.withBuildWorkspace(this.buildWorkspace.asCache());
|
||||
}
|
||||
if (this.buildCache != null) {
|
||||
request = request.withBuildCache(this.buildCache.asCache());
|
||||
}
|
||||
|
@ -170,6 +170,14 @@ class ImageTests {
|
||||
ImageReference.of("example.com/my-app:0.0.1-SNAPSHOT"), ImageReference.of("example.com/my-app:latest"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasBuildWorkspaceVolumeUsesWorkspace() {
|
||||
Image image = new Image();
|
||||
image.buildWorkspace = CacheInfo.fromVolume(new VolumeCacheInfo("build-work-vol"));
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getBuildWorkspace()).isEqualTo(Cache.volume("build-work-vol"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasBuildCacheVolumeUsesCache() {
|
||||
Image image = new Image();
|
||||
@ -186,6 +194,14 @@ class ImageTests {
|
||||
assertThat(request.getLaunchCache()).isEqualTo(Cache.volume("launch-cache-vol"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasBuildWorkspaceBindUsesWorkspace() {
|
||||
Image image = new Image();
|
||||
image.buildWorkspace = CacheInfo.fromBind(new BindCacheInfo("build-work-dir"));
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getBuildWorkspace()).isEqualTo(Cache.bind("build-work-dir"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenHasBuildCacheBindUsesCache() {
|
||||
Image image = new Image();
|
||||
|
Loading…
Reference in New Issue
Block a user