Add runImage option for image building
This commit adds a runImage property to the Maven plugin build-image goal and the Gradle bootBuildImage task. The property allows the user to override the run image reference provided in the builder metadata with an alternate run image. The runImage property can be specified in the build file or on the command line. Fixes gh-21534
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