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

fix: no match for platform in manifest when containerd is enabled #9200

Merged

Conversation

monosoul
Copy link
Contributor

@monosoul monosoul commented Sep 9, 2024

Given a Docker image that only has linux/amd64 as a platform

When I try to pull it with testcontainers on an ARM Mac

Then I should be able to pull it without any problem

Current behavior:
Trying to pull such an image causes com.github.dockerjava.api.exception.NotFoundException.
If the image manifest in the registry doesn't contain the platform it is pulled for, the registry will return 404 with the following body: {"message":"no match for platform in manifest: not found"}. Docker-java will throw com.github.dockerjava.api.exception.NotFoundException in such case (instead of DockerClientException), so the fallback to x86 will never be attempted.

This change fixes that. I didn't dig into how to write a proper test for that and I didn't find any tests covering the exception scenario, unfortunately. Nevertheless, this will make the fallback actually work, I built it locally with the patch and confirmed it works.

Fixes #9214

@eddumelendez
Copy link
Member

I've used redis:3.2.4-alpine using Docker Desktop for Mac M1 and the image has been downloaded and test executed successfully.

Do you have a public image to reproduce the issue?

@monosoul
Copy link
Contributor Author

monosoul commented Sep 11, 2024

Yes, gradle:8.6.0-jdk17-alpine.

Here's a simple reproducer in Kotlin:

import org.testcontainers.images.RemoteDockerImage
import org.testcontainers.utility.DockerImageName

fun main() {
    RemoteDockerImage(
        DockerImageName.parse("gradle:8.6.0-jdk17-alpine")
    ).get()
}

@eddumelendez
Copy link
Member

Thanks for sharing, @monosoul. However, I am not able to reproduce it on my MAC M1 using Docker Desktop and Testcontainers 1.20.1. The same image has been downloaded successfully

@Test
void test() throws IOException, InterruptedException {
	new RemoteDockerImage(DockerImageName.parse("gradle:8.6.0-jdk17-alpine")).get();
	try (final GenericContainer<?> redis = new GenericContainer<>("gradle:8.6.0-jdk17-alpine")
			.withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("sh", "-c", "while true; do sleep 1; done"))) {
		redis.start();
		org.testcontainers.containers.Container.ExecResult ping = redis.execInContainer("gradle", "help");
		System.out.println(ping.getStdout());
	}
}

output:

15:28:16.303 INFO  org.testcontainers.utility.ImageNameSubstitutor - Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
15:28:16.475 WARN  org.testcontainers.dockerclient.DockerClientProviderStrategy - DOCKER_HOST tcp://127.0.0.1:51412 is not listening
15:28:16.477 WARN  org.testcontainers.dockerclient.DockerClientProviderStrategy - DOCKER_HOST tcp://127.0.0.1:51412 is not listening
15:28:16.616 INFO  org.testcontainers.dockerclient.DockerClientProviderStrategy - Found Docker environment with Docker accessed via Unix socket (/Users/eddumelendez/.docker/run/docker.sock)
15:28:16.617 INFO  org.testcontainers.DockerClientFactory - Docker host IP address is localhost
15:28:16.637 INFO  org.testcontainers.DockerClientFactory - Connected to docker: 
  Server Version: 27.2.1
  API Version: 1.47
  Operating System: Docker Desktop
  Total Memory: 9937 MB
