Docker Stack – NGINX mit PHP 7.2 und MySQL

Docker bietet durch die Erweiterungen Docker Compose und Docker Stack die Möglichkeit verschiedene Container und Services zu erstellen und zu verwalten. Während Docker Compose eine Erweiterung von Docker ist, welche zusätzlich installiert werden muss, ist Docker Stack eine direkt von Docker zur Verfügung gestellte Funktion. Beide Funktionen sind sehr ähnlich und unterscheiden sich nur minimal. So können mit Docker Compose Container erstellt werden, während mit Docker Stack Services erstellt und verwaltet werden. Mit beiden Funktionen kann aber die Docker Compose Datei (ab der Version 3.0) zur Definition der Container / Services verwendet werden. Der Umfang der in der Docker Compose Datei verfügbaren Optionen unterscheidet sich je nach eingesetzter Funktion. Für den Docker Stack wird der Docker Swarm benötigt. Der Docker Swarm kann dabei auch für eine einzelne Maschine mit dem Befehl docker swarm init initialisiert werden. In diesem Artikel wird beschrieben, wie ein Docker Stack mit NGINX, PHP 7.2 und MySQL 5.7 eingerichtet werden kann.

Mit dem Stack können Anwendungen wie TYPO3, WordPress oder aber auch eigene Web-Anwendungen eingerichtet und verwendet werden. Der Stack kann aber auch jederzeit um weitere Services (z.B. PostgreSQL-Datenbank) erweitert werden. All diese Services können in einer einzelnen Datei beschrieben und darüber eingerichtet werden.

Einrichtung von NGINX

NGINX ist, wie auch Apache, unter anderem ein Webserver. Im Vergleich zu Apache bietet NGINX jedoch eine spürbar bessere Performance. Für NGINX wird ein eigener Service verwendet, welcher mit dem offiziellen NGINX-Image erstellt wird. Um einen einfachen NGINX-Server starten zu können, kann die folgende Definition in der Datei “docker-compose.yml” verwendet werden:

version: '3'
services:
  nginx-example:
    image: nginx:1.13-alpine
    ports:
      - "80:80"

Mit dieser Definition kann der NGINX-Server bereits gestartet werden. Die Einrichtung kann über den Befehl docker stack deploy -c docker-compose.yml example gestartet werden. Der Server sollte anschließend über die entsprechende IP-Adresse oder den Hostnamen des Servers erreichbar sein. Im Browser sollte dann die NGINX-Standardseite angezeigt werden:

Standardseite des NGINX-Server

Um nun auch eigene Inhalte anzeigen zu können muss ein Volume (Speicher) eingebunden werden. Das Volume kann mit einem Verzeichnis auf dem Host-System verbunden werden um auch im Betrieb weitere Inhalte einfügen zu können. Die Definition wird nun wie folgt erweitert:

version: '3'
services:
  nginx-example:
    image: nginx:1.13-alpine
    ports:
      - "80:80"
    volumes:
      - ./www:/www

Das Verzeichnis “www” auf dem Host-System, welches sich im gleichen Verzeichnis wie die Datei “docker-compose.yml” befindet, wird in den Service eingebunden. Dort stehen die Inhalte im Verzeichnis “www” zur Verfügung. Doch der NGINX-Server kennt dieses Verzeichnis nicht bzw. verwendet dieses Verzeichnis nicht als Ausgabe-Verzeichnis. Über eine Konfigurationsdatei kann dem NGINX-Server die entsprechende Information mitgeteilt werden:

server {
     index index.html;
     root /www;
}

Es werden die folgenden Einstellungen vorgenommen:

  • index index.html – Wenn keine bestimmte Datei aufgerufen wird, soll die Datei “index.html” angezeigt werden. Diese Einstellung findet man in den meisten Web-Servern.
  • root /www – Das Verzeichnis welches zur Ausgabe verwendet werden soll. In diesem Verzeichnis befinden sich die Dateien welche über den Browser aufgerufen werden können.

Diese Konfiguration kann ebenfalls über ein Volume dem Service und somit dem NGINX-Server zur Verfügung gestellt werden:

