Can Docker Solve a Problem of Mismatched C Shared Libraries

Can docker solve a problem of mismatched C shared libraries?


Why am I getting this problem in the first place? I thought I read somewhere that glibc is backwards compatible?

GLIBC is backwards compatible (programs built against old GLIBC continue to work on newer GLIBC), but the inverse is not true.

In your case, you built on a newer (GLIBC-2.28) system, and are trying to run on an older one (GLIBC-2.27). That is not guaranteed to work (although it might for sufficiently simple programs).

Is there a way to use docker to get around this problem?

You need to build against the oldest version of GLIBC that you are planning to use.

You can achieve this in multiple ways:

  • use a Linux to older Linux crosscompiler
  • use a chroot build environment
  • use a docker container with older GLIBC at build time.

Or you could run in a docker container that has the GLIBC-2.28 that your program needs.

Including Shared C Library (.SO) in a .NET Core Docker Image

Docker has the concept of a "build context". That defines the directory from which files are accessed. So when you say COPY foo /foo in your Dockerfile, that's copying the foo file from the build context and places it in the root folder of your container with the name foo. You set the build context when running the docker build command. Very often, people use . as the build context which means the current working directory that you're running the command from (e.g. docker build -t app .). So it depends on what directory your build context is. That's where you should be placing the .SO library so that you can then add a COPY instruction in your Dockerfile to copy it into your container image.

docker compose: Error while loading shared libraries: libz.so.1: failed to map segment from shared object: Operation not permitted

Got it solved by re-mounting the /tmp to give the volume permission to execute (it was accessible with read-only). So this solved:

sudo mount /tmp -o remount,exec

Error loading shared library libresolv.so.2 in Python Alpine Docker

The library libresolv.so.2 is part of the system C library. Alpine-based images use a different version of the C library (musl libc) which is much smaller, but also occasionally runs into compatibility issues like this.

The easiest way around this is to switch to a Debian- or Ubuntu-based image based on the more standard GNU libc. Since you're using an unmodified image here you'd just need to remove the "Alpine" reference in the image tag

pythonStack([image: '3.9.13'], ...)

In a custom Dockerfile you might also need to change the package manager invocations if you need to install any OS-level packages, since Debian/Ubuntu and Alpine have different packaging formats, tools, and names. The first line of your testInstallStage would also be affected by this.

The typical reason to use an Alpine-based image is to save space. The actual space savings here are fairly small (tens of megabytes) and once you start installing C header files the images quickly get much larger than this. You're probably not going to notice a practical difference in performance or image size making this change.

Is this a good approach for developing a multi-layered C/C++ application using docker?

If you only have one “bottom layer” that installs locally built shared libraries, you might consider building two Docker images out of it. One has a complete set of development tools, plus your library, and its header files; the other has a minimal set of runtime libraries, plus your library, and no header files.

# I am Dockerfile.builder
FROM gcc
WORKDIR /usr/src/mylib
COPY . .
RUN make && make install && ldconfig
# I am Dockerfile.runtime
FROM ubuntu
COPY --from=myname/builder /usr/lib/mylib.so* /usr/lib
RUN ldconfig

Have your CI system build both of these. Note that the second one depends on the first (myname/builder is whatever image name you’re using for the first image).

Now when you build your application, you have a base Docker image with your local build tools and libraries, plus a base Docker image with the library preinstalled.

FROM myname/builder AS build
WORKDIR /usr/src/app
COPY . .
RUN make && make install

FROM myname/runtime
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD ["app"]

This approach won’t work well if you have multiple shared libraries that you’re trying to separately build and install (as a corollary to the more general rule that you can’t combine two independent Docker images).

Another generically useful approach (that works in pretty much all languages) is to package your library without using Docker. If you’re using something like an Ubuntu runtime, you can package your library into Debian packages. This has a split between development and runtime packages, so in your builder image you can apt install the development version (with header files) and at runtime only the runtime version (with usr the shared library). Similar approaches work for npm and Python packages, Ruby gems, ....

Dockerize my gradle java project but encounter jdk version mismatch between compile time and runtime

From oracle documentation

Java SE | Released | Major | Supported majors

1.0.2 | May 1996 | 45 | 45

1.1 | February 1997 | 45 | 45

1.2 | December 1998 | 46 | 45 .. 46

1.3 | May 2000 | 47 | 45 .. 47

1.4 | February 2002 | 48 | 45 .. 48

5.0 | September 2004 | 49 | 45 .. 49

6 | December 2006 | 50 | 45 .. 50

7 | July 2011 | 51 | 45 .. 51

8 | March 2014 | 52 | 45 .. 52

9 | September 2017 | 53 | 45 .. 53

10 | March 2018 | 54 | 45 .. 54

11 | September 2018 | 55 | 45 .. 55

12 | March 2019 | 56 | 45 .. 56

13 | September 2019 | 57 | 45 .. 57

14 | March 2020 | 58 | 45 .. 58

15 | September 2020 | 59 | 45 .. 59

16 | March 2021 | 60 | 45 .. 60

17 | September 2021 | 61 | 45 .. 61

18 | March 2022 | 62 | 45 .. 62

Your error says

has been compiled by a more recent version of the Java Runtime (class
file version 61.0), this version of the Java Runtime only recognizes
class file versions up to 52.0

You have compiled with JAVA 17 and try to run it with JAVA 8. Switch either the compilation or the environment that runs the compiled application according to the above table.

Your JRE 8 that exists in docker supports any code that is compiled with JDK 8 or earlier versions (1 .. 5, 6, 7) .

If you wish to compile the project with JDK 17 you need to provide a running environment in docker >= JDK 17.

Edit:

Answering the comment

I also wonder what is the image I should use to run the code that is
compiled by JDK 17

try with

FROM openjdk:17-alpine as my-app ...

How to add custom library to docker image

Yes, you can certainly use COPY from your local machine.

However, I would make sure that the custom qt libraries are available online on GitHub or so, so that the docker image can be built correctly from anywhere without having to set up every local machine where the docker image is meant to be created.

This way, you can just clone the repository and the respective branch instead of COPY in your docker file.



Related Topics



Leave a reply



Submit