From 9e736b26f6d9441278106d2ddfcf29b6b816573a Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Mon, 14 Oct 2024 23:09:14 +0200 Subject: [PATCH] Improve docker installation (#5115) * ignore certain connection errors on startup * remove invalid code that checks for the existence of the migration table * fetch kimai code via tar archive instead of git clone, to respect .gitattributes --- .docker/dbtest.php | 11 +++++------ Dockerfile | 23 ++++++++++------------- src/Command/InstallCommand.php | 17 ++++------------- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/.docker/dbtest.php b/.docker/dbtest.php index 24b4b714..e89ea2ab 100644 --- a/.docker/dbtest.php +++ b/.docker/dbtest.php @@ -13,20 +13,19 @@ try { ]); } catch(\Exception $ex) { switch ($ex->getCode()) { - // we can immediately stop startup here and show the error message case 1045: + // we can immediately stop here and show the error message 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); + // error "Unknown database (1049)" can be ignored, the database will be created by Kimai + return; // 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); + // error "Unknown database (1049)" can be ignored, the database will be created by Kimai + return; } switch ($ex->getMessage()) { // eg. no response (fw) - the startup script should retry it a couple of times diff --git a/Dockerfile b/Dockerfile index d407b6ce..bde16deb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -218,20 +218,18 @@ COPY --from=php-ext-intl /usr/local/lib/php/extensions/no-debug-non-zts-20230831 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 ########################### -# Shared tools +# fetch Kimai sources ########################### -# full kimai source -FROM alpine:latest AS git-dev +FROM alpine:latest AS git-prod ARG KIMAI ARG TIMEZONE -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 +# the convention in the Kimai repository is: tags are always version numbers, branch names always start with a letter +# if the KIMAI variable starts with a number (e.g. 2.24.0) we assume its a tag, otherwise its a branch +RUN [[ $KIMAI =~ ^[0-9] ]] && export REF='tags' || export REF='heads' && \ + wget -O "/opt/kimai.tar.gz" "https://github.com/kimai/kimai/archive/refs/${REF}/${KIMAI}.tar.gz" && \ + tar -xpzf /opt/kimai.tar.gz -C /opt/ && \ + mv /opt/kimai-${KIMAI} /opt/kimai ########################### # global base build @@ -286,10 +284,9 @@ CMD [ "/entrypoint.sh" ] # development build FROM base AS dev # copy kimai develop source -COPY --from=git-dev --chown=www-data:www-data /opt/kimai /opt/kimai +COPY --from=git-prod --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 && \ @@ -305,7 +302,7 @@ ENV APP_ENV=dev ENV DATABASE_URL= ENV memory_limit=512M -# production build +# the "prod" stage (production build) is configured as last stage in the file, as this is the default target in BuildKit FROM base AS prod # copy kimai production source COPY --from=git-prod --chown=www-data:www-data /opt/kimai /opt/kimai diff --git a/src/Command/InstallCommand.php b/src/Command/InstallCommand.php index 54dca286..1468fca1 100644 --- a/src/Command/InstallCommand.php +++ b/src/Command/InstallCommand.php @@ -93,7 +93,7 @@ final class InstallCommand extends Command private function rebuildCaches(string $environment, SymfonyStyle $io, InputInterface $input, OutputInterface $output): int { - $io->text('Rebuilding your cache ...'); + $io->text('Rebuilding cache ...'); $command = $this->getApplication()->find('cache:clear'); try { @@ -122,15 +122,7 @@ final class InstallCommand extends Command private function importMigrations(SymfonyStyle $io, OutputInterface $output): void { - try { - if (!$this->connection->createSchemaManager()->tablesExist(['migration_versions'])) { - throw new \RuntimeException('Migration table does not exist'); - } - } catch (\Exception $ex) { - $io->error(['Failed to detect migration status, aborting update.', $ex->getMessage()]); - - return; - } + $io->text('Creating database ...'); $command = $this->getApplication()->find('doctrine:migrations:migrate'); $cmdInput = new ArrayInput(['--allow-no-migration' => true]); @@ -146,12 +138,11 @@ final class InstallCommand extends Command { try { if ($this->connection->isConnected()) { - $io->note(\sprintf('Database is existing and connection could be established')); - + // database exists: we can skip this step return; } } catch (\Exception $ex) { - // this likely means that the database does not exist and the connection failed + // this means the database does not exist and the connection failed } $command = $this->getApplication()->find('doctrine:database:create');