Dieses Tutorial ist VALID.

Bitte lies Dir den Disclaimer durch, bevor Du eine Anleitung umsetzt...

Haftungsausschluss / Disclaimer

WordPress Docker Image erstellen

Warum bauen wir ein eigenes Image für WordPress?

WordPress.

Im laufe einer sehr, sehr langen Beziehung habe ich das CMS wirklich zu schätzen und zu lieben gelernt…

WordPress war der eigentliche Grund, dass ich mich damals überhaupt mit Docker beschäftigt habe. Als mir der ganze alte Stack um die Ohren geflogen ist. Und auch dieses „Projekt Rootserver“ wurde im Grunde nur deswegen gestartet, um am Ende auf einem Server mehrere Instanzen von WordPress laufen zu lassen.

Schnell und zuverlässig. Mit uns als alleinige Herren über unsere eigenen Systeme!

Wie gesagt – hier als Abschluss der Serie nun das Tutorial zu WordPress. Wir fangen wir dem Image an.
Diesem fehlt in der offiziellen Version auch die Option, Mails zu versenden. Abgesehen davon ändern wir einige Limits nach oben. Darum bauen wir es selber und weben diese Elemente mit in die Struktur ein. Bringen wir’s zu Ende…

Verzeichnisse anlegen und Config-Dateien laden

Wie legen unterhalb von „/root/docker“ ein Verzeichnis „wordpress-php73-apache“ an, in dem wir das Entrypoint Script und das „Dockerfile“ herunterladen bzw. erstellen. Das „Dockerfile“ ist die Steuerdatei, in der Instruktionen stehen, wie das Image „gebaut“ werden soll.

Die meisten Docker Images gibt es in verschiedenen Ausführungen. Beispielsweise mit php 7.1, 7.2 oder 7.3. Oder dem Webserver apache oder fpm. Damit wir auf den ersten Blick sehen, welches Image wir bauen möchten, schreibe ich diese Bezeichnungen mit in den Verzeichnisnamen. Sollte dann zum Beispiel php 7.4 herauskommen, legen wir dafür ein neues Verzeichnis an und sind in der Lage, zwei Images parallel zu erstellen, bis wir sicher sind, dass die neue php 7.4 Version auch vernünftig funktioniert…

Achtung: die „wget“ Befehlszeile ist ziemlich lang und erstreckt sich hier über mehrere Zeilen. Diese müssen bitte komplett per Copy/Paste kopiert und im Terminal in einer einzigen Kommandozeile ausgeführt werden…

Die „docker-entrypoint.sh“-Datei müssen wir noch „ausführbar“ machen, also „+x“ für „executable“.

mkdir -p ~/docker/wordpress-php73-apache

wget -q -P ~/docker/wordpress-php73-apache https://raw.githubusercontent.com/docker-library/wordpress/master/php7.3/apache/docker-entrypoint.sh

chmod +x ~/docker/wordpress-php73-apache/docker-entrypoint.sh

Dies waren die Vorbereitungen. Jetzt erstellen wir das „Dockerfile“, die Steuerdatei für den Zusammenbau des Images.

Nicht erschrecken: Das Ding ist ziemlich umfangreich und „erschlägt“ einen gerne, wenn man es zum ersten Mal sieht. Zerlegt in seine Einzelbestandteile ist das Konstrukt aber in sich logisch und nimmt dem Ganzen seinen Schrecken…

Und bis auf einige wenige Änderungen ist diese Datei auch 1:1 vom originalen Dockerfile übernommen worden.

nano ~/docker/wordpress-php73-apache/Dockerfile
### WORDPRESS DOCKERFILE
###
##START
FROM php:7.3-apache-buster

# persistent dependencies
RUN set -eux; \
	apt-get update; \
	apt-get install -y --no-install-recommends \
# Ghostscript is required for rendering PDF previews
        ghostscript \