version: '3'
services:
  nginx-example:
    image: nginx:1.13-alpine
    ports:
      - "80:80"
    volumes:
      - ./www:/www
      - ./config/site.conf:/etc/nginx/conf.d/default.conf

Um nun die bereits erstellten Services mit den oben vorgenommenen Änderungen zu aktualisieren, muss erneut der Befehl docker stack deploy -c docker-compose.yml example ausgeführt werden. Anschließend wird der Stack aktualisiert. Der Stack ist nun nach der Aktualisierung in der Lage Dateien aus dem Verzeichnis “www” (und Unterverzeichnissen) im Browser anzuzeigen. Es können auch jederzeit weitere Dateien über das Verzeichnis “www” im Host-System zur Verfügung gestellt werden. Der Stack kann alledings keine PHP-Dateien verarbeiten. Um also auch dynamische Inhalte verarbeiten zu können, wird ein weiterer Service benötigt.

Einrichtung von PHP

Um nun auch PHP-Dateien verarbeiten zu können wird ein weiterer Service erstellt. Jedoch muss für diesen Service ein neues Image auf Basis des offiziellen PHP-Image erstellt werden, um später auch mit der MySQL-Datenbank kommunizieren zu können. Im offiziellen PHP-Image sind die Erweiterung mysqli oder PDO nicht vorinstalliert. Jedoch werden diese Erweiterungen für eine Verbindung zur MySQL -Datenbank benötigt. Mit der nachfolgenden Dockerfile können die Erweiterungen mysqli und PDO installiert werden:

FROM php:7.2-fpm
RUN docker-php-ext-install -j$(nproc) mysqli
RUN docker-php-ext-install -j$(nproc) pdo 
RUN docker-php-ext-install -j$(nproc) pdo_mysql

Mit dem Befehl docker build -t php7.2-mysql . kann aus diesem Dockerfile ein Image erstellt werden, welches sich dann mit dem Namen “php7.2-mysql” auf der Maschine befindet. So kann statt dem offiziellen PHP-Image dieses selbst erstellte Image in der Definition des Services verwendet werden. Die Definition wird nun wie folgt erweitert:

version: '3'
services:
  nginx-example:
    image: nginx:1.13-alpine
    ports:
      - "80:80"
    volumes:
      - ./www:/www
      - ./config/site.conf:/etc/nginx/conf.d/default.conf
  php-example:
    image: php7.2-mysql
    volumes:
      - ./www:/www

Dadurch kann der Stack nun theoretisch auch PHP-Dateien aus dem gleichen Ausgabe-Verzeichnis zur Verarbeitung annehmen. Jedoch müssen der NGINX-Service und der PHP-Service miteinander verbunden werden. Die Konfiguration wird nun erweitert damit der NGINX-Server Anfragen an eine PHP-Datei an den PHP-Service weiterleiten kann:

server {
     index index.html index.php;
     root /www;

     location ~ \.php$ {
         try_files $uri =404;
         fastcgi_split_path_info ^(.+\.php)(/.+)$;
         fastcgi_pass php-example:9000;
         fastcgi_index index.php;
         include fastcgi_params;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
         fastcgi_param PATH_INFO $fastcgi_path_info;
     }
}

Auch der Index des Servers wurde angepasst so dass nun auch die Datei “index.php” als Standard geladen werden kann, wenn keine bestimmte Datei aufgerufen wurde. Die PHP-Datei wird durch die zusätzliche Konfiguration an den PHP-Service weitergeleitet und verarbeitet. Die Ausführung der PHP-Dateien findet dabei über FastCGI statt, welches deutlich effizienter und schneller in der Verarbeitung ist. Mit dem Befehl docker stack deploy -c docker-compose.yml example kann der Stack nun um den PHP-Service erweitert werden.

Einrichtung von MySQL

In den meisten Web-Anwendungen wird auch eine Datenbank benötigt. Das mit am häufigsten verwendete Datenbanksystem ist MySQL. Auch für die MySQL-Datenbank wird ein eigener Service, auf Basis des offiziellen MySQL-Images, erstellt. Die Docker Compose Datei wird nun um die Definition des MySQL-Services erweitert:

