dockerdockerfileglibcquarkusquarkus-oidc

Build and Run Docker Image of Quarkus


I tried to create a simple microservice project with Quarkus. Native executables can be build but starting Docker containers of the created application does not work.

The microservices use a OIDC for authentication, i.e. a microservice receives a JWT from the caller which has to be valid. The JWTs are issued and verified by a Keycloak application. The application uses PostgreSQL databases. Both Keycloak and Postgres run as Docker containers. The whole deployment is still only relevant on the local machine.

I added the extension quarkus-container-image-docker. I am using Maven and below, I listed all of my extensions from the pom.xml.

  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-validator</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-oidc</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-orm-panache</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-jdbc-postgresql</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-rest-client</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-container-image-docker</artifactId>
    </dependency>
  </dependencies>

I use a Linux OS.

I can build native executables of all my microservices with the following command. Executing and calling them works fine.

./mvnw package -Pnative -DskipTests
./target/<artifact>-<version>-runner

I modified the ports in the Dockerfile.native because I changed the ports each service runs on. The following code shows one Dockerfile.native with port 8081.

FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3
WORKDIR /work/
RUN chown 1001 /work \
    && chmod "g+rwX" /work \
    && chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application

EXPOSE 8081
USER 1001

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

I can build Docker images with these native executables.

sudo docker build -f src/main/docker/Dockerfile.native -t <user>/<artifact> .

However, when I try to launch a container from the image with the following command,

sudo docker run -i --rm -p 8081:8081 <user>/<artifact>:latest

I get an error:

./application: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by ./application)

As I researched, I found another interesting option to tell the Maven plugin to build a container.

sudo ./mvnw package -Pnative -DskipTests -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true

Launching a container from the generated image also results in an error.

ERROR [io.qua.run.Application] (main) Failed to start application (with profile prod): java.net.ConnectException: Connection refused
    at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_VA_LIST:Ljava_net_ConnectException_2_0002e_0003cinit_0003e_00028Ljava_lang_String_2_00029V(JNIJavaCallWrappers.java:0)
    at sun.nio.ch.SocketChannelImpl.checkConnect(SocketChannelImpl.java)
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:779)
    at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:702)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:834)
    at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:517)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)

Can someone please provide me with some information how to handle this situation to allow Docker builds which can then successfully run?


Solution

  • As described by @RobertvanderSpek, the microservices are not able to talk to the keycloak and the postgres container anymore. To allow the communication in between the services as before, the easiest workaround is to connect the microservice containers to the network host upon startup because containers in this network are not isolated from the host OS.

    The following command represents an example command for running a container in the provided situation.

    docker run --network host <user>/<artifact>
    

    To see the whole microservice-based application system, see the GitHub repo. Detailed explanations on how to Dockerise a microservice can be found in the subfolders of each microservice.