WordPress Testumgebungen in Docker

Docker.io Logo

Docker wirkt unter Umständen ziemlich kompliziert, so habe auch ich den ein oder anderen Artikel zu dieser tollen Software geschrieben, der es für den Anfang womöglich etwas zu weit treibt und dabei vergessen lässt, dass Docker wahnsinnig praktisch, einfach und modular ist.

Das möchte ich im Verlauf richtig stellen…

WordPress Testumgebungen in Docker:

  • Docker auf Server installieren (Debian/Ubuntu)
  • Fertige WordPress und MySQL Images herunterladen
  • Mehrere Container miteinander verlinken und starten
  • WordPress „Produktiv nach Testing“ klonen (WordPress Plugin)

Ich verwende ausschließlich Images aus dem offizielle Docker Hub, um es nicht unnötig kompliziert zu machen.

Zur Information: Laut Dockerfiles basieren beide Images (WordPress + MySQL) auf Debian Wheezy

Installation Dockers

Debian Wheezy

Installation des Kernels aus dem Backport Repository mit anschließendem Neustart.
Dies ist notwendig, da erst ein Kernel ab Version 3.10 empfohlen wird.

echo deb http://ftp.us.debian.org/debian wheezy-backports main > /etc/apt/sources.list.d/wheezy-backports.list
apt-get update -y
apt-get -t wheezy-backports install linux-image-amd64 -y # Für ein amd64-basierendes System
reboot
OVH VMware vServer Besitzer sollten die Datei „/etc/grub.d/06_OVHkernel“ vor dem Neustart löschen und „update-grub2“ ausführen, damit der neue Kernel aktiv wird.
Der OVH Kernel ist leider etwas beschnitten und bietet unter anderem keine cgroups.

Nun Docker installieren (lassen). Vorab „curl“ installieren:

apt-get install curl
curl -sSL https://get.docker.io/ | bash

Ubuntu 14.04

Ich empfehle den Docker Installer zu verwenden. Es wird das offizielle Repository installiert. Auch hier im Vorfeld „curl“ installieren:

apt-get install curl
curl -sSL https://get.docker.io/ubuntu/ | bash

Docker Einrichtung

Docker ist etwa wie Lego, verschiedene Module werden miteinander verknüpft und bilden eine ganze App.
Im Fall WordPress werden zwei Bausteine benötigt.

-------------             ---------
| WordPress | <---------> | MySQL |
-------------             ---------

Docker bringt mit WordPress auch gleich die Web-Server Appliance mit (Apache2), weshalb dieser nicht als Baustein oben aufgeführt ist.

Ich könnte auf folgende Befehle verzichten, da ein „pull“ auch durch ein „run“ ausgelöst würde (im nächsten Schritt), aber es ist vielleicht verständlicher für den Anfang:

docker pull wordpress
docker pull mysql

Somit sind beide Images (Bausteine) für eine WordPress Infrastruktur lokal abgelegt.
Optional hätte hier auch „mysql:5.5“ stehen können, womit ein Tag (oft für eine Version verwendet) angegeben wäre. Mehr dazu im Verlauf.

Allerdings startet Docker nie Images, sondern immer Container auf Basis eines Images.
Das ergibt die Möglichkeit, einen Baustein (fast) beliebig oft zu verwenden und jede Menge Testumgebungen zu schaffen.

So erstelle ich direkt zwei MySQL Container:

docker run --name mysql-container-1 -e MYSQL_ROOT_PASSWORD=q5iBzWs4h7nCyPeSmjn0 -d mysql
docker run --name mysql-container-2 -e MYSQL_ROOT_PASSWORD=Dl4M7hVoEDiQiJQC0Fci -d mysql:5.7

Den ersten Container nenne ich demnach „mysql-container-1“, den zweiten „mysql-container-2“.

