Debugging a Perl Docker container
June 9, 2021
In the evening I tried to Dockerize the Perl version of
tumblelog
. This went very well
until I tried to add the CommonMark Perl module which relies on a C library:
libcmark
.
At this point the Dockerfile
was as follows:
# syntax=docker/dockerfile:1
FROM perl:5.34.0-slim AS base
WORKDIR /app
FROM base AS builder
RUN apt-get update \
&& apt-get install -yq build-essential cpanminus libcmark-dev \
&& cpanm URI JSON::XS YAML::XS Path::Tiny CommonMark
FROM base AS run
COPY --from=builder /usr/local /usr/local
COPY tumblelog.pl ./
WORKDIR /data
ENTRYPOINT ["perl", "/app/tumblelog.pl"]
I created the Docker image as follows:
docker build --tag tumblelog/perl -f perl.Dockerfile .
However, when I tried to run this using:
docker run tumblelog/perl
I got the following error message:
Can't load '/usr/local/lib/perl5/site_perl/5.34.0/x86_64-linux-gnu/auto/CommonMa
rk/CommonMark.so' for module CommonMark: libcmark.so.0.28.3: cannot open shared
object file: No such file or directory at /usr/local/lib/perl5/5.34.0/XSLoader.p
m line 93.
at /usr/local/lib/perl5/site_perl/5.34.0/x86_64-linux-gnu/CommonMark.pm line 11
.
BEGIN failed--compilation aborted at /usr/local/lib/perl5/site_perl/5.34.0/x86_6
4-linux-gnu/CommonMark.pm line 12.
Compilation failed in require at /app/tumblelog.pl line 11.
BEGIN failed--compilation aborted at /app/tumblelog.pl line 11.
Since I used a multi-stage build and cpanm
was able to build and test the
module something went wrong in the second stage (run
). It took me some time to
understand that libcmark.so.0.28.3
could not be found, despite the clear
message, and that COPY --from=builder /usr/local /usr/local
did work as
expected.
But where was this required file located? After some reading up on staged builds
I learned that I could stop the building process at a certain stage. So I
stopped at the builder
stage as follows:
docker build --target builder --tag tumblelog/perl -f perl.Dockerfile .
Now I could get an interactive shell (--it
option) inside the builder
stage
and check some things as follows:
docker run -it --entrypoint /bin/sh tumblelog/perl
In the shell I verified that the CommonMark
module had been installed
in the builder
stage correctly using:
perl -MCommonMark -e1
This one-liner tries to load the CommonMark module and executes the program 1
.
Executing the above resulted in no error at all. So far so good. Next I used
find
to locate libcmark.so.0.28.3
. To be cautious I searched for each file
starting with libcmark*
as follows:
find / -name 'libcmark*' -print
This resulted in the following list of files:
/var/lib/dpkg/info/libcmark-dev.list
/var/lib/dpkg/info/libcmark0.shlibs
/var/lib/dpkg/info/libcmark0.md5sums
/var/lib/dpkg/info/libcmark0.list
/var/lib/dpkg/info/libcmark-dev.md5sums
/var/lib/dpkg/info/libcmark0.triggers
/usr/share/doc/libcmark-dev
/usr/share/doc/libcmark0
/usr/lib/libcmark.so.0.28.3
/usr/lib/pkgconfig/libcmark.pc
/usr/lib/libcmark.so
/usr/lib/libcmark.a
It turned out that the missing file was located in /usr/lib
. Adding another
COPY
to the run
stage fixed the issue at hand. So the next iteration of the
Dockerfile
became:
# syntax=docker/dockerfile:1
FROM perl:5.34.0-slim AS base
WORKDIR /app
FROM base AS builder
RUN apt-get update \
&& apt-get install -yq build-essential cpanminus libcmark-dev \
&& cpanm URI JSON::XS YAML::XS Path::Tiny CommonMark
FROM base AS run
COPY --from=builder /usr/local /usr/local
COPY --from=builder /usr/lib /usr/lib
COPY tumblelog.pl ./
WORKDIR /data
ENTRYPOINT ["perl", "/app/tumblelog.pl"]
Note that this file is not complete. If you want to Dockerize tumblelog.pl
using the above you have to add Try::Tiny
to the list of Perl modules.
The resulting image is quite large: 371MB. Especially compared to the Python
tumblelog
image I created this morning, which uses Alpine and is just
58MB. Tomorrow I want to look into building an Alpine image for the Perl version
of tumblelog
as well.