Perl on Docker - Dancer2 und Redis docker-compose Beispiel
Veröffentlicht von Thomas Fahle am (Permalink)
Einführung
Das Einrichten von einzelnen Docker-Containern mit Dockerfiles ist eigentlich unkompliziert. Oft benötigt man aber Setups aus mehreren Containern, z.B. einen Front- und einen Backendserver in einem eigenem Netzwerk.
Docker Compose ermöglicht das Bereitstellen einer Gruppe mit mehreren Containern aus einer Konfigurationsdatei (docker-compose.yml oder docker-compose.yaml) im YAML-Format.
In diesem Beitrag wird eine Dancer2-Webapplikation (Frontend) in einem eigenen Container erstellt. Diese Webapp verwendet einen Redis-Server in einem weiterem Container als Backend im selben Netzwerk. Beide Container werden per Docker Compose gebaut, verbunden und gemeinsam gestartet.
Beispiel: Dancer2-Webapp mit Redis-Backend
Alle nachfolgend aufgeführten Dateien befinden sich in einem eigenen Verzeichnis.
Der Source-Code der Beispiele befindet sich auch Github Repo perl-howto-code.
Dancer2-Webapp
Zunächst die Dancer2-Webapp – Datei redis-counter.pl – ein einfaches Counter-Programm, welches den Zählerstand in einer Redis-Datenbank vorhält.
#!/usr/bin/env perl use strict; use warnings; use Dancer2; use Redis; set 'logger' => 'console'; set 'log' => 'debug'; set 'show_errors' => 1; set 'startup_info' => 1; my $redis_host = 'myredis'; my $redis_port = 6379; my $redis = Redis->new( server => "$redis_host:$redis_port" ); get '/' => sub { my $counter = $redis->incr('counter'); debug "Counter: $counter"; return "$counter\n"; }; dance;
Redishost und -port (myredis, 6379) müssen mit den Angaben in der Konfigurationsdatei docker-compose.yaml exakt übereinstimmen. Dazu später mehr.
Die Ausgabe der eingestreuten debug-logging-Anweisungen lässt sich auch per docker logs am laufenden Container einsehen.
Dockercontainer der Dancer2-Webapp
Das nachfolgende Dockerfile nutzt Official Docker Perl Images, die bereits in Perl on Docker - Offizielle Perl Docker Images als Grundlage eigener Images beschrieben wurden, als Basis (FROM perl:latest).
Zunächst werden alle installierten Pakete mit apt-get auf den neuesten Stand gebracht. Die Umgebungsvariable DEBIAN_FRONTEND wird per ARG temporär – also nur während des Builds – gesetzt.
Im nächsten Schritt werden die CPAN-Module Dancer2 und Redis mit cpanm installiert.
Um das Image so klein wie möglich zu halten, werden nun noch alle temporären Dateien und apt-repos gelöscht.
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 redis-counter.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.)
Dockerfile
Datei Dockerfile.
FROM perl:latest LABEL maintainer="Thomas Fahle <perlhowto.github.io@gmail.com>" LABEL version="0.10" LABEL description="Perl-on-Docker perl:latest buildpacks-deps Image running Dancer2 Redis Example" # apt-get # Upgrade already installed packages # Autoremove packages unused by other packages # Clean local repos # # cpanm # Install Dancer2 # Install Redis # # Free disk space to decrease image size ARG DEBIAN_FRONTEND=noninteractive RUN set -ex; \ apt-get update && \ apt-get dist-upgrade -y && \ apt-get -y autoremove && \ apt-get clean ; \ /usr/local/bin/cpanm \ Dancer2 \ Redis \ ; \ rm -rf /var/lib/apt/lists/* ; \ rm -rf /tmp/* ; \ rm -rf /root/.cpanm/ WORKDIR /app COPY ./redis-counter.pl /app/ EXPOSE 3000/tcp ENTRYPOINT ["/usr/local/bin/perl", "/app/redis-counter.pl"]
Das Image kann jetzt gebaut
sudo DOCKER_BUILDKIT=1 docker build -t perl-redis-client-image .
und zumindestens – der Redis-Container läuft ja noch nicht – inspiziert werden.
# Debug sudo docker run -it --rm --entrypoint='' --name perl-redis-client perl-redis-client-image /bin/bash
Es ist nicht zwingend erforderlich, das Image bereits jetzt zu bauen. Das kann docker-compose ebenfalls erledigen. Es vereinfacht aber das Debugging erheblich.
Dockercontainer des Redis-Servers
Für den Redis-Container wird ein vorgefertigtes offizielles Redis Image vom Docker Hub mit dem besonders schlanken Alpine Linux verwendet.
Redis-Daten werden im Docker VOLUME /data persistent gespeichert, falls das Volume vorhanden ist.
Container mit docker-compose verbinden
Die nachfolgende Konfiguration erzeugt zwei Services bzw. Container, dancer und myredis, in einem eigenem Netzwerk.
Die Servicekennzeichungen werden von docker-compose auch als Hostnamen für die Container verwendet. Der Hostname des Redis-Containers (myredis) wurde auch in der Datei redis-counter.pl hartkodiert.
Da kein Netzwerk explizit konfiguriert wurde, legt docker-compose automatisch ein Netzwerk an. Der Name des Netzwerks wird in diesem Fall aus dem Namen des Ordners, hier redis, erzeugt.
Der Webapp-Container dancer wird ggf. neu gebaut, öffnet den Dancer2-Standard-Port 3000, mappt den Port 3000 des Dockerhosts auf den Port 3000 des Containers und startet mit dem im Dockerfile konfiguriertem Kommando.
Da der Webapp-Container dancer ohne den zugehörigen Redis-Container myredis nicht lauffähig ist, wird dancer erst nach myredis gestartet
Der Redis-Container myredis nutzt, wie bereits beschrieben, ein vorgefertigtes offizielles Redis Image vom Docker Hub, öffnet den Redis-Standard-Port 6379 im Netzwerk dieser Containergruppe, mountet das lokale Verzeichnis ./redis-data als Volume /data und startet den redis-server.
docker-compose.yml
Datei docker-compose.yml
version: '3' services: dancer: build: . expose: - "3000" ports: - "3000:3000" depends_on: - "myredis" myredis: image: redis:alpine expose: - "6379" command: redis-server volumes: - ./redis-data:/data
Container bauen
Container in einem eigenen Arbeitsschritt bauen.
sudo COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose build
Container starten, testen und stoppen
Containergruppe im Vordergrund starten
sudo docker-compose up
Das sieht dann ungefähr so aus:
Creating network "redis_default" with the default driver Starting redis_myredis_1 ... done Starting redis_dancer_1 ... done Attaching to redis_myredis_1, redis_dancer_1 myredis_1 | 1:C 16 Sep 2021 10:39:03.467 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo myredis_1 | 1:C 16 Sep 2021 10:39:03.467 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, just started myredis_1 | 1:C 16 Sep 2021 10:39:03.467 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf myredis_1 | 1:M 16 Sep 2021 10:39:03.468 * monotonic clock: POSIX clock_gettime myredis_1 | 1:M 16 Sep 2021 10:39:03.469 * Running mode=standalone, port=6379. myredis_1 | 1:M 16 Sep 2021 10:39:03.469 # Server initialized myredis_1 | 1:M 16 Sep 2021 10:39:03.469 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. myredis_1 | 1:M 16 Sep 2021 10:39:03.469 * Ready to accept connections dancer_1 | >> Dancer2 v0.301004 server 1 listening on http://0.0.0.0:3000
Testen im Browser http://127.0.0.1:3000/ bzw. http://0.0.0.0:3000/ oder in einer weiteren Shell.
curl 0.0.0.0:3000
Containergruppe im Vordergrund mit der Tastenkombination Crtl-C stoppen.
Die Containergruppe kann natürlich auch im detached-Modus gestartet
sudo docker-compose -d up
und gestoppt werden.
sudo docker-compose down
Persistenz der Redis-Daten
Beim erneuten Start der Containergruppe liest Redis die Datenbank aus dem VOLUME /data ein:
... myredis_1 | 1:M 16 Sep 2021 10:42:28.509 * Loading RDB produced by version 6.2.5 myredis_1 | 1:M 16 Sep 2021 10:42:28.509 * RDB age 25 seconds myredis_1 | 1:M 16 Sep 2021 10:42:28.509 * RDB memory usage when created 0.77 Mb myredis_1 | 1:M 16 Sep 2021 10:42:28.509 * DB loaded from disk: 0.000 seconds
Aufräumarbeiten
Sobald die Containergruppe nicht mehr benötigt wird, kann weitestgehend aufgeräumt werden.
sudo docker-compose down -v --rmi all --remove-orphans Removing redis_dancer_1 ... done Removing redis_myredis_1 ... done Removing network redis_default Removing image redis:alpine Removing image redis_dancer
Siehe auch
- Overview of Docker Compose
- Sample apps with Compose
- Awesome Compose Repo - A curated list of Docker Compose samples
- Compose file version 3 reference
- Use a volume with docker-compose
- Control startup and shutdown order in Compose
- Networking in Compose
- Environment variables in Compose
- docker stack
- Docker
- Docker Docs
- Redis
- Redis - Official Image | Docker Hub
- Intro to Redis — with Docker Compose
- Redis - Perl binding for Redis database
- Dancer2
- Counter using Dancer2 and Redis in a Docker container
- Official Docker Perl
- Github docker-perl
- Perl on Docker - Dancer2 Hello World Beispiel
- Perl on Docker - Offizielle Perl Docker Images als Grundlage eigener Images
- Perl on Docker - Multi-stage Builds zur Verkürzung von Build-Laufzeiten
- Perl on Docker - Perl commandline Programm als Docker Container erstellen und nutzen
Source-Code der Beispiele im Github Repo perl-howto-code.
Bildnachweis
Photo by Lesly Juarez on Unsplash