diff --git a/.docker/000-default.conf b/.docker/000-default.conf new file mode 100644 index 00000000..5702d89a --- /dev/null +++ b/.docker/000-default.conf @@ -0,0 +1,22 @@ + + ServerAdmin webmaster@localhost + DocumentRoot /opt/kimai/public + + PassEnv DATABASE_PREFIX + PassEnv MAILER_FROM + PassEnv APP_ENV + PassEnv APP_SECRET + PassEnv DATABASE_URL + PassEnv MAILER_URL + PassEnv TRUSTED_PROXIES + PassEnv TRUSTED_HOSTS + + + Require all granted + DirectoryIndex index.php + AllowOverride All + + + + +ServerName localhost diff --git a/.docker/dbtest.php b/.docker/dbtest.php new file mode 100644 index 00000000..3e752d36 --- /dev/null +++ b/.docker/dbtest.php @@ -0,0 +1,55 @@ + \PDO::ERRMODE_EXCEPTION ]);"; +echo "*"; + +try { + $pdo = new \PDO("mysql:host=$DB_HOST;dbname=$DB_BASE;port=$DB_PORT", "$DB_USER", "$DB_PASS", [ + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION + ]); +} catch(\Exception $ex) { + switch ($ex->getCode()) { + // we can immediately stop startup here and show the error message + case 1045: + echo 'Access denied (1045)'; + die(1); + // we can immediately stop startup here and show the error message + case 1049: + echo 'Unknown database (1049)'; + die(2); + // a lot of errors share the same meaningless error code zero + case 0: + // this error includes the database name, so we can only search for the static part of the error message + if (stripos($ex->getMessage(), 'SQLSTATE[HY000] [1049] Unknown database') !== false) { + echo 'Unknown database (0-1049)'; + die(3); + } + switch ($ex->getMessage()) { + // eg. no response (fw) - the startup script should retry it a couple of times + case 'SQLSTATE[HY000] [2002] Operation timed out': + echo 'Operation timed out (0-2002)'; + die(4); + // special case "localhost" with a stopped db server (should not happen in docker compose setup) + case 'SQLSTATE[HY000] [2002] No such file or directory': + echo 'Connection could not be established (0-2002)'; + die(5); + // using IP with stopped db server - the startup script should retry it a couple of times + case 'SQLSTATE[HY000] [2002] Connection refused': + echo 'Connection refused (0-2002)'; + die(5); + } + echo $ex->getMessage() . " (0)"; + die(7); + default: + // unknown error + echo $ex->getMessage() . " (?)"; + die(10); + } +} diff --git a/.docker/monolog.yaml b/.docker/monolog.yaml new file mode 100644 index 00000000..ab4e34be --- /dev/null +++ b/.docker/monolog.yaml @@ -0,0 +1,48 @@ +when@prod: + monolog: + channels: ["deprecation"] + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + excluded_http_codes: [403, 404] + nested: + type: stream + level: info + path: php://stderr + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine"] + deprecation: + type: stream + channels: ["deprecation"] + path: php://stderr + +when@dev: + monolog: + channels: ["deprecation"] + handlers: + main: + type: stream + path: php://stderr + level: info + channels: ["!event"] + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine", "!console"] + deprecation: + type: stream + channels: ["deprecation"] + path: php://stderr + +when@test: + monolog: + handlers: + main: + type: stream + path: php://stderr + level: info + channels: ["!event"] diff --git a/.docker/self-test.sh b/.docker/self-test.sh new file mode 100755 index 00000000..8c4564ca --- /dev/null +++ b/.docker/self-test.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +/startup.sh 2>&1 +echo $$ > /tmp/startup.pid +echo "Waiting for kimai to install" +while [ ! -f /opt/kimai/var/installed ]; do + echo -n ". " + sleep 5 +done +echo + +# Test FPM CGI +if [ -f /use_fpm ]; then + + export SCRIPT_NAME=/opt/kimai/public/index.php + export SCRIPT_FILENAME=/opt/kimai/public/index.php + export REQUEST_METHOD=GET + export SERVER_ADDR=localhost + + COUNT=0 + until cgi-fcgi -bind -connect 127.0.0.1:9000 &> /dev/null + do + COUNT=$((COUNT+1)) + echo "Waiting for FPM Server to start (${COUNT})" + sleep 3 + if [ "$COUNT" -gt 5 ]; then + echo "FPM Failed to start." + exit 1 + fi + done + +fi + +# Test Apache/httpd +if [ -f /use_apache ]; then + + COUNT=0 + until curl -s -o /dev/null http://localhost:8001 + do + COUNT=$((COUNT+1)) + echo "Waiting for Apache/HTTP to start (${COUNT})" &> /dev/null + sleep 3 + if [ "$COUNT" -gt 5 ]; then + echo "Apache/HTTP failed to start." + exit 1 + fi + done + +fi + +# Test PHP/Kimai +/opt/kimai/bin/console kimai:version +if [ $? != 0 ]; then + echo "PHP/Kimai not responding" + exit 1 +fi +kill $(cat /tmp/startup.pid) + + diff --git a/.docker/service.sh b/.docker/service.sh new file mode 100755 index 00000000..ac5d1b57 --- /dev/null +++ b/.docker/service.sh @@ -0,0 +1,61 @@ +#!/bin/bash -x + +function waitForDB() { + # Parse sql connection data + if [ ! -z "$DATABASE_URL" ]; then + DB_TYPE=$(awk -F '[/:@]' '{print $1}' <<< "$DATABASE_URL") + DB_USER=$(awk -F '[/:@]' '{print $4}' <<< "$DATABASE_URL") + DB_PASS=$(awk -F '[/:@]' '{print $5}' <<< "$DATABASE_URL") + DB_HOST=$(awk -F '[/:@]' '{print $6}' <<< "$DATABASE_URL") + DB_PORT=$(awk -F '[/:@]' '{print $7}' <<< "$DATABASE_URL") + DB_BASE=$(awk -F '[/?]' '{print $4}' <<< "$DATABASE_URL") + else + DB_TYPE=${DB_TYPE:mysql} + if [ "$DB_TYPE" == "mysql" ]; then + export DATABASE_URL="${DB_TYPE}://${DB_USER:=kimai}:${DB_PASS:=kimai}@${DB_HOST:=sqldb}:${DB_PORT:=3306}/${DB_BASE:=kimai}" + else + echo "Unknown database type, cannot proceed. Only 'mysql' is supported, received: [$DB_TYPE]" + exit 1 + fi + fi + + re='^[0-9]+$' + if ! [[ $DB_PORT =~ $re ]] ; then + DB_PORT=3306 + fi + + echo "Wait for MySQL DB connection ..." + until php /dbtest.php $DB_HOST $DB_BASE $DB_PORT $DB_USER $DB_PASS; do + echo Checking DB: $? + sleep 3 + done + echo "Connection established" +} + +function handleStartup() { + # These are idempotent, run them anyway + /opt/kimai/bin/console -n kimai:install + /opt/kimai/bin/console -n kimai:update + if [ ! -z "$ADMINPASS" ] && [ ! -a "$ADMINMAIL" ]; then + /opt/kimai/bin/console kimai:user:create superadmin "$ADMINMAIL" ROLE_SUPER_ADMIN "$ADMINPASS" + fi + echo "$KIMAI" > /opt/kimai/var/installed + echo "Kimai2 ready" +} + +function runServer() { + # Just while I'm fixing things + /opt/kimai/bin/console kimai:reload --env="$APP_ENV" + chown -R $USER_ID:$GROUP_ID /opt/kimai/var + if [ -e /use_apache ]; then + exec /usr/sbin/apache2 -D FOREGROUND + elif [ -e /use_fpm ]; then + exec php-fpm + else + echo "Error, unknown server type" + fi +} + +waitForDB +handleStartup +runServer diff --git a/.docker/startup.sh b/.docker/startup.sh new file mode 100755 index 00000000..152f5cc2 --- /dev/null +++ b/.docker/startup.sh @@ -0,0 +1,96 @@ +#!/bin/bash -x + +KIMAI=$(cat /opt/kimai/version.txt) +echo $KIMAI + + +function config() { + # set mem limits and copy in custom logger config + if [ -z "$memory_limit" ]; then + memory_limit=256M + fi + + + # Parse sql connection data + if [ ! -z "$DATABASE_URL" ]; then + DB_TYPE=$(awk -F '[/:@]' '{print $1}' <<< "$DATABASE_URL") + DB_USER=$(awk -F '[/:@]' '{print $4}' <<< "$DATABASE_URL") + DB_PASS=$(awk -F '[/:@]' '{print $5}' <<< "$DATABASE_URL") + DB_HOST=$(awk -F '[/:@]' '{print $6}' <<< "$DATABASE_URL") + DB_PORT=$(awk -F '[/:@]' '{print $7}' <<< "$DATABASE_URL") + DB_BASE=$(awk -F '[/?]' '{print $4}' <<< "$DATABASE_URL") + else + DB_TYPE=${DB_TYPE:mysql} + if [ "$DB_TYPE" == "mysql" ]; then + export DATABASE_URL="${DB_TYPE}://${DB_USER:=kimai}:${DB_PASS:=kimai}@${DB_HOST:=sqldb}:${DB_PORT:=3306}/${DB_BASE:=kimai}" + else + echo "Unknown database type, cannot proceed. Only 'mysql' is supported, received: [$DB_TYPE]" + exit 1 + fi + fi + + re='^[0-9]+$' + if ! [[ $DB_PORT =~ $re ]] ; then + DB_PORT=3306 + fi + + echo "Wait for MySQL DB connection ..." + until php /dbtest.php $DB_HOST $DB_BASE $DB_PORT $DB_USER $DB_PASS; do + echo Checking DB: $? + sleep 3 + done + echo "Connection established" +} + +function handleStartup() { + # set mem limits and copy in custom logger config + sed -i "s/memory_limit.*/memory_limit=$memory_limit/g" /usr/local/etc/php/php.ini + cp /assets/monolog.yaml /opt/kimai/config/packages/monolog.yaml + + tar -zx -C /opt/kimai -f /var/tmp/public.tgz + + if [ -z "$USER_ID" ]; then + USER_ID=$(id -u www-data) + fi + if [ -z "$GROUP_ID" ]; then + GROUP_ID=$(id -g www-data) + fi + + # if group doesn't exist + if grep -w "$GROUP_ID" /etc/group &>/dev/null; then + echo Group already exists + else + echo www-kimai:x:"$GROUP_ID": >> /etc/group + grpconv + fi + + # if user doesn't exist + if id "$USER_ID" &>/dev/null; then + echo User already exists + else + echo www-kimai:x:"$USER_ID":"$GROUP_ID":www-kimai:/var/www:/usr/sbin/nologin >> /etc/passwd + pwconv + fi + + if [ -e /use_apache ]; then + export APACHE_RUN_USER=$(id -nu "$USER_ID") + # This doesn't _exactly_ run as the specified GID, it runs as the GID of the specified user but WTF + export APACHE_RUN_GROUP=$(id -ng "$USER_ID") + export APACHE_PID_FILE=/var/run/apache2/apache2.pid + export APACHE_RUN_DIR=/var/run/apache2 + export APACHE_LOCK_DIR=/var/lock/apache2 + export APACHE_LOG_DIR=/var/log/apache2 + export LANG=C + elif [ -e /use_fpm ]; then + sed -i "s/user = .*/user = $USER_ID/g" /usr/local/etc/php-fpm.d/www.conf + sed -i "s/group = .*/group = $GROUP_ID/g" /usr/local/etc/php-fpm.d/www.conf + echo "Setting fpm to run as ${USER_ID}:${GROUP_ID}" + else + echo "Error, unknown server type" + fi +} + +config +handleStartup + +exec /service.sh diff --git a/.docker/test-kimai-version.sh b/.docker/test-kimai-version.sh new file mode 100755 index 00000000..dc75d3a2 --- /dev/null +++ b/.docker/test-kimai-version.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# An reg wizard can probably do this without the cut command +VER=$(echo $KIMAI | sed 's/[^0-9]//g' | cut -c1-3) + +if test "${VER}" -lt 111 +then + echo "+--------------------------------------------------------------------------+" + echo "| Kimai versions older than 1.11 require composer 1.x |" + echo "| To build older versions you'll need to use a tagged version of this repo |" + echo "| https://github.com/tobybatch/kimai2/releases/tag/EOL-composer-1.x |" + echo "| |" + echo "| See https://github.com/tobybatch/kimai2/issues/180 |" + echo "+--------------------------------------------------------------------------+" + return 1 +fi + diff --git a/.docker/test-lite.sh b/.docker/test-lite.sh new file mode 100755 index 00000000..1ba6699e --- /dev/null +++ b/.docker/test-lite.sh @@ -0,0 +1,22 @@ +#!/bin/sh -e + +# Test PHP/Kimai +/opt/kimai/bin/console kimai:version +if [ $? != 0 ]; then + echo "PHP/Kimai not responding" + exit 1 +fi + +# Test FPM CGI +if [ -f /use_fpm ]; then + echo Testing FPM + php-fpm -t +fi + +# Test Apache/httpd +if [ -f /use_apache ]; then + echo Testing Apache + apache2ctl -t +fi + +exit 0 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..d455ca34 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,325 @@ +# _ ___ _ ____ +# | |/ (_)_ __ ___ __ _(_)___ \ +# | ' /| | '_ ` _ \ / _` | | __) | +# | . \| | | | | | | (_| | |/ __/ +# |_|\_\_|_| |_| |_|\__,_|_|_____| +# + +# Source base [fpm/apache] +ARG BASE="fpm" +ARG PHP_VER="8.1" +ARG COMPOSER_VER="latest" +# Branch name +ARG KIMAI="main" +# Timezone for images +ARG TIMEZONE="Europe/Berlin" + +########################### +# Shared tools +########################### + +# full kimai source +FROM alpine:latest AS git-dev +# pass-through Arguments in every stage. See: https://benkyriakou.com/posts/docker-args-empty +ARG KIMAI +ARG TIMEZONE +# I need to do this check somewhere, we discard all but the checkout so doing here doesn't hurt +ADD .docker/test-kimai-version.sh /test-kimai-version.sh +RUN /test-kimai-version.sh +RUN apk add --no-cache git && \ + git clone --depth 1 --branch ${KIMAI} https://github.com/kimai/kimai.git /opt/kimai + +# production kimai source +FROM git-dev AS git-prod + +WORKDIR /opt/kimai +RUN rm -r tests + +# composer base image +FROM composer:${COMPOSER_VER} AS composer + +########################### +# PHP extensions +########################### + +#fpm alpine php extension base +FROM php:${PHP_VER}-fpm-alpine AS fpm-php-ext-base +RUN apk add --no-cache \ + # build-tools + autoconf \ + dpkg \ + dpkg-dev \ + file \ + g++ \ + gcc \ + icu-dev \ + libatomic \ + libc-dev \ + libgomp \ + libmagic \ + m4 \ + make \ + mpc1 \ + mpfr4 \ + musl-dev \ + perl \ + re2c \ + # gd + freetype-dev \ + libpng-dev \ + # icu + icu-dev \ + icu-data-full \ + # ldap + openldap-dev \ + libldap \ + # zip + libzip-dev \ + # xsl + libxslt-dev + + +# apache debian php extension base +FROM php:${PHP_VER}-apache-buster AS apache-php-ext-base +RUN apt-get update +RUN apt-get install -y \ + libldap2-dev \ + libicu-dev \ + libpng-dev \ + libzip-dev \ + libxslt1-dev \ + libfreetype6-dev + + +# php extension gd - 13.86s +FROM ${BASE}-php-ext-base AS php-ext-gd +RUN docker-php-ext-configure gd \ + --with-freetype && \ + docker-php-ext-install -j$(nproc) gd + +# php extension intl : 15.26s +FROM ${BASE}-php-ext-base AS php-ext-intl +RUN docker-php-ext-install -j$(nproc) intl + +# php extension ldap : 8.45s +FROM ${BASE}-php-ext-base AS php-ext-ldap +RUN docker-php-ext-configure ldap && \ + docker-php-ext-install -j$(nproc) ldap + +# php extension pdo_mysql : 6.14s +FROM ${BASE}-php-ext-base AS php-ext-pdo_mysql +RUN docker-php-ext-install -j$(nproc) pdo_mysql + +# php extension zip : 8.18s +FROM ${BASE}-php-ext-base AS php-ext-zip +RUN docker-php-ext-install -j$(nproc) zip + +# php extension xsl : ?.?? s +FROM ${BASE}-php-ext-base AS php-ext-xsl +RUN docker-php-ext-install -j$(nproc) xsl + +# php extension redis +FROM ${BASE}-php-ext-base AS php-ext-redis +RUN yes no | pecl install redis && \ + docker-php-ext-enable redis + +# php extension opcache +FROM ${BASE}-php-ext-base AS php-ext-opcache +RUN docker-php-ext-install -j$(nproc) opcache + +########################### +# fpm base build +########################### + +# fpm base build +FROM php:${PHP_VER}-fpm-alpine AS fpm-base +ARG KIMAI +ARG TIMEZONE +RUN apk add --no-cache \ + bash \ + coreutils \ + freetype \ + haveged \ + icu \ + icu-data-full \ + libldap \ + libpng \ + libzip \ + libxslt-dev \ + fcgi \ + tzdata && \ + touch /use_fpm + +EXPOSE 9000 + +HEALTHCHECK --interval=20s --timeout=10s --retries=3 \ + CMD \ + SCRIPT_NAME=/ping \ + SCRIPT_FILENAME=/ping \ + REQUEST_METHOD=GET \ + cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1 + + + +########################### +# apache base build +########################### + +FROM php:${PHP_VER}-apache-buster AS apache-base +ARG KIMAI +ARG TIMEZONE +COPY .docker/000-default.conf /etc/apache2/sites-available/000-default.conf +RUN apt-get update && \ + apt-get install -y \ + bash \ + haveged \ + libicu63 \ + libpng16-16 \ + libzip4 \ + libxslt1.1 \ + libfreetype6 && \ + echo "Listen 8001" > /etc/apache2/ports.conf && \ + a2enmod rewrite && \ + touch /use_apache + +EXPOSE 8001 + +HEALTHCHECK --interval=20s --timeout=10s --retries=3 \ + CMD curl -f http://127.0.0.1:8001 || exit 1 + + + +########################### +# global base build +########################### + +FROM ${BASE}-base AS base +ARG KIMAI +ARG TIMEZONE + +LABEL maintainer="tobias@neontribe.co.uk" +LABEL maintainer="bastian@schroll-software.de" + +ENV KIMAI=${KIMAI} +ENV TIMEZONE=${TIMEZONE} +RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && echo ${TIMEZONE} > /etc/timezone && \ + # make composer home dir + mkdir /composer && \ + chown -R www-data:www-data /composer + +# copy startup script & DB checking script +COPY .docker/startup.sh /startup.sh +COPY .docker/service.sh /service.sh +COPY .docker/self-test.sh /self-test.sh +COPY .docker/dbtest.php /dbtest.php + +# copy composer +COPY --from=composer /usr/bin/composer /usr/bin/composer + +# copy php extensions + +# PHP extension xsl +COPY --from=php-ext-xsl /usr/local/etc/php/conf.d/docker-php-ext-xsl.ini /usr/local/etc/php/conf.d/docker-php-ext-xsl.ini +COPY --from=php-ext-xsl /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xsl.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/xsl.so +# PHP extension pdo_mysql +COPY --from=php-ext-pdo_mysql /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini +COPY --from=php-ext-pdo_mysql /usr/local/lib/php/extensions/no-debug-non-zts-20210902/pdo_mysql.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/pdo_mysql.so +# PHP extension zip +COPY --from=php-ext-zip /usr/local/etc/php/conf.d/docker-php-ext-zip.ini /usr/local/etc/php/conf.d/docker-php-ext-zip.ini +COPY --from=php-ext-zip /usr/local/lib/php/extensions/no-debug-non-zts-20210902/zip.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/zip.so +# PHP extension ldap +COPY --from=php-ext-ldap /usr/local/etc/php/conf.d/docker-php-ext-ldap.ini /usr/local/etc/php/conf.d/docker-php-ext-ldap.ini +COPY --from=php-ext-ldap /usr/local/lib/php/extensions/no-debug-non-zts-20210902/ldap.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/ldap.so +# PHP extension gd +COPY --from=php-ext-gd /usr/local/etc/php/conf.d/docker-php-ext-gd.ini /usr/local/etc/php/conf.d/docker-php-ext-gd.ini +COPY --from=php-ext-gd /usr/local/lib/php/extensions/no-debug-non-zts-20210902/gd.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/gd.so +# PHP extension intl +COPY --from=php-ext-intl /usr/local/etc/php/conf.d/docker-php-ext-intl.ini /usr/local/etc/php/conf.d/docker-php-ext-intl.ini +COPY --from=php-ext-intl /usr/local/lib/php/extensions/no-debug-non-zts-20210902/intl.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/intl.so +# PHP extension redis +COPY --from=php-ext-redis /usr/local/etc/php/conf.d/docker-php-ext-redis.ini /usr/local/etc/php/conf.d/docker-php-ext-redis.ini +COPY --from=php-ext-redis /usr/local/lib/php/extensions/no-debug-non-zts-20210902/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/redis.so +COPY --from=php-ext-opcache /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini + +ENV DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/kimai.sqlite +ENV APP_SECRET=change_this_to_something_unique +# The default container name for nginx is nginx +ENV TRUSTED_PROXIES=nginx,localhost,127.0.0.1 +ENV TRUSTED_HOSTS=nginx,localhost,127.0.0.1 +ENV MAILER_FROM=kimai@example.com +ENV MAILER_URL=null://localhost +ENV ADMINPASS= +ENV ADMINMAIL= +ENV DB_TYPE= +ENV DB_USER= +ENV DB_PASS= +ENV DB_HOST= +ENV DB_PORT= +ENV DB_BASE= +ENV COMPOSER_MEMORY_LIMIT=-1 +# If this set then the image will start, run a self test and then exit. It's used for the release process +ENV TEST_AND_EXIT= +ENV COMPOSER_ALLOW_SUPERUSER=1 +ENV USER_ID= +ENV GROUP_ID= + +VOLUME [ "/opt/kimai/var" ] + +CMD [ "/startup.sh" ] + + + +########################### +# final builds +########################### + +# developement build +FROM base AS dev +# copy kimai develop source +COPY --from=git-dev --chown=www-data:www-data /opt/kimai /opt/kimai +COPY .docker /assets +# do the composer deps installation +RUN echo \$PATH +RUN \ + export COMPOSER_HOME=/composer && \ + composer --no-ansi install --working-dir=/opt/kimai --optimize-autoloader && \ + composer --no-ansi clearcache && \ + composer --no-ansi require --working-dir=/opt/kimai laminas/laminas-ldap && \ + cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini && \ + chown -R www-data:www-data /opt/kimai /usr/local/etc/php/php.ini && \ + mkdir -p /opt/kimai/var/logs && chmod 777 /opt/kimai/var/logs && \ + sed "s/128M/-1/g" /usr/local/etc/php/php.ini-development > /opt/kimai/php-cli.ini && \ + sed -i "s/env php/env -S php -c \/opt\/kimai\/php-cli.ini/g" /opt/kimai/bin/console && \ + tar -C /opt/kimai -zcvf /var/tmp/public.tgz public && \ + /opt/kimai/bin/console kimai:version | awk '{print $2}' > /opt/kimai/version.txt +ENV APP_ENV=dev +ENV DATABASE_URL= +ENV memory_limit=256M + +# production build +FROM base AS prod +# copy kimai production source +COPY --from=git-prod --chown=www-data:www-data /opt/kimai /opt/kimai +COPY .docker /assets +# do the composer deps installation +RUN \ + export COMPOSER_HOME=/composer && \ + composer --no-ansi install --working-dir=/opt/kimai --no-dev --optimize-autoloader && \ + composer --no-ansi clearcache && \ + composer --no-ansi require --working-dir=/opt/kimai laminas/laminas-ldap && \ + cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini && \ + sed -i "s/expose_php = On/expose_php = Off/g" /usr/local/etc/php/php.ini && \ + sed -i "s/;opcache.enable=1/opcache.enable=1/g" /usr/local/etc/php/php.ini && \ + sed -i "s/;opcache.memory_consumption=128/opcache.memory_consumption=256/g" /usr/local/etc/php/php.ini && \ + sed -i "s/;opcache.interned_strings_buffer=8/opcache.interned_strings_buffer=24/g" /usr/local/etc/php/php.ini && \ + sed -i "s/;opcache.max_accelerated_files=10000/opcache.max_accelerated_files=100000/g" /usr/local/etc/php/php.ini && \ + sed -i "s/opcache.validate_timestamps=1/opcache.validate_timestamps=0/g" /usr/local/etc/php/php.ini && \ + sed -i "s/session.gc_maxlifetime = 1440/session.gc_maxlifetime = 604800/g" /usr/local/etc/php/php.ini && \ + mkdir -p /opt/kimai/var/logs && chmod 777 /opt/kimai/var/logs && \ + sed "s/128M/-1/g" /usr/local/etc/php/php.ini-development > /opt/kimai/php-cli.ini && \ + chown -R www-data:www-data /opt/kimai /usr/local/etc/php/php.ini && \ + tar -C /opt/kimai -zcvf /var/tmp/public.tgz public && \ + /opt/kimai/bin/console kimai:version | awk '{print $2}' > /opt/kimai/version.txt +ENV APP_ENV=prod +ENV DATABASE_URL= +ENV memory_limit=256M