Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of docker multi stage builds #1057

Merged
merged 6 commits into from
Apr 6, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/main/java/io/fabric8/maven/docker/service/BuildService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.LinkedList;

import io.fabric8.maven.docker.access.BuildOptions;
import io.fabric8.maven.docker.access.DockerAccess;
Expand Down Expand Up @@ -199,14 +200,20 @@ private void autoPullBaseImage(ImageConfiguration imageConfig, ImagePullManager
return;
}

String fromImage;
List<String> fromImages;
if (buildConfig.isDockerFileMode()) {
fromImage = extractBaseFromDockerfile(buildConfig, buildContext);
fromImages = extractBaseFromDockerfile(buildConfig, buildContext);
} else {
fromImage = extractBaseFromConfiguration(buildConfig);
fromImages = new LinkedList<>();
String baseImage = extractBaseFromConfiguration(buildConfig);
if (baseImage!=null) {
fromImages.add(extractBaseFromConfiguration(buildConfig));
}
}
if (fromImage != null && !DockerAssemblyManager.SCRATCH_IMAGE.equals(fromImage)) {
registryService.pullImageWithPolicy(fromImage, imagePullManager, buildContext.getRegistryConfig(), queryService.hasImage(fromImage));
for (String fromImage : fromImages) {
if (fromImage != null && !DockerAssemblyManager.SCRATCH_IMAGE.equals(fromImage)) {
registryService.pullImageWithPolicy(fromImage, imagePullManager, buildContext.getRegistryConfig(), queryService.hasImage(fromImage));
}
}
}

Expand All @@ -222,17 +229,17 @@ private String extractBaseFromConfiguration(BuildImageConfiguration buildConfig)
return fromImage;
}

