Perl on Docker - Dancer2 Hello World Beispiel

Veröffentlicht von Thomas Fahle am (Permalink)

Camel looking outside from hut

 

Docker ist eine Freie Software zur Isolierung von Anwendungen mit Hilfe von Containervirtualisierung.

Laut Wikipedia vereinfacht [Docker] die Bereitstellung von Anwendungen, weil sich Container, die alle nötigen Pakete enthalten, leicht als Dateien transportieren und installieren lassen. Container gewährleisten die Trennung und Verwaltung der auf einem Rechner genutzten Ressourcen. Das beinhaltet laut Aussage der Entwickler: Code, Laufzeitmodul, Systemwerkzeuge, Systembibliotheken – alles was auf einem Rechner installiert werden kann..

Dieser Beitrag beschäfitigt sich mit der Containerisierung/Dockerisierung einer sehr einfachen Dancer2 Webapplikation und richtet sich an Dockereinsteiger mit minimalen Dockerkenntnissen.

 

Schritt für Schritt

In einem eigenen Verzeichnis werden die Datei der Webapplikation hello-world.pl und ein Dockerfile erstellt.

Hello World App

# Shamelessly stolen from https://metacpan.org/pod/Dancer2
use Dancer2;
get '/' => sub { "Hello World\n" };
dance;

Dockerfile

FROM ubuntu:focal
# https://hub.docker.com/_/ubuntu/
# https://github.com/docker-library/official-images

LABEL maintainer="Your Name <YourMail@example.com>"
LABEL version="0.10"
LABEL description="Just Another Docker Ubuntu Focal Image running Dancer2 hello-world using build-in server"


