Skip to content

Commit

Permalink
Change the way the builder image is used on remote docker daemons
Browse files Browse the repository at this point in the history
This patch creates a volume for /project where we can copy files to/from
using `docker cp`. The volume is create in the prebuild step, then used
in the build step, and finally removed in the postbuild step. The new
approach allows us to execute more than one commands using
`docker run --rm` on the same files in /project.
  • Loading branch information
zakkak committed Mar 2, 2021
1 parent f0e7fa8 commit 01953a7
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public NativeImageBuildContainerRunner(NativeConfig nativeConfig, Path outputDir
containerRuntime = nativeConfig.containerRuntime.orElseGet(NativeImageBuildContainerRunner::detectContainerRuntime);
log.infof("Using %s to run the native image builder", containerRuntime.getExecutableName());

this.baseContainerRuntimeArgs = new String[] { "--env", "LANG=C" };
this.baseContainerRuntimeArgs = new String[] { "--env", "LANG=C", "--rm" };

outputPath = outputDir == null ? null : outputDir.toAbsolutePath().toString();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected List<String> getContainerRuntimeBuildArgs() {
}
}

Collections.addAll(containerRuntimeArgs, "--rm", "-v",
Collections.addAll(containerRuntimeArgs, "-v",
volumeOutputPath + ":" + NativeImageBuildStep.CONTAINER_BUILD_VOLUME_PATH + ":z");
return containerRuntimeArgs;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.jboss.logging.Logger;
Expand All @@ -13,6 +15,7 @@
public class NativeImageBuildRemoteContainerRunner extends NativeImageBuildContainerRunner {

private static final Logger log = Logger.getLogger(NativeImageBuildRemoteContainerRunner.class);
private static final String CONTAINER_BUILD_VOLUME_NAME = "quarkus-native-builder-image-project-volume";

private final String nativeImageName;
private String containerId;
Expand All @@ -24,41 +27,63 @@ public NativeImageBuildRemoteContainerRunner(NativeConfig nativeConfig, Path out

@Override
protected void preBuild(List<String> buildArgs) throws InterruptedException, IOException {
List<String> containerRuntimeArgs = getContainerRuntimeBuildArgs();
String[] createContainerCommand = buildCommand("create", containerRuntimeArgs, buildArgs);
log.info(String.join(" ", createContainerCommand).replace("$", "\\$"));
Process createContainerProcess = new ProcessBuilder(createContainerCommand).start();
if (createContainerProcess.waitFor() != 0) {
throw new RuntimeException("Failed to create builder container.");
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(createContainerProcess.getInputStream()))) {
containerId = reader.readLine();
}
// docker volume rm <volumeID>
rmVolume(null);
// docker create -v <volumeID>:/project <image-name>
final List<String> containerRuntimeArgs = Arrays.asList("-v",
CONTAINER_BUILD_VOLUME_NAME + ":" + NativeImageBuildStep.CONTAINER_BUILD_VOLUME_PATH);
final String[] createTempContainerCommand = buildCommand("create", containerRuntimeArgs, Collections.emptyList());
containerId = runCommandAndReadOutput(createTempContainerCommand, "Failed to create temp container.");
// docker cp <files> <containerID>:/project
String[] copyCommand = new String[] { containerRuntime.getExecutableName(), "cp", outputPath + "/.",
containerId + ":" + NativeImageBuildStep.CONTAINER_BUILD_VOLUME_PATH };
runCommand(copyCommand, "Failed to copy source-jar and libs from host to builder container", null);
super.preBuild(buildArgs);
}

@Override
protected String[] getBuildCommand(List<String> args) {
return new String[] { containerRuntime.getExecutableName(), "start", "--attach", containerId };
private String runCommandAndReadOutput(String[] command, String errorMsg) throws IOException, InterruptedException {
log.info(String.join(" ", command).replace("$", "\\$"));
Process process = new ProcessBuilder(command).start();
if (process.waitFor() != 0) {
throw new RuntimeException(errorMsg);
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
return reader.readLine();
}
}

@Override
protected void postBuild() throws InterruptedException, IOException {
copyFromBuilder(nativeImageName, "Failed to copy native image from container back to the host.");
protected void postBuild() {
copyFromContainerVolume(nativeImageName, "Failed to copy native image from container volume back to the host.");
if (nativeConfig.debug.enabled) {
copyFromBuilder("sources", "Failed to copy sources from container back to the host.");
copyFromContainerVolume("sources", "Failed to copy sources from container volume back to the host.");
}
String[] removeCommand = new String[] { containerRuntime.getExecutableName(), "container", "rm", "--volumes",
// docker container rm <containerID>
final String[] rmTempContainerCommand = new String[] { containerRuntime.getExecutableName(), "container", "rm",
containerId };
runCommand(removeCommand, "Failed to remove container: " + containerId, null);
runCommand(rmTempContainerCommand, "Failed to remove container: " + containerId, null);
// docker volume rm <volumeID>
rmVolume("Failed to remove volume: " + CONTAINER_BUILD_VOLUME_NAME);
}

private void copyFromBuilder(String path, String errorMsg) throws IOException, InterruptedException {
private void rmVolume(String errorMsg) {
final String[] rmVolumeCommand = new String[] { containerRuntime.getExecutableName(), "volume", "rm",
CONTAINER_BUILD_VOLUME_NAME };
runCommand(rmVolumeCommand, errorMsg, null);
}

private void copyFromContainerVolume(String path, String errorMsg) {
// docker cp <containerID>:/project/<path> <dest>
String[] copyCommand = new String[] { containerRuntime.getExecutableName(), "cp",
containerId + ":" + NativeImageBuildStep.CONTAINER_BUILD_VOLUME_PATH + "/" + path, outputPath };
runCommand(copyCommand, errorMsg, null);
}

@Override
protected List<String> getContainerRuntimeBuildArgs() {
List<String> containerRuntimeArgs = super.getContainerRuntimeBuildArgs();
Collections.addAll(containerRuntimeArgs, "-v",
CONTAINER_BUILD_VOLUME_NAME + ":" + NativeImageBuildStep.CONTAINER_BUILD_VOLUME_PATH);
return containerRuntimeArgs;
}
}

0 comments on commit 01953a7

Please sign in to comment.