15:28:16.646 INFO  org.testcontainers.DockerClientFactory - Checking the system...
15:28:16.646 INFO  org.testcontainers.DockerClientFactory - ✔︎ Docker server version should be at least 1.6.0
15:28:16.666 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling docker image: gradle:8.6.0-jdk17-alpine. Please be patient; this may take some time but only needs to be done once.
15:28:18.010 INFO  tc.gradle:8.6.0-jdk17-alpine - Starting to pull image
15:28:18.027 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  0 pending,  0 downloaded,  0 extracted, (0 bytes/0 bytes)
15:28:19.155 INFO  tc.gradle:8.6.0-jdk17-alpine - Starting to pull image
15:28:19.156 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  0 pending,  0 downloaded,  0 extracted, (0 bytes/0 bytes)
15:28:21.374 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  8 pending,  1 downloaded,  0 extracted, (13 MB/? MB)
15:28:21.586 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  7 pending,  2 downloaded,  0 extracted, (16 MB/? MB)
15:28:21.701 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  7 pending,  2 downloaded,  1 extracted, (18 MB/? MB)
15:28:22.106 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  7 pending,  2 downloaded,  2 extracted, (23 MB/? MB)
15:28:22.254 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  6 pending,  3 downloaded,  2 extracted, (23 MB/? MB)
15:28:22.426 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  5 pending,  4 downloaded,  2 extracted, (26 MB/? MB)
15:28:23.484 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  4 pending,  5 downloaded,  2 extracted, (40 MB/? MB)
15:28:28.936 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  3 pending,  6 downloaded,  2 extracted, (129 MB/? MB)
15:28:29.667 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  2 pending,  7 downloaded,  2 extracted, (140 MB/? MB)
15:28:35.548 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  1 pending,  8 downloaded,  2 extracted, (241 MB/? MB)
15:28:36.738 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  1 pending,  8 downloaded,  3 extracted, (256 MB/? MB)
15:28:36.748 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  1 pending,  8 downloaded,  4 extracted, (256 MB/? MB)
15:28:36.757 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  1 pending,  8 downloaded,  5 extracted, (256 MB/? MB)
15:28:36.765 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  1 pending,  8 downloaded,  6 extracted, (256 MB/? MB)
15:28:37.599 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  1 pending,  8 downloaded,  7 extracted, (270 MB/? MB)
15:28:41.853 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  0 pending,  9 downloaded,  7 extracted, (312 MB/313 MB)
15:28:42.559 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  0 pending,  9 downloaded,  8 extracted, (313 MB/313 MB)
15:28:42.568 INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling image layers:  0 pending,  9 downloaded,  9 extracted, (313 MB/313 MB)
15:28:42.579 INFO  tc.gradle:8.6.0-jdk17-alpine - Pull complete. 9 layers, pulled in 23s (downloaded 313 MB at 13 MB/s)
15:28:42.617 INFO  tc.gradle:8.6.0-jdk17-alpine - Creating container for image: gradle:8.6.0-jdk17-alpine
15:28:42.625 INFO  tc.testcontainers/ryuk:0.5.1 - Creating container for image: testcontainers/ryuk:0.5.1
15:28:43.202 INFO  tc.testcontainers/ryuk:0.5.1 - Container testcontainers/ryuk:0.5.1 is starting: 2a4d04b2c15d6c54e995e1ff9fb10240f461e536e96809d0bb205d3c3109dc90
15:28:43.449 INFO  tc.testcontainers/ryuk:0.5.1 - Container testcontainers/ryuk:0.5.1 started in PT0.824286S
15:28:43.480 INFO  tc.gradle:8.6.0-jdk17-alpine - Container gradle:8.6.0-jdk17-alpine is starting: d72650bb902e14c508a04a7d732c2971c81fa841a26ab46709242de81c13fb9d
15:28:43.636 WARN  tc.gradle:8.6.0-jdk17-alpine - The architecture 'amd64' for image 'gradle:8.6.0-jdk17-alpine' (ID sha256:ddf72ac70d67a3d311e8a7117c0926b45a62aeff013c40968bd2829408d5544c) does not match the Docker server architecture 'arm64'. This will cause the container to execute much more slowly due to emulation and may lead to timeout failures.
15:28:43.636 INFO  tc.gradle:8.6.0-jdk17-alpine - Container gradle:8.6.0-jdk17-alpine started in PT1.021259S

Welcome to Gradle 8.6!