### msmtp und Hilfsprogramme für Mailversand
        msmtp \
        msmtp-mta \
        bsd-mailx \
        mailutils \
    ; \
    rm -rf /var/lib/apt/lists/*

# PHP Erweiterungen (+zip!) installieren (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions)
RUN set -ex; \
    \
    savedAptMark="$(apt-mark showmanual)"; \
    \
    apt-get update; \
    apt-get install -y --no-install-recommends \
            libjpeg-dev \
            libpng-dev \
            libzip-dev \
            libmagickwand-dev \
	; \
	\
	docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr; \
	docker-php-ext-install -j "$(nproc)" \
		bcmath \
		exif \
		gd \
		mysqli \
		opcache \
		zip \
	; \
	pecl install imagick; \
	docker-php-ext-enable imagick; \
	\
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
	apt-mark auto '.*' > /dev/null; \
	apt-mark manual $savedAptMark; \
	ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \
		| awk '/=>/ { print $3 }' \
		| sort -u \
		| xargs -r dpkg-query -S \
		| cut -d: -f1 \
		| sort -u \
		| xargs -rt apt-mark manual; \
	\
	apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
    rm -rf /var/lib/apt/lists/*
#
# Empfohlene php.ini Einstellungen für opcache setzen...
# https://secure.php.net/manual/en/opcache.installation.php
# https://kinsta.com/blog/php-benchmarks/
RUN { \
		echo 'opcache.memory_consumption=128'; \
		echo 'opcache.interned_strings_buffer=8'; \
		echo 'opcache.max_accelerated_files=50000'; \
		echo 'opcache.revalidate_freq=1'; \
		echo 'opcache.fast_shutdown=1'; \
		echo 'opcache.enable_cli=1'; \
	} > /usr/local/etc/php/conf.d/opcache-recommended.ini
#
# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging
# https://www.php.net/manual/en/errorfunc.constants.php
# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670
RUN { \
		echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \
		echo 'display_errors = Off'; \
		echo 'display_startup_errors = Off'; \
		echo 'log_errors = On'; \
		echo 'error_log = /dev/stderr'; \
		echo 'log_errors_max_len = 1024'; \
		echo 'ignore_repeated_errors = On'; \
		echo 'ignore_repeated_source = Off'; \
		echo 'html_errors = Off'; \
	} > /usr/local/etc/php/conf.d/error-logging.ini
#
### File Upload auf 2G und Memory-Limits auf 512 MB hochschieben. Execution Timeout auf 30m (1800s)
RUN { \
		echo 'file_uploads = On'; \
		echo 'upload_max_filesize = 2G'; \
		echo 'post_max_size = 2G'; \
		echo 'memory_limit = 512M'; \
		echo 'max_execution_time = 1800'; \
		echo 'default_socket_timeout = 1800'; \
	} > /usr/local/etc/php/conf.d/upload-limits.ini
#
### msmtp CONFIG Block
## "sendmail"-Pfad auf "ssmtp" umbiegen
RUN    { \
        echo 'sendmail_path = /usr/bin/msmtp -t -C /etc/msmtprc'; \
    } > /usr/local/etc/php/conf.d/sendmail.ini
## msmtp und SMTP-Postfach konfigurieren
RUN { \
        echo '# Set defaults.'; \
        echo 'defaults'; \
        echo 'logfile /var/log/msmtp.log'; \
        echo '# Enable or disable TLS/SSL encryption.'; \
        echo 'tls on'; \
        echo 'tls_starttls on'; \
        echo 'tls_certcheck off'; \
        echo '# Setup mail to send emails via SMTP'; \
        echo 'account mail'; \
        echo 'host mein.mailserver.de'; \
        echo 'port 587'; \
        echo 'auth login'; \
        echo 'user mail@mein.mailserver.de'; \
        echo 'from mail@mein.mailserver.de'; \
        echo 'password supergeheimesmailpasswort'; \
        echo '# Set a default account'; \
        echo 'account default : mail'; \
} > /etc/msmtprc \
&& chmod 600 /etc/msmtprc && chown www-data:www-data /etc/msmtprc
#
RUN set -eux; \
    a2enmod rewrite expires headers; \
        \
# https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html
    a2enmod remoteip; \
    { \
        echo 'RemoteIPHeader X-Forwarded-For'; \
# these IP ranges are reserved for "private" use and should thus *usually* be safe inside Docker
        echo 'RemoteIPTrustedProxy 10.0.0.0/8'; \
        echo 'RemoteIPTrustedProxy 172.16.0.0/12'; \
        echo 'RemoteIPTrustedProxy 192.168.0.0/16'; \
        echo 'RemoteIPTrustedProxy 169.254.0.0/16'; \
        echo 'RemoteIPTrustedProxy 127.0.0.0/8'; \
    } > /etc/apache2/conf-available/remoteip.conf; \
    a2enconf remoteip; \
#
# https://github.com/docker-library/wordpress/issues/383#issuecomment-507886512
# (replace all instances of "%h" with "%a" in LogFormat)
find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' +

VOLUME /var/www/html

ENV WORDPRESS_VERSION 5.2.3
ENV WORDPRESS_SHA1 5efd37148788f3b14b295b2a9bf48a1a467aa303

RUN set -ex; \
        curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \
        echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \
# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress
        tar -xzf wordpress.tar.gz -C /usr/src/; \
        rm wordpress.tar.gz; \
        chown -R www-data:www-data /usr/src/wordpress

COPY docker-entrypoint.sh /usr/local/bin/

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["apache2-foreground"]
##EOF

Schauen wir uns die Blöcke mal genauer an:

Zeile 4: Das Grundlegende Image, auf dem unser WordPress-Image aufbaut, ist das „php:7.3-apache-buster“. Also ein Debian-10 Image mit Apache und php in Version 7.3. Dieses Image wird beim Bauprozess zuerst geladen. Alle folgenden Instruktionen im Dockerfile erweitern dieses Image dann um die jeweiligen Funktionen und Programme, bis am Schluss unser fertig modifiziertes WordPress Image dabei heraus kommt.

Zeilen 6-18: Als neueste Zugabe wird im offiziellen Image „Ghostcript“ installiert, das für die Ausgabe von PDF-Icons zuständig sein wird. Praktisch, weil das persistent gespeichert bleibt. Da hängen wir gleich noch unsere msmtp-Installation der Programmdateien mit dazu und teilen den Setup- und Config-Block von msmtp zum ersten Mal auf…

Zeilen 20-31: Hier werden Bibliotheken für diverse Hilfsprogramme nachgeladen. Anhand des Namens kannst Du schön erkennen, wofür die jeweils gut sind.

Zeilen 33-41: Jetzt werden eine Reihe von PHP-Erweiterungen geladen und installiert.

Zeilen 42+43: Über pecl (php extension community library) wird die imagick-Ergänzungen zur PHP-Umgebung installiert. Die kümmert sich um die Bearbeitung von Bild-Dateien.
Änderung gegenüber Original: Hier habe ich die Versionsnummern entfernt. Es wird also immer die aktuellste Version gezogen.

Zeilen 45-57: Die nicht mehr benötigten Hilfsprogramme werden, um Platz zu sparen, wieder entfernt. Diese waren nur zur Installation der PHP-Module nötig.

Zeilen 59-69: Für das Chaching Modul „opcache“ schreiben wir eine Conf-Datei mit ein paar Parametern.

Zeilen 71-84: Das „Error-Logging“ von php wird konfiguriert.

Zeilen 86-94: Hier bohren wir jetzt die Limits für die Dateigröße beim Hochladen (2 GB), die Memory Limits (512 MB) und die maximalen Ausführungszeiten (1800s / 30m) massiv auf. Große Dateien brauchen auch lange zum Übertragen!

Zeilen 96-121: Der „Config-Blocl“ von msmtp. Diese Zeilen musst Du an Deine Installation anpassen:
Zeile 112: Der Hostname von Deinem Mailserver, auf dem Du das Mailkonto für den Versand angelegt hast.
Zeilen 115+116: Hier gehört zwei Mal die volle E-Mail Adresse von Deinem Mailkonto eingetragen.
Zeile 117: Das Passwort des Mailaccounts, damit die Mails auch verschickt werden können. Die Anweisung ‚password‘ bleibt stehen, Du ersetzt nur „supergeheimesmailpasswort“ durch Dein eigenes Mail Passwort…

Zeilen 123-137: Die Apache Module „rewrite“, „expires“, „headers“ und in einem extra Block „remoteip“ werden aktiviert. Das „headers“ Modul fügen wir hinzu, das ist normalerweise aus. Brauchen wir aber, weil wir später mit Traefik zusätzliche Header hinzufügen möchten. Das Firewall Plugin wird uns dafür auch danken ;)
Das „remoteip“ Modul tauscht die IP von unserem Reverse-Proxy gegen die „echte“ IP des Besuchers aus. Dazu werden unsere eigenen Docker- und lokalen Netzwerke deklariert und in einer Config-Datei gespeichert. Anschließend wird das Modul neu geladen. Das ist zum Beispiel für das Firewall Plugin sehr wichtig, denn das würde sonst unsere „interne“ IP-Adresse des Docker-Containers aufzeichnen und nicht die „öffentliche“ IP des Angreifers. Was nicht im Sinne des Erfinders wäre ^^

Zeilen 139-141: Im Apache Log werden mit dem kryptischen Befehl alle „%h“ durch ein „%a“ ersetzt.

Zeile 143: Das Volume „/var/www/html“ wird der Docker-Engine zur Verarbeitung übergeben.

Zeilen 145+146: Die Versionsnummer und der „Hash“ von WordPress, die anschließend geladen werden sollen, werden hier eingestellt. Sollte es eine neuere Version von WordPress geben, müssen wir die Versionsnummer und den Hash an dieser Stelle anpassen und dann das Image erneut bauen.
Den Hash bekommen wir über diesen Link: https://wordpress.org/download/releases/
Wir klicken bei der passenden Version in der Spalte „.tar.gz“ auf den „sha1“-Link. Der Hash wird dann einfach per Copy/Paste übertragen.

Zeilen 148-154: WordPress wird jetzt aus den offiziellen Quellen heruntergeladen und in unser Image entpackt. Anschließend werden die Installationsdateien und nicht mehr benötigte Hilfsprogramme entfernt.

Zeile 156: Das Entrypoint-Script wird ins Image kopiert.

Zeilen 158+159: Der Entrypoint wird gesetzt und zum Abschluss kommt der Befehl, der Apache hochlaufen lässt, wenn wir den Container starten.

Image bauen

Damit ist das „Dockerfile“ fertig und wir starten den „Bauprozess“:

„docker build“ weist Docker an, aus einem Dockerfile heraus ein Image zu bauen. „-t“ ist der „Tag“, also die Bezeichnung von dem Image. Hier nenne ich das Image wie auch das Verzeichnis nach der Anwendung, der php-Version und dem verwendeten Webserver. Ein Doppelpunkt grenzt den Namen von der Versionsnummer ab. Wie wir im Dockerfile gesehen haben, ist dies hier die Version 5.2.3 von WordPress. Als Parameter wird im Anschluss der Ordner übergeben, in dem sich das Dockerfile befindet.

docker build -t wordpress-php73-apache:5.2.3 ~/docker/wordpress-php73-apache

Was jetzt kommt mutet an wie die Bildschirmausgabe im Kommandobunker von einem Kriegsfilm: Wilde verkettete Befehle, Zeilensprünge, „wirre“ Kommandos, die abgearbeitet werden…

Das alles ist beim ersten Mal sehr erschreckend, aber völlig normal. Hier laufen nun die „build“-Prozesse der Reihe nach durch. Hin und wieder erkennen wir sogar einen der Befehle aus dem Dockerfile.

Das Ganze dauert runde fünf Minuten, wobei das stark vom verwendeten Server abhängt. Am Schluss schreibt uns Docker die erlösenden Zeilen:

Successfully built 92100c3a9f43
Successfully tagged wordpress-php73-apache:5.2.3

Glückwunsch! Das Image ist jetzt fertig!

Wir taggen das Image jetzt noch einmal und geben Docker quasi eine „Weiterleitung“ mit dem „:latest“ Tag, das wir mit der gerade gebauten Version 5.2.3 verknüpfen:

docker tag wordpress-php73-apache:5.2.3 wordpress-php73-apache:latest

Damit sind wir in der Lage, anschließend das WordPress Image im Container mit „:latest“ zu deklarieren. Sollte Version 5.2.4 kommen und wir ein neues Image gebaut haben, brauchen wir das nur noch mit „:latest“ zu taggen. Der Container wird beim nächsten Start dann das neue Image benutzen. Wir sparen uns quasi das ständige Ändern der Versionsnummern in unseren „docker-compose“-Dateien…

Im nächsten Kapitel werden wir die „docker-compose“-Datei für WordPress definieren und dort gleich unser frisch gebackenes Image verwenden!

Anzeige *

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Verwendung
von Cookies

Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen zu Cookies erhalten Sie in unserer Datenschutzerklärung.

Scroll to Top