Add network option for image building
This commit adds configuration to the Maven and Gradle plugins to allow specifying the network mode to be provided to the image building goal and task. See gh-27486
This commit is contained in:
parent
e737388f5c
commit
8e6d03b221
|
@ -36,6 +36,7 @@ import org.springframework.util.Assert;
|
|||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Andrey Shlykov
|
||||
* @author Jeroen Meijer
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class BuildRequest {
|
||||
|
@ -68,6 +69,8 @@ public class BuildRequest {
|
|||
|
||||
private final List<Binding> bindings;
|
||||
|
||||
private final String network;
|
||||
|
||||
BuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent) {
|
||||
Assert.notNull(name, "Name must not be null");
|
||||
Assert.notNull(applicationContent, "ApplicationContent must not be null");
|
||||
|
@ -83,12 +86,13 @@ public class BuildRequest {
|
|||
this.creator = Creator.withVersion("");
|
||||
this.buildpacks = Collections.emptyList();
|
||||
this.bindings = Collections.emptyList();
|
||||
this.network = null;
|
||||
}
|
||||
|
||||
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) {
|
||||
List<Binding> bindings, String network) {
|
||||
this.name = name;
|
||||
this.applicationContent = applicationContent;
|
||||
this.builder = builder;
|
||||
|
@ -101,6 +105,7 @@ public class BuildRequest {
|
|||
this.publish = publish;
|
||||
this.buildpacks = buildpacks;
|
||||
this.bindings = bindings;
|
||||
this.network = network;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +117,7 @@ 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.buildpacks, this.bindings, this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,7 +128,7 @@ 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.buildpacks, this.bindings, this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,7 +139,8 @@ public class BuildRequest {
|
|||
public BuildRequest withCreator(Creator creator) {
|
||||
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.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,7 +156,7 @@ 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.buildpacks, this.bindings, this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +170,7 @@ 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.publish, this.buildpacks, this.bindings, this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,7 +180,8 @@ 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);
|
||||
cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,7 +191,8 @@ 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.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,7 +202,8 @@ 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.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks, this.bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,7 +213,8 @@ 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.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks, this.bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,7 +237,8 @@ public class BuildRequest {
|
|||
public BuildRequest withBuildpacks(List<BuildpackReference> buildpacks) {
|
||||
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.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks, this.bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,7 +261,14 @@ public class BuildRequest {
|
|||
public BuildRequest withBindings(List<Binding> bindings) {
|
||||
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.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks, bindings,
|
||||
this.network);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,6 +371,10 @@ public class BuildRequest {
|
|||
return this.bindings;
|
||||
}
|
||||
|
||||
public String getNetwork() {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link BuildRequest} from a JAR file.
|
||||
* @param jarFile the source jar file
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.springframework.util.Assert;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class Lifecycle implements Closeable {
|
||||
|
||||
|
@ -147,6 +148,7 @@ class Lifecycle implements Closeable {
|
|||
this.request.getBindings().forEach(phase::withBinding);
|
||||
}
|
||||
phase.withEnv(PLATFORM_API_VERSION_KEY, this.platformVersion.toString());
|
||||
phase.withNetworkMode(this.request.getNetwork());
|
||||
return phase;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class Phase {
|
||||
|
||||
|
@ -48,6 +49,8 @@ class Phase {
|
|||
|
||||
private final Map<String, String> env = new LinkedHashMap<>();
|
||||
|
||||
private String networkMode;
|
||||
|
||||
/**
|
||||
* Create a new {@link Phase} instance.
|
||||
* @param name the name of the phase
|
||||
|
@ -101,6 +104,10 @@ class Phase {
|
|||
this.env.put(name, value);
|
||||
}
|
||||
|
||||
void withNetworkMode(String networkMode) {
|
||||
this.networkMode = networkMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the phase.
|
||||
* @return the phase name
|
||||
|
@ -127,6 +134,7 @@ class Phase {
|
|||
update.withLabel("author", "spring-boot");
|
||||
this.bindings.forEach(update::withBinding);
|
||||
this.env.forEach(update::withEnv);
|
||||
update.withNetworkMode(this.networkMode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class ContainerConfig {
|
||||
|
@ -47,7 +48,7 @@ public class ContainerConfig {
|
|||
private final String json;
|
||||
|
||||
ContainerConfig(String user, ImageReference image, String command, List<String> args, Map<String, String> labels,
|
||||
List<Binding> bindings, Map<String, String> env) throws IOException {
|
||||
List<Binding> bindings, Map<String, String> env, String networkMode) throws IOException {
|
||||
Assert.notNull(image, "Image must not be null");
|
||||
Assert.hasText(command, "Command must not be empty");
|
||||
ObjectMapper objectMapper = SharedObjectMapper.get();
|
||||
|
@ -64,6 +65,9 @@ public class ContainerConfig {
|
|||
ObjectNode labelsNode = node.putObject("Labels");
|
||||
labels.forEach(labelsNode::put);
|
||||
ObjectNode hostConfigNode = node.putObject("HostConfig");
|
||||
if (networkMode != null) {
|
||||
hostConfigNode.put("NetworkMode", networkMode);
|
||||
}
|
||||
ArrayNode bindsNode = hostConfigNode.putArray("Binds");
|
||||
bindings.forEach((binding) -> bindsNode.add(binding.toString()));
|
||||
this.json = objectMapper.writeValueAsString(node);
|
||||
|
@ -114,6 +118,8 @@ public class ContainerConfig {
|
|||
|
||||
private final Map<String, String> env = new LinkedHashMap<>();
|
||||
|
||||
private String networkMode;
|
||||
|
||||
Update(ImageReference image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
@ -122,7 +128,7 @@ public class ContainerConfig {
|
|||
update.accept(this);
|
||||
try {
|
||||
return new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings,
|
||||
this.env);
|
||||
this.env, this.networkMode);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
|
@ -182,6 +188,10 @@ public class ContainerConfig {
|
|||
this.env.put(name, value);
|
||||
}
|
||||
|
||||
public void withNetworkMode(String networkMode) {
|
||||
this.networkMode = networkMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.entry;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
public class BuildRequestTests {
|
||||
|
||||
|
@ -199,6 +200,12 @@ public class BuildRequestTests {
|
|||
.withMessage("Bindings must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withNetworkUpdatesNetwork() throws IOException {
|
||||
BuildRequest request = BuildRequest.forJarFile(writeTestJarFile("my-app-0.0.1.jar")).withNetwork("test");
|
||||
assertThat(request.getNetwork()).isEqualTo("test");
|
||||
}
|
||||
|
||||
private void hasExpectedJarContent(TarArchive archive) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
|
|
@ -62,6 +62,7 @@ import static org.mockito.Mockito.verify;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class LifecycleTests {
|
||||
|
||||
|
@ -188,6 +189,17 @@ class LifecycleTests {
|
|||
verify(this.docker.volume()).delete(VolumeName.of("pack-app-aaaaaaaaaa"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeWithNetworkExecutesPhases() throws Exception {
|
||||
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().withNetwork("test");
|
||||
createLifecycle(request).execute();
|
||||
assertPhaseWasRun("creator", withExpectedConfig("lifecycle-creator-network.json"));
|
||||
assertThat(this.out.toString()).contains("Successfully built image 'docker.io/library/my-application:latest'");
|
||||
}
|
||||
|
||||
private DockerApi mockDockerApi() {
|
||||
DockerApi docker = mock(DockerApi.class);
|
||||
ImageApi imageApi = mock(ImageApi.class);
|
||||
|
|
|
@ -32,6 +32,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class PhaseTests {
|
||||
|
||||
|
@ -56,6 +57,7 @@ class PhaseTests {
|
|||
phase.apply(update);
|
||||
verify(update).withCommand("/cnb/lifecycle/test", NO_ARGS);
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
@ -69,6 +71,7 @@ class PhaseTests {
|
|||
verify(update).withBinding(Binding.from("/var/run/docker.sock", "/var/run/docker.sock"));
|
||||
verify(update).withCommand("/cnb/lifecycle/test", NO_ARGS);
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
@ -80,6 +83,7 @@ class PhaseTests {
|
|||
phase.apply(update);
|
||||
verify(update).withCommand("/cnb/lifecycle/test", "-log-level", "debug");
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
@ -91,6 +95,7 @@ class PhaseTests {
|
|||
phase.apply(update);
|
||||
verify(update).withCommand("/cnb/lifecycle/test");
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
@ -102,6 +107,7 @@ class PhaseTests {
|
|||
phase.apply(update);
|
||||
verify(update).withCommand("/cnb/lifecycle/test", "a", "b", "c");
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
@ -115,6 +121,7 @@ class PhaseTests {
|
|||
verify(update).withCommand("/cnb/lifecycle/test");
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withBinding(Binding.from(volumeName, "/test"));
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
@ -129,6 +136,19 @@ class PhaseTests {
|
|||
verify(update).withLabel("author", "spring-boot");
|
||||
verify(update).withEnv("name1", "value1");
|
||||
verify(update).withEnv("name2", "value2");
|
||||
verify(update).withNetworkMode(null);
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenWithNetworkModeUpdatesConfigurationWithNetworkMode() {
|
||||
Phase phase = new Phase("test", true);
|
||||
phase.withNetworkMode("test");
|
||||
Update update = mock(Update.class);
|
||||
phase.apply(update);
|
||||
verify(update).withCommand("/cnb/lifecycle/test");
|
||||
verify(update).withNetworkMode("test");
|
||||
verify(update).withLabel("author", "spring-boot");
|
||||
verifyNoMoreInteractions(update);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class ContainerConfigTests extends AbstractJsonTests {
|
||||
|
||||
|
@ -59,6 +60,7 @@ class ContainerConfigTests extends AbstractJsonTests {
|
|||
update.withBinding(Binding.from("bind-source", "bind-dest"));
|
||||
update.withEnv("name1", "value1");
|
||||
update.withEnv("name2", "value2");
|
||||
update.withNetworkMode("test");
|
||||
});
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
containerConfig.writeTo(outputStream);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"User" : "root",
|
||||
"Image" : "pack.local/ephemeral-builder",
|
||||
"Cmd" : [ "/cnb/lifecycle/creator", "-app", "/workspace", "-platform", "/platform", "-run-image", "docker.io/cloudfoundry/run:latest", "-layers", "/layers", "-cache-dir", "/cache", "-launch-cache", "/launch-cache", "-daemon", "-process-type=web", "docker.io/library/my-application:latest" ],
|
||||
"Env" : [ "CNB_PLATFORM_API=0.4" ],
|
||||
"Labels" : {
|
||||
"author" : "spring-boot"
|
||||
},
|
||||
"HostConfig" : {
|
||||
"NetworkMode" : "test",
|
||||
"Binds" : [ "/var/run/docker.sock:/var/run/docker.sock", "pack-layers-aaaaaaaaaa:/layers", "pack-app-aaaaaaaaaa:/workspace", "pack-cache-b35197ac41ea.build:/cache", "pack-cache-b35197ac41ea.launch:/launch-cache" ]
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
"HostConfig": {
|
||||
"Binds": [
|
||||
"bind-source:bind-dest"
|
||||
]
|
||||
],
|
||||
"NetworkMode": "test"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,6 +169,14 @@ Where `<options>` can contain:
|
|||
| `--publishImage`
|
||||
| Whether to publish the generated image to a Docker registry.
|
||||
| `false`
|
||||
|
||||
| `network`
|
||||
| `--network`
|
||||
| The network the build container will connect to. The value supplied for this option will be passed
|
||||
unvalidated as `HostConfig.NetworkMode` to the configuration which creates the build container,
|
||||
see https://docs.docker.com/engine/api/v1.41/#operation/ContainerCreate[Docker's engine API].
|
||||
Using this option is similar to running `docker build --network ...`.
|
||||
|
|
||||
|===
|
||||
|
||||
NOTE: The plugin detects the target Java compatibility of the project using the JavaPlugin's `targetCompatibility` property.
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class BootBuildImage extends DefaultTask {
|
||||
|
@ -92,6 +93,8 @@ public class BootBuildImage extends DefaultTask {
|
|||
|
||||
private final ListProperty<String> bindings;
|
||||
|
||||
private String network;
|
||||
|
||||
private final DockerSpec docker = new DockerSpec();
|
||||
|
||||
public BootBuildImage() {
|
||||
|
@ -376,6 +379,25 @@ public class BootBuildImage extends DefaultTask {
|
|||
this.bindings.addAll(bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network the build container will connect to.
|
||||
* @return the network
|
||||
*/
|
||||
@Input
|
||||
@Optional
|
||||
public String getNetwork() {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the network the build container will connect to.
|
||||
* @param network the network
|
||||
*/
|
||||
@Option(option = "network", description = "Connect detect and build containers to network")
|
||||
public void setNetwork(String network) {
|
||||
this.network = network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Docker configuration the builder will use.
|
||||
* @return docker configuration.
|
||||
|
@ -438,6 +460,7 @@ public class BootBuildImage extends DefaultTask {
|
|||
request = customizePublish(request);
|
||||
request = customizeBuildpacks(request);
|
||||
request = customizeBindings(request);
|
||||
request = request.withNetwork(this.network);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
* @author Andrey Shlykov
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class BootBuildImageTests {
|
||||
|
||||
|
@ -278,4 +279,10 @@ class BootBuildImageTests {
|
|||
.containsExactly(Binding.of("host-src:container-dest:ro"), Binding.of("volume-name:container-dest:rw"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNetworkIsConfiguredThenRequestHasNetwork() {
|
||||
this.buildImage.setNetwork("test");
|
||||
assertThat(this.buildImage.createRequest().getNetwork()).isEqualTo("test");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -176,6 +176,14 @@ Where `<options>` can contain:
|
|||
(`spring-boot.build-image.publish`)
|
||||
| Whether to publish the generated image to a Docker registry.
|
||||
| `false`
|
||||
|
||||
| `network` +
|
||||
(`spring-boot.build-image.network`)
|
||||
| The network the build container will connect to. The value supplied for this option will be passed
|
||||
unvalidated as `HostConfig.NetworkMode` to the configuration which creates the build container,
|
||||
see https://docs.docker.com/engine/api/v1.41/#operation/ContainerCreate[Docker's engine API].
|
||||
Using this option is similar to running `docker build --network ...`.
|
||||
|
|
||||
|===
|
||||
|
||||
NOTE: The plugin detects the target Java compatibility of the project using the compiler's plugin configuration or the `maven.compiler.target` property.
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Mojo(name = "build-image", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true,
|
||||
|
@ -153,6 +154,13 @@ public class BuildImageMojo extends AbstractPackagerMojo {
|
|||
@Parameter(property = "spring-boot.build-image.publish", readonly = true)
|
||||
Boolean publish;
|
||||
|
||||
/**
|
||||
* Alias for {@link Image#network} to support configuration via command-line property.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Parameter(property = "spring-boot.build-image.network", readonly = true)
|
||||
String network;
|
||||
|
||||
/**
|
||||
* Docker configuration options.
|
||||
* @since 2.4.0
|
||||
|
@ -248,6 +256,9 @@ public class BuildImageMojo extends AbstractPackagerMojo {
|
|||
if (image.publish == null && this.publish != null) {
|
||||
image.setPublish(this.publish);
|
||||
}
|
||||
if (image.network == null && this.network != null) {
|
||||
image.setNetwork(this.network);
|
||||
}
|
||||
if (image.publish != null && image.publish && publishRegistryNotConfigured()) {
|
||||
throw new MojoExecutionException("Publishing an image requires docker.publishRegistry to be configured");
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class Image {
|
||||
|
@ -63,6 +64,8 @@ public class Image {
|
|||
|
||||
List<String> bindings;
|
||||
|
||||
String network;
|
||||
|
||||
/**
|
||||
* The name of the created image.
|
||||
* @return the image name
|
||||
|
@ -151,6 +154,18 @@ public class Image {
|
|||
this.publish = publish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network the build container will connect to.
|
||||
* @return the network
|
||||
*/
|
||||
public String getNetwork() {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
public void setNetwork(String network) {
|
||||
this.network = network;
|
||||
}
|
||||
|
||||
BuildRequest getBuildRequest(Artifact artifact, Function<Owner, TarArchive> applicationContent) {
|
||||
return customize(BuildRequest.of(getOrDeduceName(artifact), applicationContent));
|
||||
}
|
||||
|
@ -190,6 +205,7 @@ public class Image {
|
|||
if (!CollectionUtils.isEmpty(this.bindings)) {
|
||||
request = request.withBindings(this.bindings.stream().map(Binding::of).collect(Collectors.toList()));
|
||||
}
|
||||
request = request.withNetwork(this.network);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.entry;
|
|||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @author Jeroen Meijer
|
||||
*/
|
||||
class ImageTests {
|
||||
|
||||
|
@ -70,6 +71,7 @@ class ImageTests {
|
|||
assertThat(request.getPullPolicy()).isEqualTo(PullPolicy.ALWAYS);
|
||||
assertThat(request.getBuildpacks()).isEmpty();
|
||||
assertThat(request.getBindings()).isEmpty();
|
||||
assertThat(request.getNetwork()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -146,6 +148,14 @@ class ImageTests {
|
|||
Binding.of("volume-name:container-dest:rw"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuildRequestWhenNetworkUsesNetwork() {
|
||||
Image image = new Image();
|
||||
image.network = "test";
|
||||
BuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());
|
||||
assertThat(request.getNetwork()).isEqualTo("test");
|
||||
}
|
||||
|
||||
private Artifact createArtifact() {
|
||||
return new DefaultArtifact("com.example", "my-app", VersionRange.createFromVersion("0.0.1-SNAPSHOT"), "compile",
|
||||
"jar", null, new DefaultArtifactHandler());
|
||||
|
|
Loading…
Reference in New Issue