Merge branch '2.3.x'
Closes gh-21933
This commit is contained in:
@@ -46,6 +46,8 @@ public class BuildRequest {
|
||||
|
||||
private final ImageReference builder;
|
||||
|
||||
private final ImageReference runImage;
|
||||
|
||||
private final Creator creator;
|
||||
|
||||
private final Map<String, String> env;
|
||||
@@ -60,6 +62,7 @@ public class BuildRequest {
|
||||
this.name = name.inTaggedForm();
|
||||
this.applicationContent = applicationContent;
|
||||
this.builder = DEFAULT_BUILDER;
|
||||
this.runImage = null;
|
||||
this.env = Collections.emptyMap();
|
||||
this.cleanCache = false;
|
||||
this.verboseLogging = false;
|
||||
@@ -67,10 +70,12 @@ public class BuildRequest {
|
||||
}
|
||||
|
||||
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,
|
||||
Creator creator, Map<String, String> env, boolean cleanCache, boolean verboseLogging) {
|
||||
ImageReference runImage, Creator creator, Map<String, String> env, boolean cleanCache,
|
||||
boolean verboseLogging) {
|
||||
this.name = name;
|
||||
this.applicationContent = applicationContent;
|
||||
this.builder = builder;
|
||||
this.runImage = runImage;
|
||||
this.creator = creator;
|
||||
this.env = env;
|
||||
this.cleanCache = cleanCache;
|
||||
@@ -84,20 +89,29 @@ public class BuildRequest {
|
||||
*/
|
||||
public BuildRequest withBuilder(ImageReference builder) {
|
||||
Assert.notNull(builder, "Builder must not be null");
|
||||
builder = (builder.getDigest() != null) ? builder : builder.inTaggedForm();
|
||||
return new BuildRequest(this.name, this.applicationContent, builder, this.creator, this.env, this.cleanCache,
|
||||
this.verboseLogging);
|
||||
return new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.runImage,
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an updated builder.
|
||||
* Return a new {@link BuildRequest} with an updated run image.
|
||||
* @param runImageName the run image to use
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withRunImage(ImageReference runImageName) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, runImageName.inTaggedOrDigestForm(),
|
||||
this.creator, this.env, this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an updated creator.
|
||||
* @param creator the new {@code Creator} to use
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withCreator(Creator creator) {
|
||||
Assert.notNull(creator, "Creator must not be null");
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, creator, this.env, this.cleanCache,
|
||||
this.verboseLogging);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, creator, this.env,
|
||||
this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,12 +125,12 @@ public class BuildRequest {
|
||||
Assert.hasText(value, "Value must not be empty");
|
||||
Map<String, String> env = new LinkedHashMap<>(this.env);
|
||||
env.put(name, value);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator,
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
|
||||
Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an additional env variables.
|
||||
* Return a new {@link BuildRequest} with additional env variables.
|
||||
* @param env the additional variables
|
||||
* @return an updated build request
|
||||
*/
|
||||
@@ -124,27 +138,27 @@ public class BuildRequest {
|
||||
Assert.notNull(env, "Env must not be null");
|
||||
Map<String, String> updatedEnv = new LinkedHashMap<>(this.env);
|
||||
updatedEnv.putAll(env);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator,
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator,
|
||||
Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an specific clean cache settings.
|
||||
* Return a new {@link BuildRequest} with an updated clean cache setting.
|
||||
* @param cleanCache if the cache should be cleaned
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withCleanCache(boolean cleanCache) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator, this.env, cleanCache,
|
||||
this.verboseLogging);
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
cleanCache, this.verboseLogging);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link BuildRequest} with an specific verbose logging settings.
|
||||
* Return a new {@link BuildRequest} with an updated verbose logging setting.
|
||||
* @param verboseLogging if verbose logging should be used
|
||||
* @return an updated build request
|
||||
*/
|
||||
public BuildRequest withVerboseLogging(boolean verboseLogging) {
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.creator, this.env,
|
||||
return new BuildRequest(this.name, this.applicationContent, this.builder, this.runImage, this.creator, this.env,
|
||||
this.cleanCache, verboseLogging);
|
||||
}
|
||||
|
||||
@@ -175,6 +189,14 @@ public class BuildRequest {
|
||||
return this.builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the run image that should be used, if provided.
|
||||
* @return the run image
|
||||
*/
|
||||
public ImageReference getRunImage() {
|
||||
return this.runImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Creator} the builder should use.
|
||||
* @return the {@code Creator}
|
||||
|
||||
@@ -63,15 +63,12 @@ public class Builder {
|
||||
Image builderImage = pullBuilder(request);
|
||||
BuilderMetadata builderMetadata = BuilderMetadata.fromImage(builderImage);
|
||||
BuildOwner buildOwner = BuildOwner.fromEnv(builderImage.getConfig().getEnv());
|
||||
StackId stackId = StackId.fromImage(builderImage);
|
||||
ImageReference runImageReference = getRunImageReference(builderMetadata.getStack());
|
||||
Image runImage = pullRunImage(request, runImageReference);
|
||||
assertHasExpectedStackId(runImage, stackId);
|
||||
request = determineRunImage(request, builderImage, builderMetadata.getStack());
|
||||
EphemeralBuilder builder = new EphemeralBuilder(buildOwner, builderImage, builderMetadata, request.getCreator(),
|
||||
request.getEnv());
|
||||
this.docker.image().load(builder.getArchive(), UpdateListener.none());
|
||||
try {
|
||||
executeLifecycle(request, runImageReference, builder);
|
||||
executeLifecycle(request, builder);
|
||||
}
|
||||
finally {
|
||||
this.docker.image().remove(builder.getName(), true);
|
||||
@@ -87,29 +84,41 @@ public class Builder {
|
||||
return builderImage;
|
||||
}
|
||||
|
||||
private ImageReference getRunImageReference(Stack stack) {
|
||||
String name = stack.getRunImage().getImage();
|
||||
Assert.state(StringUtils.hasText(name), "Run image must be specified");
|
||||
return ImageReference.of(name).inTaggedForm();
|
||||
private BuildRequest determineRunImage(BuildRequest request, Image builderImage, Stack builderStack)
|
||||
throws IOException {
|
||||
if (request.getRunImage() == null) {
|
||||
ImageReference runImage = getRunImageReferenceForStack(builderStack);
|
||||
request = request.withRunImage(runImage);
|
||||
}
|
||||
Image runImage = pullRunImage(request);
|
||||
assertStackIdsMatch(runImage, builderImage);
|
||||
return request;
|
||||
}
|
||||
|
||||
private Image pullRunImage(BuildRequest request, ImageReference name) throws IOException {
|
||||
Consumer<TotalProgressEvent> progressConsumer = this.log.pullingRunImage(request, name);
|
||||
private ImageReference getRunImageReferenceForStack(Stack stack) {
|
||||
String name = stack.getRunImage().getImage();
|
||||
Assert.state(StringUtils.hasText(name), "Run image must be specified in the builder image stack");
|
||||
return ImageReference.of(name).inTaggedOrDigestForm();
|
||||
}
|
||||
|
||||
private Image pullRunImage(BuildRequest request) throws IOException {
|
||||
ImageReference runImage = request.getRunImage();
|
||||
Consumer<TotalProgressEvent> progressConsumer = this.log.pullingRunImage(request, runImage);
|
||||
TotalProgressPullListener listener = new TotalProgressPullListener(progressConsumer);
|
||||
Image image = this.docker.image().pull(name, listener);
|
||||
Image image = this.docker.image().pull(runImage, listener);
|
||||
this.log.pulledRunImage(request, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
private void assertHasExpectedStackId(Image image, StackId stackId) {
|
||||
StackId pulledStackId = StackId.fromImage(image);
|
||||
Assert.state(pulledStackId.equals(stackId),
|
||||
"Run image stack '" + pulledStackId + "' does not match builder stack '" + stackId + "'");
|
||||
private void assertStackIdsMatch(Image runImage, Image builderImage) {
|
||||
StackId runImageStackId = StackId.fromImage(runImage);
|
||||
StackId builderImageStackId = StackId.fromImage(builderImage);
|
||||
Assert.state(runImageStackId.equals(builderImageStackId),
|
||||
"Run image stack '" + runImageStackId + "' does not match builder stack '" + builderImageStackId + "'");
|
||||
}
|
||||
|
||||
private void executeLifecycle(BuildRequest request, ImageReference runImageReference, EphemeralBuilder builder)
|
||||
throws IOException {
|
||||
try (Lifecycle lifecycle = new Lifecycle(this.log, this.docker, request, runImageReference, builder)) {
|
||||
private void executeLifecycle(BuildRequest request, EphemeralBuilder builder) throws IOException {
|
||||
try (Lifecycle lifecycle = new Lifecycle(this.log, this.docker, request, builder)) {
|
||||
lifecycle.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,6 @@ class Lifecycle implements Closeable {
|
||||
|
||||
private final BuildRequest request;
|
||||
|
||||
private final ImageReference runImageReference;
|
||||
|
||||
private final EphemeralBuilder builder;
|
||||
|
||||
private final LifecycleVersion lifecycleVersion;
|
||||
@@ -73,15 +71,12 @@ class Lifecycle implements Closeable {
|
||||
* @param log build output log
|
||||
* @param docker the Docker API
|
||||
* @param request the request to process
|
||||
* @param runImageReference a reference to run image that should be used
|
||||
* @param builder the ephemeral builder used to run the phases
|
||||
*/
|
||||
Lifecycle(BuildLog log, DockerApi docker, BuildRequest request, ImageReference runImageReference,
|
||||
EphemeralBuilder builder) {
|
||||
Lifecycle(BuildLog log, DockerApi docker, BuildRequest request, EphemeralBuilder builder) {
|
||||
this.log = log;
|
||||
this.docker = docker;
|
||||
this.request = request;
|
||||
this.runImageReference = runImageReference;
|
||||
this.builder = builder;
|
||||
this.lifecycleVersion = LifecycleVersion.parse(builder.getBuilderMetadata().getLifecycle().getVersion());
|
||||
this.platformVersion = ApiVersion.parse(builder.getBuilderMetadata().getLifecycle().getApi().getPlatform());
|
||||
@@ -125,7 +120,7 @@ class Lifecycle implements Closeable {
|
||||
phase.withLogLevelArg();
|
||||
phase.withArgs("-app", Directory.APPLICATION);
|
||||
phase.withArgs("-platform", Directory.PLATFORM);
|
||||
phase.withArgs("-run-image", this.runImageReference);
|
||||
phase.withArgs("-run-image", this.request.getRunImage());
|
||||
phase.withArgs("-layers", Directory.LAYERS);
|
||||
phase.withArgs("-cache-dir", Directory.CACHE);
|
||||
phase.withArgs("-launch-cache", Directory.LAUNCH_CACHE);
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* A reference to a Docker image of the form {@code "imagename[:tag|@digest]"}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 2.3.0
|
||||
* @see ImageName
|
||||
* @see <a href=
|
||||
@@ -152,7 +153,19 @@ public final class ImageReference {
|
||||
*/
|
||||
public ImageReference inTaggedForm() {
|
||||
Assert.state(this.digest == null, () -> "Image reference '" + this + "' cannot contain a digest");
|
||||
return new ImageReference(this.name, (this.tag != null) ? this.tag : LATEST, this.digest);
|
||||
return new ImageReference(this.name, (this.tag != null) ? this.tag : LATEST, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an {@link ImageReference} containing either a tag or a digest. If neither
|
||||
* the digest or the tag has been defined then tag {@code latest} is used.
|
||||
* @return the image reference in tagged or digest form
|
||||
*/
|
||||
public ImageReference inTaggedOrDigestForm() {
|
||||
if (this.digest != null) {
|
||||
return this;
|
||||
}
|
||||
return inTaggedForm();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -82,7 +82,6 @@ public class BuildRequestTests {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> BuildRequest.forJarFile(new File(this.tempDir, "missing.jar")))
|
||||
.withMessage("JarFile must exist");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,6 +105,21 @@ public class BuildRequestTests {
|
||||
"docker.io/spring/builder:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withRunImageUpdatesRunImage() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"))
|
||||
.withRunImage(ImageReference.of("example.com/custom/run-image:latest"));
|
||||
assertThat(request.getRunImage().toString()).isEqualTo("example.com/custom/run-image:latest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withRunImageWhenHasDigestUpdatesRunImage() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")).withRunImage(ImageReference
|
||||
.of("example.com/custom/run-image:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"));
|
||||
assertThat(request.getRunImage().toString()).isEqualTo(
|
||||
"example.com/custom/run-image:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCreatorUpdatesCreator() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar"));
|
||||
|
||||
@@ -106,6 +106,47 @@ class BuilderTests {
|
||||
verify(docker.image()).remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildInvokesBuilderWithRunImageInDigestForm() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage("image-with-run-image-digest.json");
|
||||
Image runImage = loadImage("run-image.json");
|
||||
given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(ImageReference.of(
|
||||
"docker.io/cloudfoundry/run:@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d")),
|
||||
any())).willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker);
|
||||
BuildRequest request = getTestRequest();
|
||||
builder.build(request);
|
||||
assertThat(out.toString()).contains("Running creator");
|
||||
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
|
||||
verify(docker.image()).load(archive.capture(), any());
|
||||
verify(docker.image()).remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildInvokesBuilderWithRunImageFromRequest() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
DockerApi docker = mockDockerApi();
|
||||
Image builderImage = loadImage("image.json");
|
||||
Image runImage = loadImage("run-image.json");
|
||||
given(docker.image().pull(eq(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME)), any()))
|
||||
.willAnswer(withPulledImage(builderImage));
|
||||
given(docker.image().pull(eq(ImageReference.of("example.com/custom/run:latest")), any()))
|
||||
.willAnswer(withPulledImage(runImage));
|
||||
Builder builder = new Builder(BuildLog.to(out), docker);
|
||||
BuildRequest request = getTestRequest().withRunImage(ImageReference.of("example.com/custom/run:latest"));
|
||||
builder.build(request);
|
||||
assertThat(out.toString()).contains("Running creator");
|
||||
assertThat(out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
ArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);
|
||||
verify(docker.image()).load(archive.capture(), any());
|
||||
verify(docker.image()).remove(archive.getValue().getTag(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWhenStackIdDoesNotMatchThrowsException() throws Exception {
|
||||
TestPrintStream out = new TestPrintStream();
|
||||
@@ -175,8 +216,7 @@ class BuilderTests {
|
||||
private BuildRequest getTestRequest() {
|
||||
TarArchive content = mock(TarArchive.class);
|
||||
ImageReference name = ImageReference.of("my-application");
|
||||
BuildRequest request = BuildRequest.of(name, (owner) -> content);
|
||||
return request;
|
||||
return BuildRequest.of(name, (owner) -> content);
|
||||
}
|
||||
|
||||
private Image loadImage(String name) throws IOException {
|
||||
|
||||
@@ -150,7 +150,7 @@ class LifecycleTests {
|
||||
private BuildRequest getTestRequest() {
|
||||
TarArchive content = mock(TarArchive.class);
|
||||
ImageReference name = ImageReference.of("my-application");
|
||||
return BuildRequest.of(name, (owner) -> content);
|
||||
return BuildRequest.of(name, (owner) -> content).withRunImage(ImageReference.of("cloudfoundry/run"));
|
||||
}
|
||||
|
||||
private Lifecycle createLifecycle() throws IOException {
|
||||
@@ -159,8 +159,7 @@ class LifecycleTests {
|
||||
|
||||
private Lifecycle createLifecycle(BuildRequest request) throws IOException {
|
||||
EphemeralBuilder builder = mockEphemeralBuilder();
|
||||
return new TestLifecycle(BuildLog.to(this.out), this.docker, request, ImageReference.of("cloudfoundry/run"),
|
||||
builder);
|
||||
return new TestLifecycle(BuildLog.to(this.out), this.docker, request, builder);
|
||||
}
|
||||
|
||||
private EphemeralBuilder mockEphemeralBuilder() throws IOException {
|
||||
@@ -208,9 +207,8 @@ class LifecycleTests {
|
||||
|
||||
static class TestLifecycle extends Lifecycle {
|
||||
|
||||
TestLifecycle(BuildLog log, DockerApi docker, BuildRequest request, ImageReference runImageReference,
|
||||
EphemeralBuilder builder) {
|
||||
super(log, docker, request, runImageReference, builder);
|
||||
TestLifecycle(BuildLog log, DockerApi docker, BuildRequest request, EphemeralBuilder builder) {
|
||||
super(log, docker, request, builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* Tests for {@link ImageReference}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class ImageReferenceTests {
|
||||
|
||||
@@ -223,6 +224,26 @@ class ImageReferenceTests {
|
||||
assertThat(reference.inTaggedForm().toString()).isEqualTo("docker.io/library/ubuntu:bionic");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inTaggedOrDigestFormWhenHasDigestUsesDigest() {
|
||||
ImageReference reference = ImageReference
|
||||
.of("ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
assertThat(reference.inTaggedOrDigestForm().toString()).isEqualTo(
|
||||
"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inTaggedOrDigestFormWhenHasTagUsesTag() {
|
||||
ImageReference reference = ImageReference.of("ubuntu:bionic");
|
||||
assertThat(reference.inTaggedOrDigestForm().toString()).isEqualTo("docker.io/library/ubuntu:bionic");
|
||||
}
|
||||
|
||||
@Test
|
||||
void inTaggedOrDigestFormWhenHasNoTagOrDigestUsesLatest() {
|
||||
ImageReference reference = ImageReference.of("ubuntu");
|
||||
assertThat(reference.inTaggedOrDigestForm().toString()).isEqualTo("docker.io/library/ubuntu:latest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsAndHashCode() {
|
||||
ImageReference r1 = ImageReference.of("ubuntu:bionic");
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"User" : "root",
|
||||
"Image" : "pack.local/ephemeral-builder",
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "docker.io/library/my-application:latest" ],
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-skip-restore", "docker.io/library/my-application:latest" ],
|
||||
"Labels" : {
|
||||
"author" : "spring-boot"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"User" : "root",
|
||||
"Image" : "pack.local/ephemeral-builder",
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ],
|
||||
"Cmd" : [ "/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "docker.io/library/my-application:latest" ],
|
||||
"Labels" : {
|
||||
"author" : "spring-boot"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user