Inhaltsverzeichnis

rkCSD-WebsiteEngine in Docker verpacken

Im vorherigen Artikel ging es um Docker-Grundlagen, jetzt wollen wir uns damit beschäftigen, wie man eine PHP-Anwenung mit etwas spezifischeren Anforderungen als „PHP & Apache“ in ein eigenes Dockerimage packt und in Docker Hub pusht. Wir nehmen hier als Beispiel unser CMS.

Syntax

Zuerst brauchen wir einen neuen Ordner. In diesem legen wir eine Datei namens „Dockerfile“ an. Dieses Dockerfile enthält nachher alle Anweisungen, die für das fertige Image wichtig sind. Es ist wichtig, dass der Ordner nur für das Image relevante Dateien enthält, da der gesamte Ordner, inklusive Unterordner zu den Dockerservern gesendet wird, um dann „in der cloud“ in ein ausführbares Image verwandelt wird.

Zuallererst (und ganz am Anfang der Datei) kommt die Anweisung „FROM <image>“. Jedes neue Image basiert auf einem andern, vorherigen (das sozusagen unterste Image hat dann den Namen „scratch“). Unsere Anwendung benötigt PHP 5.6 mit Apache, also schreiben wir

FROM php:5.6-apache

als Start hin.

Beginnen wir damit, das eigentliche CMS hinzuzufügen. Dazu benutzen wir das „ADD“ Kommando: (Vorrausgesetzt, dass das CMS im Unterordner „cms“ im aktuellen Ordner gespeichert ist)

ADD cms/ /var/www/html

Als nächstes brauchen wir ein paar Volumes. Volumes lassen sich auch direkt im Container anlegen, dann werden die Dateien vom Dockerdaemon irgendwo auf dem Host gespeichert, wenn beim Ausführen des Images keine Volumes angegeben wurden.

Unser CMS speichert wichtige Daten in /content, /apps und /config. Wir brauchen also drei Volumes:

VOLUME /var/www/html/apps
VOLUME /var/www/html/content
VOLUME /var/www/html/config

Das sieht doch gut aus! Speichern wir die Datei ab und bauen das Image mit

docker build .

. Dabei sollten wir uns im selben Ordner mit dem Dockerfile befinden.

Das müsste dann in etwa so aussehen:

docker build .
Sending build context to Docker daemon 3.223 MB
Step 1/5 : FROM php:5.6-apache
5.6-apache: Pulling from library/php
6d827a3ef358: Already exists 
87fe8fbc743a: Already exists 
f6d1a8d304ab: Already exists 
caf3547d9b73: Already exists 
1004db2760ff: Already exists 
66e2d66a547e: Already exists 
bbfaa62c234a: Already exists 
19ce8807f4d1: Already exists 
65dc0142d59b: Pull complete 
a95f4fa43ae2: Pull complete 
f4edd48c3730: Pull complete 
d58fc629c9d1: Pull complete 
c75a71ebb7f4: Pull complete 
Digest: sha256:fdd934917130261fe59e51fe303934cdb8657e458ff7b139a4e76caf4526bcb7
Status: Downloaded newer image for php:5.6-apache
 ---> 7371a90e1216
Step 2/5 : ADD cms/ /var/www/html
 ---> 340466aa2e3e
Removing intermediate container a9243bafb75e
Step 3/5 : VOLUME /var/www/html/apps
 ---> Running in 38ed9a9be9c4
 ---> 09ff1566cd06
Removing intermediate container 38ed9a9be9c4
Step 4/5 : VOLUME /var/www/html/content
 ---> Running in 3809c65bb5ac
 ---> ac15bec9c7f0
Removing intermediate container 3809c65bb5ac
Step 5/5 : VOLUME /var/www/html/config
 ---> Running in ba8939e3c391
 ---> 7d2e36e48359
Removing intermediate container ba8939e3c391
Successfully built 7d2e36e48359

Die letzte Zeile ist wichtig, dort steht der Name des neuen Images. Den können wir jetzt mit

docker run -p 8080:80 7d2e36e48359

ausführen. Kurz mal probehalber localhost:8080 im Browser aufrufen uuuuuuund…

Hier Bild einfügen FIXME

Es geht nicht. Mist. Hilft nur nix, über das Problem zu jammern, gucken wir lieber mal nach, wie's im Container aussieht.

Mit

docker exec -it <name des containers> /bin/bash

