SMOLNET PORTAL home about changes
=====================================================================
             ___       __  _ __
  ___  _____/ (_)___  / /_(_) /__
 / _ \/ ___/ / / __ \/ __/ / //_/
/  __/ /__/ / / /_/ / /_/ / ,<
\___/\___/_/_/ .___/\__/_/_/|_|
            /_/
=====================================================================


Containerizing a Perl Script

2015-08-29 | #containers #docker #perl


Intro


Almost every IT department has one; a Perl script written decades ago by a long-gone employee that's critical to production. It does it's job well, but no one wants to touch or take responsibility for it. You just want to upgrade your infrastructure and bring it along, but there are so many CPAN[1] modules and inconsitencies you want never want to look at it again. What to do?

1: http://www.cpan.org/ (http://www.cpan.org)


Executable Containers


Most articles on containers focus on running a service, exposing ports and data volumes, but one feature frequently overlooked is the ability to run a container as an executable.

In Docker[2], the ENTRYPOINT[3] instruction makes this possible by running a command and accpeting command line arguments from `docker run`. Combining this with `-it` and `--rm` will run an interactive emphermal container, disappearing when the command is complete.

2: https://www.docker.com (https://www.docker.com)
3: https://docs.docker.com/reference/builder/#entrypoint (https://docs.docker.com)


Dockerfile


Let's walk through an example that runs a Perl script called ps.pl[4], which prints a simple process table using the CPAN module Proc::ProcessTable[5] and includes `-h` and `-v` arguments.

4: https://gist.github.com/ecliptik/9a868cbe348d87a5141a#file-ps-pl (https://gist.github.com)
5: http://search.cpan.org/~durist/Proc-ProcessTable-0.39/ProcessTable.pm (http://search.cpan.org)


The following Multi-Stage Dockerfile[6] will build a container to run a simple perl script,

6: https://docs.docker.com/develop/develop-images/multistage-build/ (https://docs.docker.com)


  • Debian Stable Slim base image
  • Install OS packages
  • Install CPAN modules
  • Copy ps.pl[7] script
  • Set `ps.pl` script as ENTRYPOINT[8]
  • Set `-h` as default argument


7: https://gist.github.com/ecliptik/9a868cbe348d87a5141a#file-ps-pl (https://gist.github.com)
8: https://docs.docker.com/engine/reference/builder/#entrypoint (https://docs.docker.com)


Here is the Dockerfile[9] in full,

9: https://gist.github.com/ecliptik/9a868cbe348d87a5141a#file-dockerfile (https://gist.github.com)


#This Dockerfile uses a Multi-Stage Build: https://docs.docker.com/develop/develop-images/multistage-build/
FROM debian:stable-slim AS base
LABEL maintainer="Micheal Waltz <dockerfiles@ecliptik.com>"

# Environment
ENV DEBIAN_FRONTEND=noninteractive \
    LANG=en_US.UTF-8 \
    LC_ALL=C.UTF-8 \
    LANGUAGE=en_US.UTF-8

# Install runtime packages
RUN apt-get update \
    && apt-get install -y \
      perl

# Set app dir
WORKDIR /app

# Intermediate build layer
FROM base AS build
#Update system and install packages
RUN apt-get update \
    && apt-get install -yq \
        build-essential \
        cpanminus

# Install cpan modules
RUN cpanm Proc::ProcessTable Data::Dumper

# Runtime layer
FROM base AS run

# Copy build artifacts from build layer
COPY --from=build /usr/local /usr/local

# Copy perl script
COPY ./ps.pl .

# Set Entrypoint
ENTRYPOINT [ "/app/ps.pl" ]


Dockerfile Breakdown


Standard start of a Dockerfile, using the Official Debian image[10] tagged `stable-slim` as the `base` layer and a label[11] for the image maintainer,

10: https://hub.docker.com/_/debian/ (https://hub.docker.com)
11: https://docs.docker.com/engine/reference/builder/#label (https://docs.docker.com)


FROM debian:stable-slim AS base
LABEL maintainer="Micheal Waltz <dockerfiles@ecliptik.com>"


Basic environment variables for Debian packages through `apt` non-interactive and set locale to UTF-8,

ENV DEBIAN_FRONTEND=noninteractive \
    LANG=en_US.UTF-8 \
    LC_ALL=C.UTF-8 \
    LANGUAGE=en_US.UTF-8


Install "runtime" packages for the `base` layer that other layers will inheriet. Sets `/app` as WORKDIR[12],

12: https://docs.docker.com/engine/reference/builder/#workdir (https://docs.docker.com)


# Install runtime packages
RUN apt-get update \
    && apt-get install -y \
      perl

# Set app dir
WORKDIR /app


Intermediate `build` layer which is used temporarily to install packages and modules that won't be used directly at runtime. Using an intermeiate layer will save space in the resulting image and no include packages that aren't used explicitly for runtime operation, improving security posture.

