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”:

---

# 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:
      - '127.0.0.1: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:

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:

<VirtualHost *:8080>
  DocumentRoot "/app"
  ProxyPassMatch ^/(.*.php(/.*)?)$ fcgi://php:9000/app/$1
  <Directory "/app">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
    DirectoryIndex index.html index.php
  </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"  

  DocumentRoot "/app"
  ProxyPassMatch ^/(.*.php(/.*)?)$ fcgi://php:9000/app/$1
  <Directory "/app">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
    DirectoryIndex index.html index.php
  </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:

<?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:

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"

Unter Anderem werden hier die ImageMagick extension aktiviert und 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:

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.

Viel Spaß mit dem neuen Docker Stack :-)