Skip to content

Commit a05bcd1

Browse files
[1457] pull cacheFrom images during build (#1463)
* [1457] pull cacheFrom images during build * [1457] remove star imports
1 parent ee65068 commit a05bcd1

File tree

4 files changed

+94
-40
lines changed

4 files changed

+94
-40
lines changed

doc/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Update documentation to clearly state that `docker.cacheFrom.idx` is a _list_ property and should always be used with a `idx` suffix. With this change, `docker.cacheFrom` (without _idx_) is not considered anymore.
77
- A placeholder in docker.image.tag isn't replaced by the final result when used during docker:build ([1468](https://github.com/fabric8io/docker-maven-plugin/issues/1468))
88
- Add a property(`outputFile`) to dump the output of Docker commands to file ([1472]https://github.com/fabric8io/docker-maven-plugin/pull/1472)
9+
- Add pulling of `cacheFrom` images during build ([1457](https://github.com/fabric8io/docker-maven-plugin/issues/1457))
910

1011
* **0.35.0** (2021-04-04)
1112
- Building 'spring-boot-with-jib' sample fails with NoSuchMethodError ([1384](https://github.com/fabric8io/docker-maven-plugin/issues/1384))

src/main/asciidoc/inc/build/_configuration.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ a| Scan the archive specified in `dockerArchive` and find the actual repository
9696
| Squash newly built layers into a single new layer. This can be overwritten by setting a system property `docker.squash` when running Maven.
9797

9898
| *cacheFrom*
99-
| A list of `<image>` elements specifying image names to use as cache sources.
99+
| A list of `<image>` elements specifying image names to use as cache sources. During image build, it will attempt to pull these images, but not fail the build. Follows `imagePullPolicy` semantics.
100100

101101
| *optimise*
102102
| if set to true then it will compress all the `runCmds` into a single `RUN` directive so that only one image layer is created.

src/main/java/io/fabric8/maven/docker/service/BuildService.java

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,8 @@
11
package io.fabric8.maven.docker.service;
22

3-
import java.io.File;
4-
import java.io.IOException;
5-
import java.io.Serializable;
6-
import java.nio.file.Files;
7-
import java.util.Collections;
8-
import java.util.HashMap;
9-
import java.util.LinkedList;
10-
import java.util.List;
11-
import java.util.Map;
12-
import java.util.Properties;
13-
import java.util.regex.PatternSyntaxException;
14-
15-
import org.apache.maven.plugin.MojoExecutionException;
163
import com.google.common.collect.ImmutableMap;
174
import com.google.gson.JsonObject;
185
import com.google.gson.JsonParseException;
19-
206
import io.fabric8.maven.docker.access.BuildOptions;
217
import io.fabric8.maven.docker.access.DockerAccess;
228
import io.fabric8.maven.docker.access.DockerAccessException;
@@ -34,6 +20,19 @@
3420
import io.fabric8.maven.docker.util.Logger;
3521
import io.fabric8.maven.docker.util.MojoParameters;
3622
import io.fabric8.maven.docker.util.NamePatternUtil;
23+
import org.apache.maven.plugin.MojoExecutionException;
24+
25+
import java.io.File;
26+
import java.io.IOException;
27+
import java.io.Serializable;
28+
import java.nio.file.Files;
29+
import java.util.Collections;
30+
import java.util.HashMap;
31+
import java.util.LinkedList;
32+
import java.util.List;
33+
import java.util.Map;
34+
import java.util.Properties;
35+
import java.util.regex.PatternSyntaxException;
3736

3837
public class BuildService {
3938

@@ -56,7 +55,7 @@ public class BuildService {
5655
/**
5756
* Pull the base image if needed and run the build.
5857
*
59-
* @param imageConfig the image configuration
58+
* @param imageConfig the image configuration
6059
* @param buildContext the build context
6160
* @throws DockerAccessException
6261
* @throws MojoExecutionException
@@ -66,6 +65,7 @@ public void buildImage(ImageConfiguration imageConfig, ImagePullManager imagePul
6665

6766
if (imagePullManager != null) {
6867
autoPullBaseImage(imageConfig, imagePullManager, buildContext);
68+
autoPullCacheFromImage(imageConfig, imagePullManager, buildContext);
6969
}
7070

7171
buildImage(imageConfig, buildContext.getMojoParameters(), checkForNocache(imageConfig), checkForSquash(imageConfig), addBuildArgs(buildContext), buildArchiveFile);
@@ -75,9 +75,9 @@ public void buildImage(ImageConfiguration imageConfig, ImagePullManager imagePul
7575
* Create docker archive for building image
7676
*
7777
* @param imageConfiguration image configuration
78-
* @param buildContext docker build context
79-
* @param archivePath build archive only flag, it can have values TRUE or FALSE and also
80-
* it can hold path to archive where it might get copied over
78+
* @param buildContext docker build context
79+
* @param archivePath build archive only flag, it can have values TRUE or FALSE and also
80+
* it can hold path to archive where it might get copied over
8181
* @return tarball for docker image
8282
* @throws MojoExecutionException in case any exception comes during building tarball
8383
*/
@@ -130,9 +130,9 @@ public void tagImage(ImageConfiguration imageConfig) throws DockerAccessExceptio
130130
* Build an image
131131
*
132132
* @param imageConfig the image configuration
133-
* @param params mojo params for the project
134-
* @param noCache if not null, dictate the caching behaviour. Otherwise its taken from the build configuration
135-
* @param buildArgs docker build args
133+
* @param params mojo params for the project
134+
* @param noCache if not null, dictate the caching behaviour. Otherwise its taken from the build configuration
135+
* @param buildArgs docker build args
136136
* @throws DockerAccessException
137137
* @throws MojoExecutionException
138138
*/
@@ -160,7 +160,7 @@ protected void buildImage(ImageConfiguration imageConfig, MojoParameters params,
160160
docker.loadImage(imageName, tarArchive);
161161
log.info("%s: Loaded tarball in %s", buildConfig.getDockerArchive(), EnvUtil.formatDurationTill(time));
162162

163-
if(archiveImageName != null && !archiveImageName.equals(imageName)) {
163+
if (archiveImageName != null && !archiveImageName.equals(imageName)) {
164164
docker.tag(archiveImageName, imageName, true);
165165
}
166166

@@ -214,7 +214,7 @@ private Map<String, String> prepareBuildArgs(Map<String, String> buildArgs, Buil
214214
}
215215

216216
private String getArchiveImageName(BuildImageConfiguration buildConfig, File tarArchive) throws MojoExecutionException {
217-
if(buildConfig.getLoadNamePattern() == null || buildConfig.getLoadNamePattern().length() == 0) {
217+
if (buildConfig.getLoadNamePattern() == null || buildConfig.getLoadNamePattern().length() == 0) {
218218
return null;
219219
}
220220

@@ -229,11 +229,11 @@ private String getArchiveImageName(BuildImageConfiguration buildConfig, File tar
229229

230230
try {
231231
archiveImageName = matchArchiveImagesToPattern(buildConfig.getLoadNamePattern(), manifest);
232-
} catch(PatternSyntaxException e) {
232+
} catch (PatternSyntaxException e) {
233233
throw new MojoExecutionException("Unable to interpret loadNamePattern " + buildConfig.getLoadNamePattern(), e);
234234
}
235235

236-
if(archiveImageName == null) {
236+
if (archiveImageName == null) {
237237
throw new MojoExecutionException("No image in the archive has a tag that matches pattern " + buildConfig.getLoadNamePattern());
238238
}
239239

@@ -248,10 +248,10 @@ private ImageArchiveManifest readArchiveManifest(File tarArchive) throws IOExcep
248248
log.info("%s: Read archive manifest in %s", tarArchive, EnvUtil.formatDurationTill(time));
249249

250250
// Show the results of reading the manifest to users trying to debug their configuration
251-
if(log.isDebugEnabled()) {
252-
for(ImageArchiveManifestEntry entry : manifest.getEntries()) {
251+
if (log.isDebugEnabled()) {
252+
for (ImageArchiveManifestEntry entry : manifest.getEntries()) {
253253
log.debug("Entry ID: %s has %d repo tag(s)", entry.getId(), entry.getRepoTags().size());
254-
for(String repoTag : entry.getRepoTags()) {
254+
for (String repoTag : entry.getRepoTags()) {
255255
log.debug("Repo Tag: %s", repoTag);
256256
}
257257
}
@@ -267,16 +267,16 @@ private String matchArchiveImagesToPattern(String imageNamePattern, ImageArchive
267267
Map<String, ImageArchiveManifestEntry> entries = ImageArchiveUtil.findEntriesByRepoTagPattern(imageNameRegex, manifest);
268268

269269
// Show the matches from the manifest to users trying to debug their configuration
270-
if(log.isDebugEnabled()) {
271-
for(Map.Entry<String, ImageArchiveManifestEntry> entry : entries.entrySet()) {
270+
if (log.isDebugEnabled()) {
271+
for (Map.Entry<String, ImageArchiveManifestEntry> entry : entries.entrySet()) {
272272
log.debug("Repo tag pattern matched %s referring to image %s", entry.getKey(), entry.getValue().getId());
273273
}
274274
}
275275

276-
if(!entries.isEmpty()) {
276+
if (!entries.isEmpty()) {
277277
Map.Entry<String, ImageArchiveManifestEntry> matchedEntry = entries.entrySet().iterator().next();
278278

279-
if(ImageArchiveUtil.mapEntriesById(entries.values()).size() > 1) {
279+
if (ImageArchiveUtil.mapEntriesById(entries.values()).size() > 1) {
280280
log.warn("Multiple image ids matched pattern %s: using tag %s associated with id %s",
281281
imageNamePattern, matchedEntry.getKey(), matchedEntry.getValue().getId());
282282
} else {
@@ -344,16 +344,16 @@ private Map<String, String> addBuildArgsFromDockerConfig() {
344344
JsonObject proxies = dockerConfig.getAsJsonObject("proxies");
345345
if (proxies.has("default")) {
346346
JsonObject defaultProxyObj = proxies.getAsJsonObject("default");
347-
String[] proxyMapping = new String[] {
347+
String[] proxyMapping = new String[]{
348348
"httpProxy", "http_proxy",
349349
"httpsProxy", "https_proxy",
350350
"noProxy", "no_proxy",
351351
"ftpProxy", "ftp_proxy"
352352
};
353353

354-
for(int index = 0; index < proxyMapping.length; index += 2) {
354+
for (int index = 0; index < proxyMapping.length; index += 2) {
355355
if (defaultProxyObj.has(proxyMapping[index])) {
356-
buildArgs.put(proxyMapping[index+1], defaultProxyObj.get(proxyMapping[index]).getAsString());
356+
buildArgs.put(proxyMapping[index + 1], defaultProxyObj.get(proxyMapping[index]).getAsString());
357357
}
358358
}
359359
}
@@ -377,7 +377,7 @@ private void autoPullBaseImage(ImageConfiguration imageConfig, ImagePullManager
377377
} else {
378378
fromImages = new LinkedList<>();
379379
String baseImage = extractBaseFromConfiguration(buildConfig);
380-
if (baseImage!=null) {
380+
if (baseImage != null) {
381381
fromImages.add(extractBaseFromConfiguration(buildConfig));
382382
}
383383
}
@@ -388,6 +388,20 @@ private void autoPullBaseImage(ImageConfiguration imageConfig, ImagePullManager
388388
}
389389
}
390390

391+
private void autoPullCacheFromImage(ImageConfiguration imageConfig, ImagePullManager imagePullManager, BuildContext buildContext) throws MojoExecutionException {
392+
if (imageConfig.getBuildConfiguration().getCacheFrom() == null) {
393+
return;
394+
}
395+
396+
for (String cacheFromImage : imageConfig.getBuildConfiguration().getCacheFrom()) {
397+
try {
398+
registryService.pullImageWithPolicy(cacheFromImage, imagePullManager, buildContext.getRegistryConfig(), queryService.hasImage(cacheFromImage));
399+
} catch (DockerAccessException e) {
400+
log.warn("Could not pull cacheFrom image: '%s'. Reason: %s", cacheFromImage, e.getMessage());
401+
}
402+
}
403+
}
404+
391405
private String extractBaseFromConfiguration(BuildImageConfiguration buildConfig) {
392406
String fromImage;
393407
fromImage = buildConfig.getFrom();
@@ -405,9 +419,9 @@ private List<String> extractBaseFromDockerfile(BuildImageConfiguration buildConf
405419
try {
406420
File fullDockerFilePath = buildConfig.getAbsoluteDockerFilePath(buildContext.getMojoParameters());
407421
fromImage = DockerFileUtil.extractBaseImages(
408-
fullDockerFilePath,
409-
DockerFileUtil.createInterpolator(buildContext.getMojoParameters(), buildConfig.getFilter()),
410-
buildConfig.getArgs());
422+
fullDockerFilePath,
423+
DockerFileUtil.createInterpolator(buildContext.getMojoParameters(), buildConfig.getFilter()),
424+
buildConfig.getArgs());
411425
} catch (IOException e) {
412426
// Cant extract base image, so we wont try an auto pull. An error will occur later anyway when
413427
// building the image, so we are passive here.

src/test/java/io/fabric8/maven/docker/service/BuildServiceTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,45 @@ public void testMultiStageBuild() throws Exception {
153153
}};
154154
}
155155

156+
@Test
157+
public void testBuildImageWithCacheFrom_ShouldPullImage() throws Exception {
158+
BuildImageConfiguration buildConfig = new BuildImageConfiguration.Builder()
159+
.cleanup("false")
160+
.cacheFrom("fabric8/s1i-java")
161+
.dockerFile(DockerFileUtilTest.class.getResource("Dockerfile_from_simple").getPath())
162+
.filter("false")
163+
.build();
164+
165+
buildConfig.initAndValidate(logger);
166+
167+
imageConfig = new ImageConfiguration.Builder()
168+
.name("build-image")
169+
.alias("build-alias")
170+
.buildConfig(buildConfig)
171+
.build();
172+
173+
final ImagePullManager pullManager = new ImagePullManager(null,null, null);
174+
final BuildService.BuildContext buildContext = new BuildService.BuildContext.Builder()
175+
.mojoParameters(mojoParameters)
176+
.build();
177+
178+
new Expectations(mojoParameters) {{
179+
mojoParameters.getProject(); result = mavenProject;
180+
mavenProject.getProperties(); result = new Properties();
181+
}};
182+
183+
File buildArchive = buildService.buildArchive(imageConfig, buildContext, "");
184+
buildService.buildImage(imageConfig, pullManager, buildContext, buildArchive);
185+
186+
//verify that tries to pull both images
187+
new Verifications() {{
188+
queryService.hasImage("fabric8/s2i-java");
189+
registryService.pullImageWithPolicy("fabric8/s2i-java", pullManager, buildContext.getRegistryConfig(), false);
190+
queryService.hasImage("fabric8/s1i-java");
191+
registryService.pullImageWithPolicy("fabric8/s1i-java", pullManager, buildContext.getRegistryConfig(), false);
192+
}};
193+
}
194+
156195
@Test
157196
public void testDockerBuildArchiveOnly() throws Exception {
158197
givenAnImageConfiguration(true);

0 commit comments

Comments
 (0)