# Intermediate build layer
FROM base AS build
#Update system and install packages
RUN apt-get update \
    && apt-get install -yq \
        build-essential \
        cpanminus


Install Perl CPAN[13] packages and dependencies with cpanminus[14] which works well within a container build environment,

13: https://www.cpan.org/ (https://www.cpan.org)
14: http://search.cpan.org/~miyagawa/App-cpanminus-0.05/cpanm (http://search.cpan.org)


# Install cpan modules
RUN cpanm Proc::ProcessTable Data::Dumper


Create final `run` layer for the resulting image and copy `/usr/local` from the intermediate `build` layer to include required CPAN modules,

# Runtime layer
FROM base AS run

# Copy build artifacts from build layer
COPY --from=build /usr/local /usr/local


Copy ps.pl[15] script into `WORKDIR` (aka `/app`) of the container. This is put near the end of the `Dockerfile` since it is the file most likely to change and will allow re-using of cache for previous layers, speeding up subsequent builds[16].

15: https://gist.github.com/ecliptik/9a868cbe348d87a5141a#file-ps-pl (https://gist.github.com)
16: https://thenewstack.io/understanding-the-docker-cache-for-faster-builds/ (https://thenewstack.io)


# Copy perl script
COPY ./ps.pl .


Set `ENTRYPOINT` to the ps.pl[17] script,

17: https://gist.github.com/ecliptik/9a868cbe348d87a5141a#file-ps-pl (https://gist.github.com)


# Set entrypoint
ENTRYPOINT [ "/app/ps.pl" ]


Running the Containerized Perl Script


Now that the Dockerfile is complete, build a container image with the name `ps-perl`,

🚀➜ docker build -t ps-perl .


With a container image ready, run it with `docker run -it --rm ps-perl`, using the `-it` and `--rm` options so the container is removed when it exits,,

🚀➜ docker run -it --rm ps-perl
PID    TTY        STAT     START                    COMMAND
1      /dev/pts/0 run      Fri Sep 11 17:45:16 2020 /usr/bin/perl -w /app/ps.pl
--------------------------------
uid:  0
gid:  0
pid:  1
fname:  ps.pl
ppid:  0
pgrp:  1
sess:  1
ttynum:  34816
flags:  4210944
minflt:  1684
cminflt:  0
majflt:  0
cmajflt:  0
utime:  40000
stime:  10000
cutime:  0
cstime:  0
priority:  20
start:  1599846316
size:  12779520
rss:  8192000
wchan:  0
time:  50000
ctime:  0
state:  run
euid:  0
suid:  0
fuid:  0
egid:  0
sgid:  0
fgid:  0
pctcpu:    5.00
pctmem:  0.07
cmndline:  /usr/bin/perl -w /app/ps.pl
exec:  /usr/bin/perl
cwd:  /app
cmdline:  ARRAY(0x55fb475bb9f0)
environ:  ARRAY(0x55fb472dd500)
tracer:  0


Command Line Arguments


Command line arguments will also pass into the container when run using the CMD[18] to pass to `ENTRYPOINT`,

18: https://docs.docker.com/engine/reference/builder/#cmd (https://docs.docker.com)


`-h`

🚀➜ docker run -it --rm ps-perl -h
A simple perl version of ps


`-v`

🚀➜ docker run -it --rm ps-perl -v
Version: 1.0


Conclusions


By using the `-slim` variant of Debian for the base image and multi-stage builds, the resulting container size is just over 130MB. Using a smaller image like Alpine Linux[19] could further reduce the image size, but could introduce known caveats[20] because of musl libc and glibc differences[21].

19: https://hub.docker.com/_/alpine/ (https://hub.docker.com)
20: http://gliderlabs.viewdocs.io/docker-alpine/caveats/ (http://gliderlabs.viewdocs.io)
21: https://wiki.musl-libc.org/functional-differences-from-glibc.html (https://wiki.musl-libc.org)


🚀➜ docker images
ps-perl             latest              938c3dde86d7        29 minutes ago      134MB


Additional References


  • Dockerising a Perl application[22]
  • Downsizing Docker Containers[23]
  • Proc::ProcessTable Example[24]


22: http://robn.io/docker-perl/ (http://robn.io)
23: https://intercityup.com/blog/downsizing-docker-containers.html (https://intercityup.com)
24: http://search.cpan.org/~durist/Proc-ProcessTable-0.39/ProcessTable.pm (http://search.cpan.org)


(Updated 9/11/2020)

Tags


perl
docker
containers

____________________________________________________________________

Home
Response: 20 (Success), text/gemini
Original URLgemini://rawtext.club/~ecliptik/_posts/2015-08-29-Contain...
Status Code20 (Success)
Content-Typetext/gemini; charset=utf-8; lang=en