Docker: Apache, MySQL, PHP und PhpMyAdmin im Container-Verbund
In diesem Beitrag bauen wir einen Web Application Stack mit Docker-Containern, bestehend aus Apache, MySQL, PHP (inkl. Redis) und PhpMyAdmin. Jeder Service läuft in einem eigenen Container. Auf diese Weise ist der Stack modular mit weiteren Diensten erweiterbar. Mit wenigen Handgriffen kann z.B. MySQL gegen PostgreSQL oder PHP 7.4 gegen eine andere Version getauscht werden. SSL und XDdebug sind bereits vorkonfiguriert. Der Stack kann somit für Development oder App Deployment benutzt werden.
Damit alles schön zusammen passt und wir möglichst wenig Aufwand haben, basiert alles auf den Docker Images von Bitnami.
Für unser Projekt benötigen wir die folgende Verzeichnisstruktur:

Der Unterordner “Build” ist nur für Geräte mit Apple Silicon relevant. Dazu später mehr.
Da alle Container über Docker Compose gestartet werden, erstellen wir zuerst die docker-compose.yml-Datei im Ordner “dstack”, neben dem Unterordner “docker”:
# AMPP 1.0.9
#
# Runs Apache, MySQL, PHP (+Redis) and PhpMyAdmin
# SSL is preconfigured.
# Imagemagick and XDebug are activated.
#
# Run with
# docker-compose up -d
#
# (C)2020-2022 Harald Schneider
#
version: "3"
services:
# --- MySQL 5.7
#
mysql:
container_name: "ampp-mysql"
image: bitnami/mysql:5.7
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=MYSQL_PASSWORD
- MYSQL_USER=admin
- MYSQL_PASSWORD=MYSQL_PASSWORD
ports:
- '3306:3306'
volumes:
- ./docker/mysql/data:/bitnami/mysql/data
- ./docker/mysql/backup:/backup
# --- PHP 7.4
#
php:
container_name: "ampp-php"
image: bitnami/php-fpm:latest
restart: unless-stopped
depends_on:
- redis
volumes:
#- /Users/hschneider/Work/Web:/app:delegated
- ./docker/www:/app:delegated
- ./docker/php/php.ini:/opt/bitnami/php/etc/conf.d/php.ini:ro
# --- Apache 2.4
#
apache:
container_name: "ampp-apache"
image: bitnami/apache:2.4
ports:
- '80:8080'
- '443:8443'
depends_on:
- php
volumes:
#- /Users/hschneider/Work/Web:/app:delegated
- ./docker/www:/app:delegated
- ./docker/apache/my_vhost.conf:/vhosts/myapp.conf:ro
- ./docker/apache/certs:/certs
# Use this for bitnami's builtin certs:
# ./docker/apache/certs:/opt/bitnami/apache2/conf/bitnami/certs
# --- Redis 6.0
#
redis:
container_name: "ampp-redis"
image: bitnami/redis:6.0
restart: unless-stopped
environment:
- REDIS_PASSWORD=at15jx13
# --- PhpMyAdmin latest
# Acccess via
# http://127.0.0.1:8180 or https://127.0.0.1:8143
# Login with user root and mysql-password.
#
phpmyadmin:
container_name: "ampp-phpmyadmin"
image: bitnami/phpmyadmin:latest
depends_on:
- mysql
ports:
- '8180:8080'
- '8143:8443'
environment:
- DATABASE_HOST=mysql
volumes:
ampp-mysql:
driver: localYAMLAußer PhpMyAdmin benutzen alle Dienste ihre Standard-Ports. Alle wichtigen Daten werden in persistenten Ordnern ausserhalb der Container gespeichert (Volumes).
Apache
SSL Variante 1:
Mit mkcert ein neues lokales Zertifikat installieren
mkcert -installBashJetzt die Zertifikate für den Apache generieren:
mkcert localhost 127.0.0.1 ::1Bashund speichern diese Dateien im Ordner ./docker/apache/certs. Wichtig ist, dass die Namen der Zertifikate mit denen aus der Apachekonfiguration übereinstimmen.
SSL Variante 2:
Zuerst generieren wir mit dem folgenden Befehl ein selbst signiertes SSL-Zertifikat und speichern dessen Dateien im Ordner ./docker/apache/certs:
openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout server.key -out server.crt -subj "/CN=dstack.local" -days 3650BashFür die Apache-Konfiguration legen wir folgende Datei an: ./docker/apache/my_vhost.conf:
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/app/$1
DirectoryIndex disabled
DirectoryIndex index.php index.html
<VirtualHost *:8080>
DocumentRoot "/app"
<Directory "/app">
Options -Indexes
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# Create self signed certs with
# openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout server.key -out server.crt -subj "/CN=YOURDOMAIN.LOCAL" -days 3650
#
<VirtualHost *:8443>
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile "/certs/server.crt" // oder server.pem
SSLCertificateKeyFile "/certs/server.key" // oder server-key.pem
<Directory "/app">
Options -Indexes
AllowOverride All
Require all granted
</Directory>
</VirtualHost>BashFür unsere Website-Daten legen wir noch den Ordner ./docker/www an. In unserem Beispiel liegt hier die Datei info.php mit folgendem Inhalt:
<?php
phpinfo();
?>PHPDamit ist Apache samt SSL komplett.
MySQL
Für MySQL benötigen wir nur einen leeren Ordner namens ./docker/mysql/data. Nach dem Start des MySQL-Containers, werden in diesem Ordner die Daten des MySQL-Servers erzeugt.
Bei Bedarf kann dieser Container noch mit einer Backup-Lösung für MySQL-Datenbanken, wie hier beschrieben, ergänzt werden.
PHP
Für die PHP-Konfiguration erzeugen wir die folgende Datei in ./docker/php/php.ini:
display_errors = On
expose_php = off
max_execution_time = 360
max_input_time = 360
memory_limit = 256M
upload_max_filesize = 1G
post_max_size = 1G
opcache.enable = 1
opcache.revalidate_freq = 2
opcache.validate_timestamps = 1
opcache.interned_strings_buffer = 32
opcache.memory_consumption = 256
extension=imagick.so
zend_extension = "/opt/bitnami/php/lib/php/extensions/xdebug.so"
[Xdebug]
xdebug.remote_autostart=1
xdebug.remote_enable=1
xdebug.default_enable=0
xdebug.remote_host=host.docker.internal
xdebug.remote_port=9000
xdebug.remote_connect_back=0
xdebug.profiler_enable=0
xdebug.remote_log="/tmp/xdebug.log"BashUnter Anderem werden hier die ImageMagick extension aktiviert und XDebug konfiguriert. PHP ist damit ebenfalls komplett.
PhpMyAdmin
PhpMyAdmin benötigt keine extra Konfiguration und ist später über die Adresse 127.0.0.1:81 oder :8143 (SSL) erreichbar. Die Anmeldung geschieht mit Benutzer “root” und dem MySQL Root User Passwort.
Alle Docker-Container auf einmal starten
Der folgende Befehlt starten nun alle Container auf einmal:
docker-compose up -dBashZum Test geben wir im Browser http://127.0.0.1/info.php ein. Wenn wir alles richtig gemacht haben, erscheint nun die PHP-Info Page.
Docker: Zugriff von PHP auf MySQL liefert “Connection refused”
Hier ist folgende Besonderheit zu beachten:
Da ja alle Dienste in getrennten Docker-Containern laufen, wird ein Aufbau des DBConnects mit
'host' => '127.0.0.1:3306'Bashnicht funktionieren. Statt dessen ist der Docker-Containername als Hostname zu verwenden:
'host' => 'mysql:3306'BashSolltet Ihr in docker-compose.yaml Port 3306 auf eine andere Portnummer gemapped haben, bleibt es in diesem Fall trotzdem bei 3306, da aus Perspektive des Webservers der interne Port des Containers sichtbar ist.
Nur für Apps, die von außen auf MySQL zugreifen (z.B. SequelPro, Querious, Navicat etc), wäre dann der gemappte Port gültig.
Docker: Bitnami Images auf Macs mit Apple Silicon lauffähig machen
Damit unser Docker Stack auch auf Macs mit Apple Silicon läuft, sind Build Patches für die Apache und PhpMyAdmin Docker Images notwendig. Dazu gehen wir wie folgt vor:
In der docker-compose.yml ergänzen wir die beiden markierten Zeilen (build):
# --- Apache 2.4
#
apache:
container_name: "ampp-apache"
image: bitnami/apache:2.4
build: ./build/apache
...
# --- PhpMyAdmin latest
# Acccess via
# http://127.0.0.1:8180 or https://127.0.0.1:8143
# Login with user root and mysql-password.
#
phpmyadmin:
container_name: "ampp-phpmyadmin"
image: bitnami/phpmyadmin:latest
build: ./build/phpmyadmin
...YAMLIm Ordner “build” legen wir 2 weitere Ordner an:
“apache” mit einer Datei namens “Dockerfile”. Diese hat folgenden Inhalt:
FROM bitnami/apache:2.4
USER 0
RUN echo 'Mutex posixsem' >>/opt/bitnami/apache2/conf/httpd.conf
USER 1001YAMLSowie den Ordner “phpmyadmin” mit ebenfalls einer Datei namens “Dockerfile” und folgenden Inhalt:
FROM bitnami/phpmyadmin:latest
USER 0
RUN echo 'Mutex posixsem' >>/opt/bitnami/apache2/conf/httpd.conf
USER 1001YAMLDanach starten beide Docker Container auch auf Apple Silicon.