Here are the highlights of this release:
 - Configurable encryption key for configuration cache
 - Build init improvements
 - Build authoring improvements

For more details see https://docs.gradle.org/8.6/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :help

Welcome to Gradle 8.6.

Directory '/home/gradle' does not contain a Gradle build.

To create a new build in this directory, run gradle init

For more detail on the 'init' task, see https://docs.gradle.org/8.6/userguide/build_init_plugin.html

For more detail on creating a Gradle build, see https://docs.gradle.org/8.6/userguide/tutorial_using_tasks.html

To see a list of command-line options, run gradle --help

For more detail on using Gradle, see https://docs.gradle.org/8.6/userguide/command_line_interface.html

For troubleshooting, visit https://help.gradle.org

BUILD SUCCESSFUL in 6s
1 actionable task: 1 executed

Logs show The architecture 'amd64' for image 'gradle:8.6.0-jdk17-alpine' (ID sha256:ddf72ac70d67a3d311e8a7117c0926b45a62aeff013c40968bd2829408d5544c) does not match the Docker server architecture 'arm64'. This will cause the container to execute much more slowly due to emulation and may lead to timeout failures. which confirms that the image is amd64 and the host is arm64

@monosoul
Copy link
Contributor Author

monosoul commented Sep 11, 2024

This is what I get trying to run the same test 🤔

23:44:13.157 [main] INFO  o.testcontainers.images.PullPolicy - Image pull policy will be performed by: DefaultPullPolicy() | MDC: []
23:44:13.162 [main] INFO  o.t.utility.ImageNameSubstitutor - Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor') | MDC: []
23:44:13.166 [main] INFO  o.testcontainers.DockerClientFactory - Testcontainers version: 1.20.1 | MDC: []
23:44:13.265 [main] INFO  o.t.d.DockerClientProviderStrategy - Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first | MDC: []
23:44:13.375 [main] INFO  o.t.d.DockerClientProviderStrategy - Found Docker environment with local Unix socket (unix:///var/run/docker.sock) | MDC: []
23:44:13.375 [main] INFO  o.testcontainers.DockerClientFactory - Docker host IP address is localhost | MDC: []
23:44:13.387 [main] INFO  o.testcontainers.DockerClientFactory - Connected to docker: 
  Server Version: 27.2.0
  API Version: 1.47
  Operating System: Docker Desktop
  Total Memory: 7839 MB | MDC: []
23:44:13.461 [main] INFO  tc.testcontainers/ryuk:0.8.1 - Creating container for image: testcontainers/ryuk:0.8.1 | MDC: []
23:44:13.542 [main] INFO  tc.testcontainers/ryuk:0.8.1 - Container testcontainers/ryuk:0.8.1 is starting: 8ae387d210c7b9ff13a01e1418fc6f0c968843d7d96d437b4796bd3263f10183 | MDC: []
23:44:13.709 [main] INFO  tc.testcontainers/ryuk:0.8.1 - Container testcontainers/ryuk:0.8.1 started in PT0.248709S | MDC: []
23:44:13.712 [main] INFO  o.t.utility.RyukResourceReaper - Ryuk started - will monitor and terminate Testcontainers containers on JVM exit | MDC: []
23:44:13.712 [main] INFO  o.testcontainers.DockerClientFactory - Checking the system... | MDC: []
23:44:13.712 [main] INFO  o.testcontainers.DockerClientFactory - ✔︎ Docker server version should be at least 1.6.0 | MDC: []
23:44:13.716 [main] INFO  tc.gradle:8.6.0-jdk17-alpine - Pulling docker image: gradle:8.6.0-jdk17-alpine. Please be patient; this may take some time but only needs to be done once. | MDC: []
23:44:15.075 [docker-java-stream-967203167] ERROR c.g.d.a.async.ResultCallbackTemplate - Error during callback | MDC: []
com.github.dockerjava.api.exception.NotFoundException: Status 404: {"message":"no match for platform in manifest: not found"}

	at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.execute(DefaultInvocationBuilder.java:241)
	at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.lambda$executeAndStream$1(DefaultInvocationBuilder.java:269)
	at java.base/java.lang.Thread.run(Thread.java:1583)

com.github.dockerjava.api.exception.NotFoundException: Status 404: {"message":"no match for platform in manifest: not found"}


	at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.execute(DefaultInvocationBuilder.java:241)
	at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.lambda$executeAndStream$1(DefaultInvocationBuilder.java:269)
	at java.base/java.lang.Thread.run(Thread.java:1583)


I have a team license for Docker Desktop, I wonder if it can have anything to do with the error I get.

Here's my docker system info output:

docker system info
Client:
 Version:    27.2.0
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.16.2-desktop.1
    Path:     /Users/monosoul/.docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.29.2-desktop.2
    Path:     /Users/monosoul/.docker/cli-plugins/docker-compose
  debug: Get a shell into any image or container (Docker Inc.)
    Version:  0.0.34
    Path:     /Users/monosoul/.docker/cli-plugins/docker-debug
  desktop: Docker Desktop commands (Alpha) (Docker Inc.)
    Version:  v0.0.15
    Path:     /Users/monosoul/.docker/cli-plugins/docker-desktop
  dev: Docker Dev Environments (Docker Inc.)
    Version:  v0.1.2
    Path:     /Users/monosoul/.docker/cli-plugins/docker-dev
  extension: Manages Docker extensions (Docker Inc.)
    Version:  v0.2.25
    Path:     /Users/monosoul/.docker/cli-plugins/docker-extension
  feedback: Provide feedback, right in your terminal! (Docker Inc.)
    Version:  v1.0.5
    Path:     /Users/monosoul/.docker/cli-plugins/docker-feedback
  init: Creates Docker-related starter files for your project (Docker Inc.)
    Version:  v1.3.0
    Path:     /Users/monosoul/.docker/cli-plugins/docker-init
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc.)
    Version:  0.6.0
    Path:     /Users/monosoul/.docker/cli-plugins/docker-sbom
  scout: Docker Scout (Docker Inc.)
    Version:  v1.13.0
    Path:     /Users/monosoul/.docker/cli-plugins/docker-scout