# Upgrade already installed packages
# Install Dancer2
# Install File::Slurper
# Install Template-Toolkit
# Install SQLite3
# Install vim
# Autoremove unused packages
# Clean local repos
# Free disk space to decrease image size
ARG DEBIAN_FRONTEND=noninteractive
RUN set -ex; \
       apt-get update && \
       apt-get dist-upgrade -y && \
       apt-get -qq -y --no-install-recommends install \
       libdancer2-perl \
       libfile-slurper-perl \
       libtemplate-perl \
       sqlite3 libdbd-sqlite3-perl \
       vim \
       & apt-get -y autoremove & apt-get clean \
       ; \
    rm -rf /var/lib/apt/lists/* ; \
    rm -rf /tmp/*

WORKDIR /app

COPY ./hello-world.pl /app/

EXPOSE 3000/tcp

ENTRYPOINT ["perl", "/app/hello-world.pl"]

Das neue Container-Image basiert auf dem offiziellem Ubuntu Focal Docker Image (FROM ubuntu:focal).

Per LABEL werden diverse Metadaten gesetzt, welche die Verwaltung der Images erleichtern sollen.

Mittels apt-get werden zunächst alle installierten Pakete auf den neuesten Stand gebracht und Dancer2 installiert. Die Umgebungsvariable DEBIAN_FRONTEND wird per ARG temporär – also nur während des Builds – gesetzt. (Bei der Verwendung von ENV werden Umgebungsvariablen dauerhaft (unveränderlich) im Image gesetzt.)

Der Vollständigkeit halber werden die – im Dancer2::Tutorial erwähnten – Module Template-Toolkit, File::Slurper, DBD::SQLite und die Datenbank SQLite installiert, auch wenn sie für das Beispiel nicht benötigt werden.

Danach werden noch alle temporären Dateien und apt-repos gelöscht, um das Image so klein wie möglich zu halten.

Die WORKDIR-Anweisung erzeugt den Ordner /app im Containerimage und setzt diesen als Startpunkt für nachfolgende Befehle, z.B. COPY.

Anschließend wird die Datei hello-world.pl im aktuellen Verzeichis per COPY in das Image kopiert.

Der in Dancer2 eingebaute Miniwebserver nutzt den TCP-Port 3000, der per EXPOSE von aussen zugänglich gemacht wird.

Im letzten Schritt wird mittels ENTRYPOINT die Anwendung gesetzt, die mit dem Start des Containers gestartet werden soll. (Hier könnte man auch CMD verwenden.)

 

Docker in Aktion

Docker läuft unter Linux mit root-Rechten. Alle Kommandos müssen daher als root-User oder mit sudo-Rechten ausgeführt werden. Die oft in Blogs empfohlene Verwendung der docker-Gruppe öffnet einen Angriffsvektor, den ich allenfalls in Entwicklungsumgebungen toleriere.

In diesem Beitrag wird daher stets folgende Form verwendet:

sudo docker command

Wem das häufige Eintippen des sudo-Befehls zu lästig ist, empfehle ich einen Shell-Alias wie alias docker="sudo docker".

Die nachfolgend aufgeführten Kommandos werden in dem Ordner ausgeführt, in dem sich die beiden o.a. Dateien befinden.

 

Containerimage bauen

Das Kommando docker build erzeugt eine Containerimagedatei aus den Anweisungen im Dockerfile. Aktuelle Dockerversionen (18.09 oder höher) können BuildKit verwenden - die neue und optimierte build-Version.

sudo DOCKER_BUILDKIT=1 docker build -t dancer-hello-world .

oder ohne BuildKit

sudo docker build -t dancer-hello-world .

Der Parameter -t tagged (benennt) das neu erstellte Image. So können Images in weiteren Kommandos auch über den Namen statt der ID angesprochen werden.

Der Punkt (.) bezieht sich auf das Dockerfile im aktuellen Verzeichnis.

 

Images listen

Vorhandene Images lassen sich mit docker images anzeigen.

sudo docker images

REPOSITORY           TAG       IMAGE ID       CREATED       SIZE
dancer-hello-world   latest    72ba77dc6169   4 hours ago   194MB

Noch mehr Informationen über das Image liefert docker inspect.

sudo docker inspect dancer-hello-world

[
    {
        "Id": "sha256:72ba77dc6169d6bc1d08ef56c24b7d5ca74fef84554a9a80ad364c0c3a7a53d1",
        "RepoTags": [
            "dancer-hello-world:latest"
        ],
...
   }
]

 

Container mit App erzeugen und starten

docker run erzeugt aus einem Docker-Image einen Container und startet diesen auch sofort.

sudo docker run -p 3000:3000 -d --name dancer dancer-hello-world

063f9bf4824971fd9fbccf372ea3737d7804d08e37dfcf9975c23b6ce48c7db

Der Parameter -d lässt den Container im Hintergrund (detached) laufen, --name vergibt einen Namen für den Container, -p erzeugt ein Portmapping vom Dockerhost zum Dockercontainer.

 

Container auflisten

Mit docker ps können vorhandene Container angezeigt werden.

sudo docker ps -a

CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS         PORTS                                       NAMES
063f9bf48249   dancer-hello-world   "perl /app/hello-wor…"   8 minutes ago   Up 8 minutes   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   dancer

Der Parameter -a zeigt alle Container an, also auch solche, die bereits beendet sind.

 

Container Logs

Jetzt noch ein kurzer Blick in die Containerlogs mit docker logs

sudo docker logs dancer

 >> Dancer2 v0.300000 server 1 listening on http://0.0.0.0:3000

 

Container Applikation verwenden

Nachdem ausführlich geprüft wurde, ob alles läuft, kann die App ja auch mal verwendet werden:

curl 0.0.0.0:3000

Hello World

Oder http://0.0.0.0:3000 im Browser öffnen.

 

Shellzugang zu einem laufendem Container

docker exec ermöglicht die Ausführung von Kommandos, z.B. /bin/bash, in einem bereits laufendem Container.

sudo docker exec -it dancer /bin/bash

root@063f9bf48249:/app#

Die Parameter -i und -t erzeugen einen interaktiven Zugang per Terminal. Sehr hilfreich zum Debuggen. Docker wechselt in das im Dockerfile angegebene WORKDIR.

 

Debuggingtipp

Falls die Applikation nicht starten will, kann man den ENTRYPOINT des Dockerfile auf der Kommandozeile überschreiben und sich per Shell in einen neuen Container einloggen.

sudo docker run -p 3000:3000 --name dancer-x --entrypoint='' -it --rm dancer-hello-world /bin/bash

root@a753025c55d4:/app# perl -c hello-world.pl
hello-world.pl syntax OK

root@a753025c55d4:/app# exit

Der Parameter --rm löscht den Container automatisch nach der Verwendung.

 

Container stoppen

docker stop stoppt (beendet) einen laufenden Container.

sudo docker stop dancer

dancer

sudo docker ps -a

CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS                        PORTS     NAMES
063f9bf48249   dancer-hello-world   "perl /app/hello-wor…"   26 minutes ago   Exited (137) 11 seconds ago             dancer

Gestoppte Container lassen sich mit docker start erneut starten.

 

Docker Images sichern und verteilen

Nun kann das Image mit docker save als tar-Archiv gesichert und anschließend komprimiert zum Kunden versandt werden.

sudo docker save dancer-hello-world -o myimage.tar
sudo gzip myimage.tar

Auf der Empfängerseite wird das Image entkomprimiert und mit docker load geladen.

gunzip myimage.tar.gz
sudo docker load -i myimage.tar
 >>Loaded image: dancer-hello-world:latest

 

Aufräumarbeiten

Wenn alles getan ist, kann der gestoppte Container per docker rm gelöscht werden.

sudo docker ps -a
CONTAINER ID   IMAGE                COMMAND                  CREATED             STATUS                           PORTS     NAMES
063f9bf48249   dancer-hello-world   "perl /app/hello-wor…"   About an hour ago   Exited (137) About an hour ago             dancer

sudo docker rm dancer
dancer

Images können mittels docker rmi gelöscht werden, sobald kein Container mehr darauf zugreift.

sudo docker images
REPOSITORY           TAG       IMAGE ID       CREATED       SIZE
dancer-hello-world   latest    72ba77dc6169   6 hours ago   194MB

sudo docker rmi dancer-hello-world
Untagged: dancer-hello-world:latest
Deleted: sha256:72ba77dc6169d6bc1d08ef56c24b7d5ca74fef84554a9a80ad364c0c3a7a53d1

 

Bonus - PSGI

Wer statt des eingebauten Miniwebservers lieber PSGI und plackup verwendet, kann sich folgendes Dockerfile mal anschauen.

FROM ubuntu:focal
# https://hub.docker.com/_/ubuntu/
# https://github.com/docker-library/official-images

LABEL maintainer="Your Name <YourMail@example.com>"
LABEL version="0.10"
LABEL description="Just Another Docker Ubuntu Focal Image running Dancer2 hello-world with plackup"


# Upgrade already installed packages
# Install Dancer2
# Insatll Plackup
# Install File::Slurper
# Install Template-Toolkit
# Install SQLite3
# Install vim
# Autoremove unused packages
# Clean local repos
# Free disk space to decrease image size
ARG DEBIAN_FRONTEND=noninteractive
RUN set -ex; \
       apt-get update && \
       apt-get dist-upgrade -y && \
       apt-get -qq -y --no-install-recommends install \
       libdancer2-perl \
       libplack-perl \
       libfile-slurper-perl \
       libtemplate-perl \
       sqlite3 libdbd-sqlite3-perl \
       vim \
       && apt-get -y autoremove && apt-get clean \
       ; \
    rm -rf /var/lib/apt/lists/* ; \
    rm -rf /tmp/*

WORKDIR /app

COPY ./hello-world.pl /app/

EXPOSE 5000/tcp

ENTRYPOINT ["/usr/bin/plackup", "/app/hello-world.pl"]

 

That's it.

 

Siehe auch

 

Source-Code der Beispiele im Github Repo perl-howto-code.

 

Bildnachweis

Photo by Peter Fogden on Unsplash

 

Weitere Posts