Contao im Container

Submitted by Erik Wegner on Sun, 10/09/2022 - 21:23
Body

Contao ist ein Content Management System auf PHP-Basis. Die folgenden Hinweise sollen helfen, es mit Hilfe von Docker laufen zu lassen. Das Ergebnis sind 4 getrennte Container:

  1. PHP mit FPM-Schnittstelle zur Ausführung des Codes
  2. nginx zur Auslieferung der Webseiten und statischen Dateien
  3. MariaDB als Datenbank
  4. Adminer für den einfachen Zugriff auf die Datenbank

Als Voraussetzung habe ich Traefik installiert, um das Verteilen der Zugriffe auf die Container zu  routen.

In der Datei Dockerfile-contao wird die PHP-Umgebung bereitgestellt. Zur Vereinfachung verwende ich die Drupal-Bereitstellung.

Dockerfile-contao
# from https://github.com/docker-library/drupal/blob/0bc267208f3f1405b8441588a48e0004508f65f8/9.4/php8.1/fpm-alpine3.16/Dockerfile
FROM php:8.1-fpm-alpine3.16

# install the PHP extensions we need
RUN set -eux; \
\
apk add --no-cache --virtual .build-deps \
coreutils \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev \
libwebp-dev \
libzip-dev \
# postgresql-dev is needed for https://bugs.alpinelinux.org/issues/3642
postgresql-dev \
; \
\
docker-php-ext-configure gd \
--with-freetype \
--with-jpeg=/usr/include \
--with-webp \
; \
\
docker-php-ext-install -j "$(nproc)" \
gd \
opcache \
pdo_mysql \
pdo_pgsql \
zip \
; \
\
runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)"; \
apk add --no-network --virtual .drupal-phpexts-rundeps $runDeps; \
apk del --no-network .build-deps

# set recommended PHP.ini settings
# see https://secure.php.net/manual/en/opcache.installation.php
RUN { \
echo 'opcache.memory_consumption=128'; \
echo 'opcache.interned_strings_buffer=8'; \
echo 'opcache.max_accelerated_files=4000'; \
echo 'opcache.revalidate_freq=60'; \
echo 'opcache.fast_shutdown=1'; \
} > /usr/local/etc/php/conf.d/opcache-recommended.ini

# Thanks to https://github.com/docker-library/php/issues/57#issuecomment-318056930
RUN set -xe \
&& apk add --update icu \
&& apk add --no-cache --virtual .php-deps make \
&& apk add --no-cache --virtual .build-deps $PHPIZE_DEPS zlib-dev icu-dev \
&& docker-php-ext-configure intl \
&& docker-php-ext-install intl \
&& docker-php-ext-enable intl \
&& { find /usr/local/lib -type f -print0 | xargs -0r strip --strip-all -p 2>/dev/null || true; } \
&& apk del .build-deps \
&& rm -rf /tmp/* /usr/local/lib/php/doc/* /var/cache/apk/*

COPY --from=composer:2 /usr/bin/composer /usr/local/bin/

WORKDIR /opt/contao
RUN set -eux; \
export COMPOSER_HOME="$(mktemp -d)"; \
composer create-project --no-interaction contao/managed-edition . 4.13; \
chown -R www-data:www-data var; \
rmdir /var/www/html; \
ln -sf /opt/contao/public /var/www/html; \
# delete composer cache
rm -rf "$COMPOSER_HOME"

ENV PATH=${PATH}:/opt/contao/vendor/bin

RUN /bin/sh -c "echo php_admin_flag[log_errors] = on >> /usr/local/etc/php-fpm.d/docker.conf"

Die Konfiguration des nginx-Webservers sorgt für die Übergabe aller Anfragen nach PHP-Dateien an den FPM-Prozess. Sonstige Dateien werden direkt ausgeliefert.

nginx.conf
server {
server_name localhost;
root /var/www/html/public;
index index.php index.html index.htm;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM Configuration Nginx
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param DOCUMENT_ROOT /var/www/html;
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
}
}

Die Bereitstellung aller Container erfolgt mit docker-compose.

docker-compose.yml
version: "3"

services:
php:
build:
context: .
dockerfile: Dockerfile-contao
depends_on:
- database
restart: 'no'
volumes:
- ./contao:/opt/contao
labels:
- traefik.enabled=false
networks:
- default

web:
image: nginx:1
depends_on:
- php
restart: 'no'
volumes:
- ./contao:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
labels:
- traefik.http.routers.contao.rule=Host(`contao.localhost`)
networks:
- default
- traefik

database:
image: mariadb:10
restart: 'no'
environment:
- MARIADB_ROOT_PASSWORD=contao
- MARIADB_DATABASE=contao
- MARIADB_PASSWORD=contao
- MARIADB_USER=contao
volumes:
- ./db_data:/var/lib/mysql:rw
labels:
- traefik.enabled=false
networks:
- default

adminer:
image: adminer
restart: 'no'
labels:
- traefik.http.routers.adminer-contao.rule=Host(`adminer-contao.localhost`)
networks:
- default
- traefik

volumes:
db_data:

networks:
traefik:
external: true

In der docker-compose-Datei wird das Verzeichnis ./contao dem Container-Verzeichnis /opt/contao zugeordnet. Damit die Inhalte am richtigen Platz landen, wird nach dem Starten der Container die Installation mittels composer wiederholt.

Anschließend ist die Installationsseite von contao unter http://contao.localhost/contao/install erreichbar.