Skip to content

Commit 6230392

Browse files
committed
Respect image platform when exporting buildpack layers
Ensure the builder propagates the requested image platform to DockerApi.exportLayers so Docker 1.41+ saves layers for the pulled architecture rather than the host default. Add platform-aware tests issue: #46665 Signed-off-by: hojooo <ghwn5833@gmail.com>
1 parent c417d2e commit 6230392

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ public Image fetchImage(ImageReference reference, ImageType imageType) throws IO
355355
@Override
356356
public void exportImageLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)
357357
throws IOException {
358-
Builder.this.docker.image().exportLayers(reference, exports);
358+
Builder.this.docker.image().exportLayers(reference, this.imageFetcher.defaultPlatform, exports);
359359
}
360360

361361
}

buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,24 @@ public void load(ImageArchive archive, UpdateListener<LoadImageUpdateEvent> list
311311
*/
312312
public void exportLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)
313313
throws IOException {
314+
exportLayers(reference, null, exports);
315+
}
316+
317+
/**
318+
* Export the layers of an image as {@link TarArchive TarArchives}.
319+
* @param reference the reference to export
320+
* @param platform the platform (os/architecture/variant) of the image to export
321+
* @param exports a consumer to receive the layers (contents can only be accessed
322+
* during the callback)
323+
* @throws IOException on IO error
324+
*/
325+
public void exportLayers(ImageReference reference, @Nullable ImagePlatform platform,
326+
IOBiConsumer<String, TarArchive> exports) throws IOException {
314327
Assert.notNull(reference, "'reference' must not be null");
315328
Assert.notNull(exports, "'exports' must not be null");
316-
URI uri = buildUrl("/images/" + reference + "/get");
329+
URI uri = (platform != null)
330+
? buildUrl(PLATFORM_API_VERSION, "/images/" + reference + "/get", "platform", platform)
331+
: buildUrl("/images/" + reference + "/get");
317332
try (Response response = http().get(uri)) {
318333
try (ExportedImageTar exportedImageTar = new ExportedImageTar(reference, response.getContent())) {
319334
exportedImageTar.exportLayers(exports);

buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,38 @@ void exportLayersWithSymlinksExportsLayerTars() throws Exception {
447447
.containsExactly("/cnb/stack.toml");
448448
}
449449

450+
@Test
451+
void exportLayersWithPlatformExportsLayerTars() throws Exception {
452+
ImageReference reference = ImageReference.of("docker.io/paketobuildpacks/builder:base");
453+
ImagePlatform platform = ImagePlatform.of("linux/amd64");
454+
URI exportUri = new URI(
455+
PLATFORM_IMAGES_URL + "/docker.io/paketobuildpacks/builder:base/get?platform=linux%2Famd64");
456+
given(DockerApiTests.this.http.head(eq(new URI(PING_URL))))
457+
.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, "1.41")));
458+
given(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf("export.tar"));
459+
MultiValueMap<String, String> contents = new LinkedMultiValueMap<>();
460+
this.api.exportLayers(reference, platform, (name, archive) -> {
461+
ByteArrayOutputStream out = new ByteArrayOutputStream();
462+
archive.writeTo(out);
463+
try (TarArchiveInputStream in = new TarArchiveInputStream(
464+
new ByteArrayInputStream(out.toByteArray()))) {
465+
TarArchiveEntry entry = in.getNextEntry();
466+
while (entry != null) {
467+
contents.add(name, entry.getName());
468+
entry = in.getNextEntry();
469+
}
470+
}
471+
});
472+
assertThat(contents).hasSize(3)
473+
.containsKeys("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar",
474+
"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar",
475+
"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar");
476+
assertThat(contents.get("70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar"))
477+
.containsExactly("/cnb/order.toml");
478+
assertThat(contents.get("74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar"))
479+
.containsExactly("/cnb/stack.toml");
480+
}
481+
450482
@Test
451483
void tagWhenReferenceIsNullThrowsException() {
452484
ImageReference tag = ImageReference.of("localhost:5000/ubuntu");

0 commit comments

Comments
 (0)