Via Environment Variable gebe ich ein MySQL Root Passwort mit. Diese Variablen sind je nach Image unterschiedlich, dazu bitte immer das Docker Hub zur Hand nehmen und durchlesen, welche Attribute mitgegeben werden können (in diesem Fall: https://registry.hub.docker.com/_/mysql/)

Weiterhin gebe ich für den ersten Container keinen „Tag“ nach „mysql“ an, es wird „latest“ angenommen, in diesem Fall bedeutet das MySQL in Version 5.6.

Ein „Tag“ ist hingegen für den zweiten Container festgelegt: mysql:5.7. Ergo MySQL in Version 5.7. Auch die Tags eines Images sind immer dem Docker Hub zu entnehmen!

Wurden beide Befehle ausgeführt, sind die Container auch schon aktiv/gestartet (die IDs sind zufällig):

root@vps96713:~/build# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
20a245efe5b3        -a:latest           "/entrypoint.sh mysq   5 seconds ago       Up 5 seconds        3306/tcp            mysql-container-2
8de566127e89        -a:latest           "/entrypoint.sh mysq   8 seconds ago       Up 7 seconds        3306/tcp            mysql-container-1

Das war einfach, oder?

Die Ausgabe „PORTS“ beschreibt „exposed“ Ports. Diese Ports wurden vom Ersteller des Images festgelegt und bedeuten, dass diese Schnittstellen von anderen Containern zur Kommunikation benutzt werden können. Ansonsten wäre so ein MySQL Container ja auch ziemlich wertlos…

Nun möchte ich auch zwei WordPress Installationen ablegen/starten:

docker run --name wordpress-spielwiese-1 --link mysql-container-1:mysql -p 8080:80 -d wordpress
docker run --name wordpress-spielwiese-2 --link mysql-container-2:mysql -p 8081:80 -d wordpress

Wieder wähle ich individuelle Namen für die Container (> „wordpress-spielwiese-1“ und „wordpress-spielwiese-2“).

Jetzt folgt der große Spaß, den Docker mitbringt: Ich verlinke jeweils einen MySQL Container mit einer WordPress Installation.

Das passiert durch „–link container-name:alias“. Der Alias ist frei zu wählen.
Ich erweise mich als unkreativ und entscheide mich für „mysql“.

Durch den Switch „-p“ wird ein Port aus einem Container an den Host weitergeleitet.
So wird ein Zugriff via Browser auf Port 8081 zu Port 80 der WordPress Spielwiese 2 weitergeleitet. Gleiches Gilt für Port 8080 und Port 80 der Spielwiese 1.

WordPress hat nun also seine benötigte MySQL Installation an der Hand und – ganz wichtig – Zugriff auf die Environment Variablen, die für diese festgelegt wurden.

„wordpress-spielwiese-1“ weiß durch den Link zu „mysql-container-2“, dass „MYSQL_ROOT_PASSWORD=Dl4M7hVoEDiQiJQC0Fci“ lautet. Und das ist wichtig! Denn…
Öffne https://registry.hub.docker.com/_/wordpress/ und stelle fest, dass es eine Menge Variablen gibt, die hätten mitgegeben werden können:

-e WORDPRESS_DB_USER=… (defaults to “root”)
-e WORDPRESS_DB_PASSWORD=… (defaults to the value of the MYSQL_ROOT_PASSWORD environment variable from the linked mysql container)
-e WORDPRESS_DB_NAME=… (defaults to “wordpress”)
-e WORDPRESS_AUTH_KEY=…, -e WORDPRESS_SECURE_AUTH_KEY=…, -e WORDPRESS_LOGGED_IN_KEY=…, -e WORDPRESS_NONCE_KEY=…, -e WORDPRESS_AUTH_SALT=…, -e WORDPRESS_SECURE_AUTH_SALT=…, -e WORDPRESS_LOGGED_IN_SALT=…, -e WORDPRESS_NONCE_SALT=… (default to unique random SHA1s)

Allerdings sind die „Defaults“ alle annehmbar. Zu sehen ist, dass „WORDPRESS_DB_PASSWORD“ dem Wert „MYSQL_ROOT_PASSWORD“ aus einer verknüpften MySQL Installation entspricht. Somit ist alles notwendige für eine lauffähige Installation gegeben.

Noch einmal schaue ich mir den Status der Container an:

root@vps96713:~/build# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                  NAMES
38b039fef2cd        wordpress:latest    "/entrypoint.sh apac   3 minutes ago       Up 3 minutes        0.0.0.0:8081->80/tcp   wordpress-spielwiese-2
64232ec1223f        wordpress:latest    "/entrypoint.sh apac   3 minutes ago       Up 3 minutes        0.0.0.0:8080->80/tcp   wordpress-spielwiese-1
20a245efe5b3        -a:latest           "/entrypoint.sh mysq   3 minutes ago       Up 3 minutes        3306/tcp               mysql-container-2
8de566127e89        -a:latest           "/entrypoint.sh mysq   4 minutes ago       Up 4 minutes        3306/tcp               mysql-container-1

Unter „PORTS“ ist nun ebenso die Weiterleitung des jeweiligen Ports in den Container zu sehen.

Das war es schon.

Mit dem Browser öffne ich die URLS

http://1.2.3.4:8080
http://1.2.3.4:8081

wobei 1.2.3.4 für die IP des Hosts steht. Denn das interne Docker Netzwerk wird automatisch verwaltet.
Empfangen werde ich von der Installationsroutine WordPress‘:

Wordpress Installation
WordPress Installation

Alle Parameter zur Installation wurden bereits durch Docker konfiguriert, es fehlen nur noch die wesentlichen Details wie der Name des Blogs etc.

Verwaltung der Container

Die wichtigsten Befehle, um die erstellten Container/heruntergeladenen Images zu verwalten, nöchte ich nicht vorenthalten.
Bitte lest auf jeden Fall auch den User Guide durch.
pre>docker stop wordpress-spielwiese-1 # wordpress-spielwiese-1 anhalten
docker stop wordpress-spielwiese-1 # wordpress-spielwiese-1 starten
docker rm wordpress-spielwiese-1 # Den Container wordpress-spielwiese-1 löschen!
docker rmi wordpress # Das Image „wordpress“, das aus dem Docker Hub geladen wurde vom lokalen Host entfernen
docker rmi mysql:5.7 # Lediglich Version/Tag „5.7“ des Images „mysql“ vom lokalen Host löschen

Es wird auffallen, dass die oben erstellten WordPress Installationen nur dann starten, wenn auch der verlinkte MySQL Container gestartet wurde.

WordPress klonen

Für die Kopie meiner WordPress Installation verwendete ich das Plugin „All-in-One WP Migration“.
Nach der Installation befindet sich auf der linken Seite im Admin-Bereich der Punkt „Site Migration“. Die Verwendung ist wirklich selbsterklärend…

Site Migration Plugin
Site Migration Plugin

Der Import gestaltet sich genauso reibungslos.
Ich habe keine Probleme mit dem Plugin gehabt, nehme aber gerne Vorschläge zu Alternativen entgegen.

TL;DR

Docker installieren:

apt-get install curl
curl -sSL https://get.docker.io/ | bash # Debian
curl -sSL https://get.docker.io/ubuntu/ | bash # Ubuntu

Container starten:

docker run --name mysql-container-1 -e MYSQL_ROOT_PASSWORD=q5iBzWs4h7nCyPeSmjn0 -d mysql
docker run --name mysql-container-2 -e MYSQL_ROOT_PASSWORD=Dl4M7hVoEDiQiJQC0Fci -d mysql:5.7
docker run --name wordpress-spielwiese-1 --link mysql-container-1:mysql -p 8080:80 -d wordpress
docker run --name wordpress-spielwiese-2 --link mysql-container-2:mysql -p 8081:80 -d wordpress

Zugriff auf http://host:8080 sowie http://host:8081.

16 Antworten auf “WordPress Testumgebungen in Docker

  1. Johannes

    Hallo, faszinierendes Teil, dieses Docker.io! Ist das hauptsächlich zum Testen einzelner Pakete gedacht oder macht das auch produktiv Sinn? Ich habe ca. 5 Kundenwebseiten, die ich entweder alle auf einem vServer betreiben würde mit einer nginx-Instanz, PHP-FPM und mysql, oder halt eben pro Webseite ein Container.
    Wie sieht das performancemäßig aus? Wie würde man verschiedene Domains auf die verschiedenen Container forwarden (quasi virtual hosts, aber jeder Container hat ja nur eine Seite)?`Oder ist das dafür alles nicht geeignet.

    1. André P. Autor

      Wenn die Seiten nicht so aufwändig sind, würde ich es schon fast lassen und nur auf die Kunden zugeschnittene PHP-FPM Worker erstellen (open_basedir und die ganzen Klassiker, damit der eine nicht ins Verzeichnis vom anderen kommt etc.).
      Aber klar, denkbar ist das schon. Ist zwecks Versionierung bestimmt auch interessant.
      Ich würde vielleicht auch noch systemd-nspawn anschauen, was dem sehr nahe kommt, nur vielleicht etwas simpler ist. So hättest du Container mit eigenem Init-System und definitiv mehr Freiheiten. Diese Container könntest du zusätzlich in ihrem Resourcen begrenzen. Kannst hier im Blog mal danach suchen. :-)

      Wenn es doch Docker sein soll, gibt es verschiedene Möglichkeiten zu forwarden. Ich glaube, ich würde mich für einen simplen Reverse Proxy entscheiden, der auf dem Host läuft und dann entsprechend der Namen an die Container weiterleitet.

      Würde das Thema gerne noch ausweiten und mehr recherchieren, bin aber ziemlich kaputt, war wieder eine ganze Menge zu tun heute… :-)

  2. Christoph

    Nach längerer Fehlersuche funktionert folgendes:
    „git clone https://github.com/docker-library/wordpress.git
    ins Verzeichnis wechseln und das Image per „docker build -t wordpress/own .“ bauen lassen. Danach funktioniert alles wie gewünscht.
    Warum das eigentliche Image nicht „korrekt“ funktionert … scheint an den Rechten einer älteren Version von docker-entrypoint.sh
    https://github.com/docker-library/wordpress/commit/8a3f1826ecd05b20a1e903bf250cc836c7b9657c
    zu liegen.

    1. Christoph

      Hm, so langsam spamme ich deinen Blog zu! ;o)
      Nachdem die Images erst einmal laufen und ich eine erste Testwordpresspage erstellt habe, wollte ich diese klonen. Plugin installiert, aber Export läuft nicht durch, nur wenn ich die Datenbank ausschließe dann gehts. Dann läuft aber der Import in der 2ten Spielwiese nicht duch!?
      Kannst du von Spielwiese1 deine Page in Spielwiese2 importieren, so als wenn es ein Klon wäre ohne nachträgliche Anpassungen?

      1. André P. Autor

        Hi,
        macht nichts, finde es nett, dass du mich up-to-date hälst.
        Bin noch nicht dazu gekommen es selber auf Ubuntu zu testen, deine Erklärung erscheint aber plausibel. Danke für die Information!
        Von WordPress-1 nach WordPress-2 habe ich es noch nicht ausprobiert, habe aber kein Problem mit dem Export dieses Blogs und dem Import in eine der beiden Installationen.
        Was für Fehler bekommst du denn?

        1. Christoph

          Ich bekomme beim exportieren einen „white screen“ und muss dann über den Browser zurück gehen. Danach ist die WordPressseite in maintenance. Wenn ich ohne Datenbank exportieren will, dann geht es. Der Import funktioniert dann damit auch nicht.
          Kann es damit was zu tun haben, dass mysql in einem anderen Container als WordPress läuft?
          Ich möchte mal Debian ausprobieren. Welches Image hast du verwendet?

          1. André P. Autor

            Im Moment des White Screens, wird PHP einen Fehler reported haben, schau dann am Besten mal in die Apache Error Logs. Ist bestimmt etwas, das sich leicht beheben lässt. Es wird eher nicht daran liegen, dass MySQL in einem anderen Container läuft.
            Debian verwende ich in stabiler Ausführung, allerdings brauchst du einen etwas neueren Kernel (aus den Backports). Oder du verwendest direkt „jessie“/“testing“.

            1. Christoph

              Das Logfile sehe ich doch per „docker logs wordpress-spielwiese-2“ oder?
              Gibts noch eine andere Möglichkeit, „Zugang“ zu dem Container zu bekommen?
              Landen alle Logfiles in einem, unter „/var/lib/docker/containers/0cf7a33a4a6ebae1276f59dd8b369a5e43aa51db7532a20058eae3b33b4e363f/ 0cf7a33a4a6ebae1276f59dd8b369a5e43aa51db7532a20058eae3b33b4e363f-json.log ?

              1. Christoph

                Jetzt möchte ich wenigstens noch ein Fazit posten. Mittlerweile nehme ich die Images von tutum. Mit diesen gibt es keine Probleme bei dem Im- und Export der WordPressseite. Das Dockerfile des WordPressimages habe ich etwas modifiziert und das image selbst gebaut.
                Nachträglichen Zugang zum Container erhält man mit „docker exex -it bash“

              2. André P. Autor

                Ohje, sorry, total untergegangen, das sollte nicht passieren!
                Genau, wie du schon selber festgestellt hast, kannst du den CMD oder EntryPoint mit /bin/bash überschreiben und den „-i“ (interaktiv) Switch setzen. Das, was du in den Logs siehst, wird wohl dem entsprechen, was du siehst, wenn du dich mit „docker attach“ einhängst.
                Während der Laufzeit könntest du wohl auch in /var/lib/docker/XYZ deinen Container finden und durchstöbern, würde ich aber von abraten. Der saubere Weg ist auf jeden Fall eine Shell im Container zu starten und sich dann zu attachen. Abraten würde ich auf jeden Fall davon, eine SSH im Container laufen zu lassen. Wird leider häufig gemacht, passiert dann mit Tools wie „Supervisord“, die Pseudo-Daemons (kann man das so nennen?) im Container zulassen.

    2. car insurance quote

      Preparing a business expense whereas a policy might be able to reduce that payment. But of course, maycheck your coverage to be! There are simple tips on how to qualify for a contract with any other item, several retailer carries comparable, if not thousands, of Rands, so surethey know you’re not getting ripped off by family and loved ones, and settle for „cheap“ insurance, is to try and try and find the online sites have almost doubled somecar insurance companies. As an automobile or other professional risks. This all underlies the importance of giving your prospective insurance company’s history in great detail in your vehicle for you yourabove situations have changed the no-fault part of the best service or charge card being maxed out your zip code. Good luck and got your car is a budget for providerslosses. Definitely, being run and great insurance company to see and buy the rental company? Always keep in mind when buying inexpensive auto insurance shoppers can get a higher rate knowwith an accident and the place for a quick and the payment you can get back to you in getting a car dealer may step in finding out about discount these.

  3. Christoph

    Die Anleitung finde ich Klasse um WordPress einfach einmal ausprobieren zu können.
    Was allerdings nicht geht, ist die Sprache zu Beginn der Installation einzustellen und das Plugin “All-in-One WP Migration” (per ftp gehts nicht, per Upload geht es nicht auf Grund mangelnder Rechte) zu installieren.
    Wie hat das bei dir funktioniert?

    1. André P. Autor

      Hi,
      auf welcher Distribution hast du Docker denn installiert? Mir scheint als würdest du einfach keine Schreibrechte im Container haben.
      Ich habe gerade extra eine Debian VM aufgesetzt und es getestet, hier funktioniert noch alles.

      1. Christoph

        Mist falsche Formatierung! Nun ohne:
        Ich nutze Ubuntu14.04 64bit mit Docker.
        Ich hab jetzt mal Spielwiese 2 so gestartet:
        docker run –name wordpress-spielwiese-2 -i -t –link mysql-container-2:mysql -p 8081:80 wordpress /bin/bash
        Die Rechte von /var/www/html sehen so aus:
        root@a55c594c693b:/var/www/html# ls -l
        total 180
        -rw-r–r– 1 nobody nogroup 418 Sep 25 2013 index.php
        -rw-r–r– 1 nobody nogroup 19930 Apr 9 2014 license.txt
        -rw-r–r– 1 nobody nogroup 7192 Apr 21 2014 readme.html
        nach einem „chown www-data:www-data html -R“ kann ich plugins installieren. An was liegt das?
        Ich habe /var/lib/docker auf einer anderen Partition als Ubuntu liegen.

Schreibe einen Kommentar

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