können wir einen Bash im Container öffnen und uns drinnen umsehen. (Den Namen kriegen wir, wenn wir vorher keinen vergeben haben mit „docker ps“ raus.

Auf der Konsole sagt der Container: (Der läuft ja immernoch im Vordergrund, alle Logs werden direkt an uns weitergegeben)

[core:alert] [pid 17] [client 172.17.0.1:39640] /var/www/html/.htaccess: Invalid command 'RewriteEngine', perhaps misspelled or defined by a module not included in the server configuration

Es fehlt also die RewriteEngine, die wir als benötigt in unserer .htaccess definiert haben. Von der Übersichtsseite auf Docker Hub über das PHP-Apache Image erfahren wir, dass das Image absichtlich minimal gehalten wurde, um die Imagegröße klein zu halten. (Das entspricht der 'Philosophie' von Docker, weshalb die meisten Images nur das haben, was sie brauchen um die Anwendung laufen zu lassen, nichtmal rudimentäre Systemwerkzeuge sind meist dabei)

Da wir das nun wissen, wird auch die PHP-Mysqli Erweiterung nicht vorhanden sein, die das CMS ebenfalls benötigt.

Um diese und mod_rewrite hinzuzufügen brauchen wir dieses Kommando:

RUN docker-php-source extract \
&& docker-php-ext-install mysql mysqli pdo pdo_mysql \
&& a2enmod rewrite \
&& docker-php-source delete

Mit der RUN-Anweisung lassen sich belibige Anweisungen auf der Konsole des Containers ausführen. Generell ist es eine gut Praxis, mehrere Anweisungen in einem RUN-Kommando zusammenzufassen, das minimiert die verschiedenen Images, die für jede Anweisung erstellt werden.

Wenn wir den Container jetzt bauen, laufen lassen und anschließend im Browser localhost:8080 aufrufen, sollten wir was in dieser Richtung hier sehen:

[Hier zweites Bild einfügen]

Der Container scheint also zu funktionieren! (Das CMS ist noch nicht installiert, wir müssten also als nächstes im /config Volume eine entsprechende Config-datei anlegen.

Eigene PHP.ini

Momentan sind wir noch auf die Standard-PHP.ini angewiesen. In der steht z.B. drin, dass Dateien bis zu einer maximalen größe von 2M hochgeladen werden dürfen… im Produktiveinsatz ist das devinitiv zu wenig. Das müssen wir also anpassen. Dazu erstellen wir eine eigene php.ini-Datei (Download hier) und bauen die mit folgendem Befehl in unser Image ein:

COPY php.ini /usr/local/etc/php/

Hier müssten wir auch Error-Reporting für einen Entwicklungscontainer anschalten.

Pushen zu Dockerhub

Das fertige Image können wir nun zu Dockerhub pushen, um es später wiederzuverwenden, und nicht nocheinmal bauen zu müssen. Dazu brauchen wir zunächst ein Benutzerkonto auf Dockerhub

Anschließend können wir uns mittels

docker login

einloggen.

Um das Image zu pushen, müssen wir es zunächst erstmal taggen, momentan hat es noch keinen Namen, nur etwas kryptischen ID wie „bb9bec94fd60“. Um diese rauszufinden, gibt es

docker images</docker>
Damit werden alle Images, die auf diesem PC vorhanden sind, (also auch unser vorhin erstelltes) angezeigt. Um dieses Image nun mit einem "richtigen" Namen zu versehen, führt man <code>docker tag <image-ID von gerade Eben> <repository, also z.B. Nutzername>/<Imagename>

aus. Konkret bei uns wäre das

docker tag bb9bec94fd60 rkcsd/cms

Wenn wir nun nochmal

docker images

ausführen, sehen wir dass unser Image jetzt ein Tag hat:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rkcsd/cms           latest              bb9bec94fd60        7 hours ago         375 MB

Jetzt können wir das Image mit

docker push rkcsd/cms

in Docker Hub pushen, anschließend kann jeder das Image mit

docker run rkcsd/cms

herunterladen und starten. Es gibt auch die Möglichkeit „private“ Images in Docker Hub zu laden, eins davon ist kostenlos, die anderen kosten. Man kann auch sein eigenes Docker Repository hosten und dort dann seine Images privat halten.

Schlusswort

Dieses Tutorial (und das vorherige sollte einen Einstieg in das große Thema „arbeiten mit Docker“ geben. Ich habe sicherlich nur die Oberfläche angekratzt, wer mag kann sich noch z.B. in den Docs weiterbilden, dort gibt es auch noch tiefergehende (ganz gute) Tutorials und eine Erklärung der Befehle. Im Netz findet man ebenfalls eine Vielzahl an Tutorials.