docker-client
docker-client copied to clipboard
ContainerInspect on PortBindings throws NullPointerException on Podman Installation
BUG REPORT or FEATURE REQUEST?: BUG REPORT
Description
we get a NullPointerException when we inspect a podman containers PortBindings.
How to reproduce
we want to inspect the publish ports of a podman container. In the inspect json of the podman container the PortBinding are listet as follows:
"PortBindings": {
"15671/tcp": null,
"15672/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "15672"
}
],
if the port isn't expposed like 15671, a NullPointerException will be thrown
What do you expect
the containerport defined as "null" should be ignored.
What happened instead
containerport defined as "null" is recognized and a NullPointerException is thrown
Software:
-
podman version
: 4.1.1 - Spotify's docker-client version: 6.0.5
Full backtrace
Caused by: jakarta.ws.rs.client.ResponseProcessingException: jakarta.ws.rs.ProcessingException: com.fasterxml.jackson.databind.JsonMappingException: portBindings value
at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 3087] (through reference chain: org.mandas.docker.client.messages.ImmutableContainerInfo$Builder["HostConfig"]->org.mandas.docker.client.messages.ImmutableHostConfig$Builder["PortBindings"])
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:203)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:514)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.method(ClientInvocationBuilder.java:318)
at org.mandas.docker.client.DefaultDockerClient.request(DefaultDockerClient.java:2466)
... 73 more
Caused by: jakarta.ws.rs.ProcessingException: com.fasterxml.jackson.databind.JsonMappingException: portBindings value
at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 3087] (through reference chain: org.mandas.docker.client.messages.ImmutableContainerInfo$Builder["HostConfig"]->org.mandas.docker.client.messages.ImmutableHostConfig$Builder["PortBindings"])
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:254)
at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:90)
at org.jboss.resteasy.specimpl.AbstractBuiltResponse.readEntity(AbstractBuiltResponse.java:256)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:167)
... 76 more
Caused by: com.fasterxml.jackson.databind.JsonMappingException: portBindings value
at [Source: (org.jboss.resteasy.specimpl.AbstractBuiltResponse$InputStreamWrapper); line: 1, column: 3087] (through reference chain: org.mandas.docker.client.messages.ImmutableContainerInfo$Builder["HostConfig"]->org.mandas.docker.client.messages.ImmutableHostConfig$Builder["PortBindings"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:276)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:623)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:611)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:173)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:293)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:217)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:293)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:217)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:2025)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1175)
at com.fasterxml.jackson.jakarta.rs.base.ProviderBase.readFrom(ProviderBase.java:776)
at org.jboss.resteasy.core.interception.jaxrs.AbstractReaderInterceptorContext.readFrom(AbstractReaderInterceptorContext.java:101)
at org.jboss.resteasy.core.interception.jaxrs.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:80)
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:217)
... 79 more
Caused by: java.lang.NullPointerException: portBindings value
at java.base/java.util.Objects.requireNonNull(Objects.java:233)
at org.mandas.docker.client.messages.ImmutableHostConfig$Builder.putAllPortBindings(ImmutableHostConfig.java:7860)
at org.mandas.docker.client.messages.ImmutableHostConfig$Builder.portBindings(ImmutableHostConfig.java:7843)
Hi @3XC1T3D ,
(docker-client does not directly support podman, but it may work for most of the cases)
Could you please post the container's creation command here for me to check how this null
is inserted into the portBinding
construct?
Thanks
Hi @dmandalidis , yes so far docker-client works pretty well with the docker-compatible API of Podman. It seems there are only some edge cases where the responses from Podman are not 100% identical to the Docker responses.
This sample code will start the official RabbitMQ container and then cause the mentioned NullPointerException on inspection of the (successfully) started container
static String podmanEngineUrl = "http://<host>:2375";
public static void main(String[] args) throws DockerException, InterruptedException {
try (DefaultDockerClient dc = new ResteasyDockerClientBuilder()
.uri(URI.create(podmanEngineUrl))
.build()) {
List<Integer> exposedPorts = List.of(5672, 4369, 25672, 15692, 15672, 5673);
Map<String, List<PortBinding>> portBindings = exposedPorts.stream().collect(Collectors.toMap(
port -> port + "/tcp",
port -> List.of(PortBinding.of("0.0.0.0", port))
));
HostConfig hostConfig = HostConfig.builder()
.portBindings(portBindings)
.build();
ContainerConfig containerConfig = ContainerConfig.builder()
.image("rabbitmq:3.9.22-alpine")
.hostConfig(hostConfig)
.tty(true)
// note: if the healthcheck is not given, another NullPointerException will be thrown on inspectContainer()
.healthcheck(ContainerConfig.Healthcheck.builder()
.test(List.of("CMD-SHELL", "${APP_ROOT}/docker-healthcheck.sh")).build())
.exposedPorts(exposedPorts.stream().map(port -> port + "/tcp").collect(Collectors.toList()))
.build();
dc.pull(containerConfig.image());
ContainerCreation container =
dc.createContainer(containerConfig, "rabbitmq");
dc.startContainer(container.id());
Thread.sleep(2000);
dc.inspectContainer(container.id()); // this will throw NPE
}
}
When we compare "docker inspect rabbitmq" vs. "podman inspect rabbitmq", we see the difference at HostConfig->PortBindings, where non-bound ports are ommitted by Docker, but presented with a "null" value by Podman:
"PortBindings": {
"15672/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "15672"
}
],
"15691/tcp": null,
I think Podman should fix this in a future release to comply with the Docker API, however for the current and older versions of Podman, it also seems easy and safe to handle this in the docker-client:
In ImmutableHostConfig.java:7856
adding if (v == null) continue;
should be enough.
Note that a very similar NullPointer problem will occur once you comment out the .healthcheck(...)
line, since the lack of any healthchecks also causes a slight difference in the inspect json. In addAllLog(ImmutableContainerState.java:1296)
, the iterated elements
collection is null. This might be fixed by a preceding null check in ImmutableContainerState.java:1285
as well.
Thanks!
@dmandalidis You might have a look at the commit on my fork (https://github.com/lukaseckert/docker-client/commit/b5e29f5cc6b22dbb98317b52e38ba6aee685a368) which fixes both NullPointerExceptions related to the JSON differences when targeting Podman. With these two little tweaks, we successfully deployed a complex application with many containers on a Podman instance using the docker-client :) Our test involved pulling images, creating networks, and stop/remove/create/start/inspect commands on different containers. (However we did not yet test building images on a remote host or loading and exporting the images)
@dmandalidis did you take a look at the pull request?
Best Regards
@3XC1T3D Sorry, but I wouldn't want to deviate from Docker API. No matter how simple a change might be, it doesn't seem correct to me.