Heute basteln wir einen Web Application Stack mit Docker-Containern, bestehend aus Apache, PostgreSQL, PHP (inkl. Redis) und PhpPgAdmin. Der Container-Verbund ist modular aufgebaut und so jederzeit mit weiteren Diensten erweiterbar.
Mit geringem Aufwand kann z.B. ein PostgreSQL Cluster mit Replikation simuliert, oder PostgreSQL 12 und PHP 7.4 gegen andere Versionen getauscht werden. SSL und XDdebug sind unter PHP vorkonfiguriert. Der Stack kann somit für Development oder App Deployment benutzt werden. Zum Einsatz kommen die Docker Images von Bitnami.
Für unser Projekt benötigen wir die folgende Verzeichnisstruktur:
Da später alle Container mit Docker Compose gestartet werden, erstellen wir zuerst die docker-compose.yml-Datei im Ordner “appp”, neben dem Unterordner “docker”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
--- # APPP 1.0.0 # # Runs Apache, Postgres, PHP (+Redis) and phpPgAdmin # SSL is preconfigured. # Imagemagick and XDebug are activated. # # Run with # docker-compose up -d # # (c)2020 Harald Schneider # version: "3" services: # --- PostgreSQL 12 # postgresql: container_name: "appp-postgresql" image: bitnami/postgresql:12 #build: ./build/postgresql environment: - POSTGRESQL_USERNAME=admin - POSTGRESQL_PASSWORD=YOUR_PASSWORD_HERE - POSTGRESQL_ENABLE_TLS=yes - POSTGRESQL_TLS_CERT_FILE=/certs/server.crt - POSTGRESQL_TLS_KEY_FILE=/certs/server.key # Use Bitnami's certs: #- POSTGRESQL_TLS_CERT_FILE=/opt/bitnami/postgresql/certs/postgres.crt #- POSTGRESQL_TLS_KEY_FILE=/opt/bitnami/postgresql/certs/postgres.key ports: - '5432:5432' volumes: - ./docker/postgresql:/bitnami/postgresql - ./docker/postgresql/certs:/certs # --- PHP 7.4 # php: container_name: "appp-php" image: bitnami/php-fpm:7.4 depends_on: - redis volumes: - ./docker/www:/app:delegated - ./docker/php/php.ini:/opt/bitnami/php/etc/conf.d/php.ini:ro # --- Apache 2.4 # apache: container_name: "appp-apache" image: bitnami/apache:2.4 ports: - '80:8080' - '443:8443' depends_on: - php volumes: - ./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: "appp-redis" image: bitnami/redis:6.0 environment: - REDIS_PASSWORD=at15jx13 # --- PhpPgAdmin latest # Acccess via # http://127.0.0.1:82 or https://127.0.0.1:8243 # phppgadmin: container_name: "appp-phppgadmin" image: bitnami/phppgadmin:latest depends_on: - postgresql ports: - '82:8080' - '8243:8443' environment: - DATABASE_HOST=host.docker.internal volumes: appp-mysql: driver: local |
Außer PhpPgAdmin benutzen alle Dienste ihre Standard-Ports. Alle wichtigen Daten werden in persistenten Ordnern ausserhalb der Docker-Container gespeichert (Volumes).
Apache
Zuerst generieren wir ein selbst signiertes SSL-Zertifikat und speichern dessen Dateien im Ordner ./docker/apache/certs:
1 |
openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout server.key -out server.crt -subj "/CN=appp.local" -days 3650 |
Für die Apache-Konfiguration legen wir folgende Datei an: ./docker/apache/my_vhost.conf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
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" SSLCertificateKeyFile "/certs/server.key" <Directory "/app"> Options -Indexes AllowOverride All Require all granted </Directory> </VirtualHost> |
Für unsere Website-Daten legen wir noch den Ordner ./docker/www an. In unserem Beispiel liegt hier die Datei info.php mit folgendem Inhalt:
1 2 3 |
<?php phpinfo(); ?> |
Damit ist Apache samt SSL fertig konfiguriert.
PostgeSQL Server
Für PostgreSQL benötigen wir einen leeren Ordner namens ./docker/postgresq. Nach dem Start des PostgrSQL-Containers, werden in diesem Ordner die Daten des PostgreSQL-Servers erzeugt.
Des weiteren benötigen wir einen Ordner ./docker/postgresql/certs in den wir ebenfalls die im Abschnitt “Apache” erzeugten Zertifikatsdateien kopieren. PostgreSQL ist so konfiguriert, dass alle Datenbank-Verbindungen bei Bedarf verschlüsselt sind.
PHP
Für die PHP-Konfiguration erzeugen wir die Datei ./docker/php/php.ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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 extension=pdo_pgsql.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" |
Unter Anderem werden hier die ImageMagick und pdo_pgsql Extensions aktiviert sowie XDebug konfiguriert. PHP ist damit ebenfalls fertiggestellt.
PhpPgAdmin
PhpPgAdmin benötigt keine extra Konfiguration und ist später über die Adresse 127.0.0.1:82 oder :8243 (SSL) erreichbar. Die Anmeldung geschieht mit dem Datenbankbenutzer aus unserer PostgreSQL-Konfiguration.
Alle Docker-Container gleichzeitig starten
Der folgende Befehlt starten nun alle Container gleichzeitig:
1 |
docker-compose up -d |
Zum 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 Postgres liefert “Connection refused”
Hier ist folgende Besonderheit zu beachten:
Da ja alle Dienste in getrennten Docker-Containern laufen, wird ein Aufbau des DBConnects mit
1 |
'host' => '127.0.0.1:5432' |
nicht funktionieren. Statt dessen ist der Docker-Containername als Hostname zu verwenden:
1 |
'host' => 'postgresql:5432' |
Solltet Ihr in docker-compose.yaml Port 5432 auf eine andere Portnummer gemapped haben, bleibt es in diesem Fall trotzdem bei 5432, da aus Perspektive des Webservers der interne Port des Containers sichtbar ist.
Nur für Apps, die von außen auf Postgres zugreifen (z.B. Postico, Navicat etc), wäre dann der gemappte Port gültig.
Viel Spaß mit dem neuen Docker Stack :-)