Server:
 Containers: 2
  Running: 0
  Paused: 0
  Stopped: 2
 Images: 9
 Server Version: 27.2.0
 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 8fc6bcff51318944179630522a095cc9dbf9f353
 runc version: v1.1.13-0-g58aa920
 init version: de40ad0
 Security Options:
  seccomp
   Profile: unconfined
  cgroupns
 Kernel Version: 6.10.4-linuxkit
 Operating System: Docker Desktop
 OSType: linux
 Architecture: aarch64
 CPUs: 4
 Total Memory: 7.656GiB
 Name: docker-desktop
 ID: c6fb4e42-ad83-4a51-94e9-09e95867196d
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Labels:
  com.docker.desktop.address=unix:///Users/monosoul/Library/Containers/com.docker.docker/Data/docker-cli.sock
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5555
  127.0.0.0/8
 Live Restore Enabled: false

@eddumelendez
Copy link
Member

The issue happens with containerd. Thanks for sharing the docker info output

@monosoul
Copy link
Contributor Author

@eddumelendez glad we figured it out 🙂

@eddumelendez eddumelendez changed the title fix: no match for platform in manifest fix: no match for platform in manifest when containerd is enabled Sep 11, 2024
@monosoul
Copy link
Contributor Author

@eddumelendez is this okay to merge/release?

@eddumelendez eddumelendez added this to the next milestone Sep 17, 2024
@eddumelendez eddumelendez merged commit f2ed9e0 into testcontainers:main Sep 17, 2024
102 checks passed
@eddumelendez
Copy link
Member

Thanks for your contribution, @monosoul !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: can't pull an image that only has linux/amd64 platform on ARM Mac OS
3 participants