version: '3'
services:
  nginx-example:
    image: nginx:1.13-alpine
    ports:
      - "80:80"
    volumes:
      - ./www:/www
      - ./config/site.conf:/etc/nginx/conf.d/default.conf
  php-example:
    image: php7.2-mysql
    volumes:
      - ./www:/www
  mysql-example:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: test123

Für die Einrichtung der MySQL-Datenbank muss das Passwort des Benutzers “root” festgelegt werden. In diesem Fall verwenden wir dazu das Passwort “test123”, welches vor der Einrichtung durch ein komplexeres Passwort ersetzt werden sollte. Weitere Einstellungen können der Dokumentation des Images im Kapitel “Environment Variables” entnommen werden. So könnte auch ein neuer Benutzer inkl. Passwort sowie eine bestimmte Datenbank direkt mit der Erstellung des Services eingerichtet werden. Um nun auch den letzten Service zum Stack hinzufügen zu können, muss ein letztes Mal der Befehl docker stack deploy -c docker-compose.yml example ausgeführt werden. Nach der erfolgreichen Aktualisierung sollte nun auch der MySQL-Service zur Verfügung stehen.

Fazit

Nach einer erfolgreichen Einrichtung sollten auf dem Server die folgenden Services vorhanden sein:

  • nginx-example:80 – Der Webserver welcher über die IP oder den Hostnamen des Host-Servers erreichbar sein sollte.
  • php-example:9000 – Der PHP-Service welcher über FastCGI die Verarbeitung von PHP-Dateien ermöglicht.
  • mysql-example:3306 – Die MySQL-Datenbank um Informationen und Daten speichern zu können. Die Verbindung kann mit dem Benutzernamen “root” und “test123” hergestellt werden.

Alle Services befinden sich innerhalb eines Netzwerks und können über die Namen angesprochen werden.

Mit den oben gezeigten Konfigurationen wurde nun ein einfacher Web-Server mit NGINX, PHP 7.2 und MySQL 5.7 eingerichtet. Der Server kann für die Anzeige einer Website mit PHP und MySQL verwendet werden. Der Fokus dieser Anleitung liegt nicht auf der Sicherheit sondern nur auf der Funktion. Es fehlt die Einrichtung eines SSL-Zertifikats oder anderer sicherheitsrelevanter Einstellungen. Diese Anleitung kann jedoch als Grundlage und Einstieg in dieses Thema verwendet werden.  Die gesamte Konfiguration kann auch auf GitHub nochmals als Zusammenfassung heruntergeladen werden.

Avatar for Sebastian Brosch

Sebastian Brosch

Ich bin gelernter Fachinformatiker für Anwendungsentwicklung und konnte bereits Erfahrungen in der Entwicklung von Desktop- und Web-Anwendungen sammeln. In diesem Blog schreibe ich über Probleme und Erfahrungen aus dem Gebiet der Anwendungsentwicklung. Ich werde hier meist Artikel aus den Bereichen .NET, Datenbanken (hauptsächlich T-SQL und MySQL), PHP, HTML, CSS und Docker schreiben.

3 Antworten

  1. Avatar for hardy hardy sagt:

    Bei mir klappt das so nicht.
    Es kommt nach dem Befehl docker stack deploy -c docker-compose.yml example “yaml: line 1: did not find expected key”.

    Welche Dateien müssen denn im gleichen Ordner sein? Und wie müssen die heißen? docker-compose.yaml dockerfile config.yaml www ??

    Bin eine Docker-Neuling – würde mich über ein paar Hinweise freuen.

  2. Avatar for Georg Georg sagt:

    Super, herzlichen Dank!
    Im Standard-Modul von PHP-FPM ist nur PDO_sqlite vorinstalliert.
    Danke dass du hier die Anleitung zum Einfügen des MySQL-Treibers veröffentlicht hast, das hat mir sehr viel Zeit erspart!

Schreibe einen Kommentar

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