Teil 1: Anforderungen und Problem.. äh, Herausforderungen
Teil 2: Lösungsansätze – Dockerimages und Initialisierung
Teil 3: Lösungsansätze – Dockerimage mit WordPress
Teil 4: Lösungsansätze – Kubernetes
Teil 5: Installation automatisieren
Teil 6: Updates automatisieren
Teil 7: Feinschliff


Nachdem wir nun das Setup vorbereitet haben, müssen wir noch das eigentliche Dockerimage zusammen stellen.
Diesmal benötigen wir auch keine verzwickten Helper-Scripte oder ähnliches, sondern nur ein passendes Dockerfile:

ARG VERSION
FROM yourorganization.azurecr.io/wp-init:$VERSION as builder

WORKDIR /wp/plugins
RUN ls -1 /wp/plugins/*.zip > plugin-files.txt
RUN while read -r p; do \
       echo "processing plugin: $p"; \
       unzip -o "$p"; \
    done < plugin-files.txt
RUN rm /wp/plugins/*.zip

WORKDIR /wp/themes
RUN ls -1 /wp/themes/*.zip > theme-files.txt
RUN while read -r p; do \
       echo "processing theme: $p"; \
       unzip -o "$p"; \
    done < theme-files.txt
RUN rm /wp/themes/*.zip


ARG VERSION
FROM wordpress:$VERSION-apache

RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get -y upgrade \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

COPY --from=builder /wp/plugins/ /usr/src/wordpress/wp-content/plugins/
COPY --from=builder /wp/themes/ /usr/src/wordpress/wp-content/themes/
COPY --from=builder /wp/instance/wp-content/languages/ /usr/src/wordpress/wp-content/languages/

RUN cd /usr/src/wordpress/wp-content/ && \
    rm -f /usr/src/wordpress/.htaccess && \
    rm -rf plugins/akismet/ plugins/hello.php

Die wichtigen Files sind ja schon im setup-image (hier mal „wp-init“ genannt) vorhanden. Das können wir also einfach als Builder nehmen und alles notwendige in unser eigentliches Image kopieren.
Wie im vorherigen Beitrag bereits erwähnt, wird das WordPress-Image von dem wir hier erben, beim Start die WordPress-Basisfiles nach /var/www/html kopieren.
Also entpacken wir unsere Plugins und Themes erst einmal und kopieren sie dann zu den anderen Source-Files.

Anschließend müssen wir nur noch sicher stellen, dass ein paar Files beim Starten nicht mit kopiert werden, und löschen diese ganz dreist!
Das ist besonders wichtig bei der Datei /usr/src/wordpress/.htaccess! Diese wird im Kubernetes-Setup – auf das wir im nächsten Beitrag eingehen – von einer Configmap gemounted.
Wordpress bzw. das Image wird sich dann beim Starten ganz fürchterlich darüber beschweren, dass es die Datei nicht überschreiben kann und dann einfach abbrechen. Der POD würde dann in einer Crash-Loop hängen bleiben!

Falls sich jemand fragen sollte, warum in dem Image als erster Schritt noch ein System-Update gemacht wird – schaut euch dieses Video an: https://media.ccc.de/v/rc3-49321-devops_disasters_3_1
…der entsprechende Teil kommt so ab Minute 30 – aber schaut euch ruhig das ganze Video an!

…haben wir nicht noch etwas vergessen?

Ja – haben wir!
Wir müssen noch irgendwie diese Geschichte mit den wflogs für das Wordfence-Plugin angehen. JA – auch ihr!
Wordpress ist jetzt nicht gerade bekannt, als das sicherste CMS da draußen – da möchte man jeden Schutz mitnehmen, den man kriegen kann! Also bleibt dran.

Statt das ganze in das vorstehende Image mit einzubauen – was einerseits unschön, vor allem aber unnötig wäre – werden wir ein weiteres Dockerimage basteln.
Denn damit – um schon mal einen Teaser auf den nächsten Beitrag zu machen – können wir uns zunutze machen, dass Kubernetes-Deployments initContainers unterstützen!

Das gestaltet sich auch vergleichsweise simpel:

# use latest wordpress to ensure matching user- and group-ids!
FROM wordpress:apache

COPY init-wflogs.sh /opt/init-wflogs.sh
COPY wflogs-tmpl/ /opt/wflogs/

RUN chown -R www-data:www-data /opt/wflogs
RUN chmod +x /opt/init-wflogs.sh

ENTRYPOINT [ "/opt/init-wflogs.sh" ]

Wie bereits kommentiert: wir nehmen das offizielle, neueste WordPress-Apache-Image als Basis, um sicher zu stellen, dass wir einen „www-data“-User sowie Gruppe mit der selben ID wie im oben erstellten WordPress-Image haben!
Das macht die Gestaltung des Script deutlich einfacher.

Doch noch kurz ein Wort zu den „wflogs“ die hier noch kopiert werden.
Das sind Daten von einem bestehenden WordPress – optimaler weise direkt von dem, das migriert werden soll. Hat den Vorteil, dass Wordfence dann nicht erst neu angelernt werden muss.
Wenn ihr das nicht zur Verfügung habt macht das aber auch nix. Wordfence legt die Files selber an, wenn sie nicht da sind.

Doch nun zum Script:

#!/bin/bash

echo "Check for existing wflogs...";

if [[ ! -d /var/www/html/wp-content/wflogs/ ]]; then
	echo "ERROR: expected mount-point not found: /var/www/html/wp-content/wflogs/";
	exit 1;
fi

if [[ -f /var/www/html/wp-content/wflogs/GeoLite2-Country.mmdb ]]; then
	echo "wflogs already exists - aborting.";
	exit 0;
fi

echo "wflogs not found in expected path: /var/www/html/wp-content/wflogs/";
echo "Copy template-files...";

cp -R /opt/wflogs/* /var/www/html/wp-content/wflogs/

echo "chown copied files...";
chown -R www-data:www-data /var/www/html/wp-content/wflogs/

echo "chown upload-dir...";
chown -R www-data:www-data /var/www/html/wp-content/uploads/

echo "DONE";

Weil wir gründlich sind, checken wir natürlich erst einmal, ob der Mountpoint existiert – weil wenn nicht, dann ist irgendetwas schief gelaufen, was wir auch direkt mit einem Fehler quittieren.
Danach dann der Check auf eine der regulären Dateien die Wordfence anlegt.

Und wenn nicht, kopieren wir die Vorlage – sofern vorhanden.

Falls nicht sollten die beiden letzten Schritte aber dennoch unbedingt ausgeführt werden, da die neu eingerichteten Volumes mit Sicherheit noch „root:root“ gehören.
…das Volume für das Upload-Directory gehört zwar eigentlich zum WordPress-Image und nicht direkt zu Wordfence – aber wenn wir einmal einen schicken init-container haben, warum nicht nutzen?!

An dieser Stelle sind wir mit den Dockerimages aber soweit durch.
Wie wir die jetzt so verknüpfen, dass dabei ein lauffähiges WordPress heraus kommt, behandeln wir dann im nächsten Teil.


Weiter zu Teil 4: Lösungsansätze – Kubernetes