private String extractBaseFromDockerfile(BuildImageConfiguration buildConfig, BuildContext buildContext) {
String fromImage;
private List<String> extractBaseFromDockerfile(BuildImageConfiguration buildConfig, BuildContext buildContext) {
List<String> fromImage;
try {
File fullDockerFilePath = buildConfig.getAbsoluteDockerFilePath(buildContext.getMojoParameters());
fromImage = DockerFileUtil.extractBaseImage(
fromImage = DockerFileUtil.extractBaseImages(
fullDockerFilePath,
DockerFileUtil.createInterpolator(buildContext.getMojoParameters(), buildConfig.getFilter()));
} catch (IOException e) {
// Cant extract base image, so we wont try an auto pull. An error will occur later anyway when
// building the image, so we are passive here.
fromImage = null;
return Collections.emptyList();
}
return fromImage;
}
Expand Down
26 changes: 21 additions & 5 deletions src/main/java/io/fabric8/maven/docker/util/DockerFileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -43,16 +44,31 @@ private DockerFileUtil() {}
*
* @param dockerFile file from where to extract the base image
* @param interpolator interpolator for replacing properties
* @deprecated Use {@link DockerFileUtil#extractBaseImages} extractBaseImages instead
*/
@Deprecated
public static String extractBaseImage(File dockerFile, FixedStringSearchInterpolator interpolator) throws IOException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INFO Do not forget to remove this deprecated code someday. rule

List<String> result = extractBaseImages(dockerFile, interpolator);
return result.isEmpty() ? null : result.iterator().next();
}

/**
* Extract the base images from a dockerfile. All lines containing a <code>FROM</code> is
* taken.
*
* @param dockerFile file from where to extract the base image
* @param interpolator interpolator for replacing properties
* @return LinkedList of base images name or empty collection if none is found.
*/
public static List<String> extractBaseImages(File dockerFile, FixedStringSearchInterpolator interpolator) throws IOException {
List<String[]> fromLines = extractLines(dockerFile, "FROM", interpolator);
if (!fromLines.isEmpty()) {
String[] parts = fromLines.get(0);
if (parts.length > 1) {
return parts[1];
LinkedList<String> result = new LinkedList<>();
for (String[] fromLine : fromLines) {
if (fromLine.length > 1) {
result.add(fromLine[1]);
}
}
return null;
return result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import java.io.File;
import java.util.Collections;

import java.util.Properties;


import io.fabric8.maven.docker.access.BuildOptions;
import io.fabric8.maven.docker.access.DockerAccess;
import io.fabric8.maven.docker.access.DockerAccessException;
import io.fabric8.maven.docker.assembly.DockerAssemblyManager;
import io.fabric8.maven.docker.config.BuildImageConfiguration;
import io.fabric8.maven.docker.util.DockerFileUtilTest;
import io.fabric8.maven.docker.config.ImageConfiguration;
import io.fabric8.maven.docker.util.Logger;
import io.fabric8.maven.docker.util.MojoParameters;
Expand All @@ -18,6 +22,7 @@
import mockit.Tested;
import mockit.Verifications;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.junit.Before;
import org.junit.Test;

Expand Down Expand Up @@ -46,6 +51,15 @@ public class BuildServiceTest {
@Mocked
private MojoParameters params;

@Mocked
Logger logger;

@Mocked
MojoParameters mojoParameters;

@Mocked
MavenProject mavenProject;

@Injectable
private QueryService queryService;

Expand Down Expand Up @@ -99,6 +113,43 @@ public void testCleanupNoExistingImage() throws Exception {
thenOldImageIsNotRemoved();
}

@Test
public void testMultiStageBuild() throws Exception {
BuildImageConfiguration buildConfig = new BuildImageConfiguration.Builder()
.cleanup("false")
.dockerFile(DockerFileUtilTest.class.getResource("Dockerfile_multi_stage").getPath())
.filter("false")
.build();

buildConfig.initAndValidate(logger);

imageConfig = new ImageConfiguration.Builder()
.name("build-image")
.alias("build-alias")
.buildConfig(buildConfig)
.build();

final ImagePullManager pullManager = new ImagePullManager(null,null, null);
final BuildService.BuildContext buildContext = new BuildService.BuildContext.Builder()
.mojoParameters(mojoParameters)
.build();

new Expectations(mojoParameters) {{
mojoParameters.getProject(); result = mavenProject;
mavenProject.getProperties(); result = new Properties();
}};

buildService.buildImage(imageConfig, pullManager, buildContext);

//verify that tries to pull both images
new Verifications() {{
queryService.hasImage("fabric8/s2i-java");
registryService.pullImageWithPolicy("fabric8/s2i-java", pullManager, buildContext.getRegistryConfig(), false);
queryService.hasImage("fabric8/s1i-java");
registryService.pullImageWithPolicy("fabric8/s1i-java", pullManager, buildContext.getRegistryConfig(), false);
}};
}

private void givenAnImageConfiguration(Boolean cleanup) {
BuildImageConfiguration buildConfig = new BuildImageConfiguration.Builder()
.cleanup(cleanup.toString())
Expand Down
17 changes: 12 additions & 5 deletions src/test/java/io/fabric8/maven/docker/util/DockerFileUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@

import java.io.*;
import java.nio.file.Files;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.*;

import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
Expand Down Expand Up @@ -52,6 +48,17 @@ public void testSimple() throws Exception {
toTest, FixedStringSearchInterpolator.create()));
}

@Test
public void testMultiStage() throws Exception {
File toTest = copyToTempDir("Dockerfile_multi_stage");
Iterator<String> fromClauses = DockerFileUtil.extractBaseImages(
toTest, FixedStringSearchInterpolator.create()).iterator();

assertEquals("fabric8/s2i-java", fromClauses.next());
assertEquals("fabric8/s1i-java", fromClauses.next());
assertEquals(false, fromClauses.hasNext());
}

private File copyToTempDir(String resource) throws IOException {
File dir = Files.createTempDirectory("d-m-p").toFile();
File ret = new File(dir, "Dockerfile");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Dockerfile with a multi FROM clause
# see https://docs.docker.com/develop/develop-images/multistage-build/

FROM fabric8/s2i-java

FROM fabric8/s1i-java