I have a problem while call com.google.firebase.cloud.FirestoreClient.getFirestore()
in a Java Application inside a Quarkus Server which is Running on an Alpine 3.15.4 inside a Docker container.
I have created a small demo. The results are:
Configuration 1
Enable in the docker file
RUN apk update RUN apk --no-cache add curl ca-certificates openjdk11-jre-headless
Results:
init ok
shell fail
Configuration2
Disable in the docker file
#RUN apk update #RUN apk --no-cache add curl ca-certificates openjdk11-jre-headless
Results:
init fail
shell ok
If init fail this error is logged
[de.ibe.DemoResource] (executor-thread-0) getFirestore # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x0000000000003efe, pid=1, tid=142 # # JRE version: OpenJDK Runtime Environment (11.0.15+10) (build 11.0.15+10-alpine-r0) # Java VM: OpenJDK 64-Bit Server VM (11.0.15+10-alpine-r0, mixed mode, tiered, compressed oops, g1 gc, linux-amd64) # Problematic frame: # C 0x0000000000003efe # # No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # An error report file with more information is saved as: # /deployments/hs_err_pid1.log # # If you would like to submit a bug report, please visit: # https://gitlab.alpinelinux.org/alpine/aports/issues # The crash happened outside the Java Virtual Machine in native code. # See problematic frame for where to report the bug.
If shell fail this error is logged
java.io.IOException: Cannot run program "ls": error=2, No such file or directory at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1128) at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1071) at de.ibe.DemoResource.shell(DemoResource.java:72) at de.ibe.DemoResource.demo(DemoResource.java:37)
If found some bug reports e.g.
https://github.com/grpc/grpc-java/issues/8751 (see varpa89 commented on 28 Apr) https://github.com/micrometer-metrics/micrometer/issues/2776
One workaround would be to create two container with different docker files. But I would prefer one container..
Hope someone can held me!
Here is the code of the demo
package de.ibe; import java.io.IOException; import java.io.InputStream; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.jaxrs.PathParam; import com.google.auth.oauth2.GoogleCredentials; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.cloud.FirestoreClient; @Path("/demo") public class DemoResource { private static final Logger LOG = Logger.getLogger(DemoResource.class); @GET @Produces(MediaType.TEXT_PLAIN) @Path("/{command}") public String demo(@PathParam String command) { try { if (command == null || command.equals("")) { return "command null or empty"; } else if (command.equals("init")) { LOG.info("run init"); return this.init(); } else if (command.equals("shell")) { LOG.info("run shell"); return this.shell(); } else { return "unkown command"; } } catch (Exception e) { LOG.error(e); return e.getMessage(); } } private String init() throws IOException { try (InputStream in = this.getClass().getResourceAsStream("/demo-b9aa8a6.json")) { if (in == null) { return "init in is null"; } GoogleCredentials credentials = GoogleCredentials.fromStream(in); LOG.info("options"); FirebaseOptions options = new FirebaseOptions.Builder().setCredentials(credentials).build(); LOG.info("initializeApp"); FirebaseApp.initializeApp(options); LOG.info("getFirestore"); FirestoreClient.getFirestore(); } return "init ok"; } private String shell() { try { final ProcessBuilder builder = new ProcessBuilder("ls"); builder.start(); } catch (IOException e) { e.printStackTrace(); return "shell error"; } return "shell ok"; } }
Docker file
FROM alpine:3.15.4 ARG RUN_JAVA_VERSION=1.3.8 ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' # Install java and the run-java script RUN apk update RUN apk --no-cache add curl ca-certificates openjdk11-jre-headless # init ok but shell false, enable #RUN apk add gcompat #ENV LD_PRELOAD=/lib/libgcompat.so.0 RUN mkdir /deployments RUN chmod "g+rwX" /deployments RUN curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh RUN chmod 540 /deployments/run-java.sh # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" # We make four distinct layers so if there are application changes the library layers can be re-used COPY target/quarkus-app/lib/ /deployments/lib/ COPY target/quarkus-app/*.jar /deployments/ COPY target/quarkus-app/app/ /deployments/app/ COPY target/quarkus-app/quarkus/ /deployments/quarkus/ EXPOSE 8080 ENTRYPOINT [ "/deployments/run-java.sh" ]
Advertisement
Answer
I was not able to solve the problem so I found a second “workaround”. Workarounds 1.Use 2 containers with different configuration.2 2.Use an other OS than alpin.
I used debian instead of alpin and the problem disappear.
FROM debian:11.3 ARG RUN_JAVA_VERSION=1.3.8 ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' #debian special-------------------------------------------- #install curl -y=send yes to input RUN apt-get update; apt-get install curl -y #install jdk RUN mkdir -p /usr/share/man/man1 /usr/share/man/man2 RUN apt-get install -y --no-install-recommends openjdk-11-jre #---------------------------------------------------------- RUN mkdir /deployments RUN chmod "g+rwX" /deployments RUN curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh RUN chmod 540 /deployments/run-java.sh # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" # We make four distinct layers so if there are application changes the library layers can be re-used COPY target/quarkus-app/lib/ /deployments/lib/ COPY target/quarkus-app/*.jar /deployments/ COPY target/quarkus-app/app/ /deployments/app/ COPY target/quarkus-app/quarkus/ /deployments/quarkus/ EXPOSE 8080 ENTRYPOINT [ "/deployments/run-java.sh" ]