mirror of
https://github.com/invoiceninja/dockerfiles.git
synced 2026-01-28 01:37:12 +01:00
octane and multistage
This commit is contained in:
116
debian/Dockerfile
vendored
116
debian/Dockerfile
vendored
@@ -1,16 +1,40 @@
|
|||||||
|
FROM composer:latest AS composer
|
||||||
|
|
||||||
|
RUN curl -s "https://api.github.com/repos/invoiceninja/invoiceninja/releases/latest" | \
|
||||||
|
grep -o '"browser_download_url": "[^"]*invoiceninja.tar"' | \
|
||||||
|
cut -d '"' -f 4 | \
|
||||||
|
xargs curl -sL | \
|
||||||
|
tar -xz
|
||||||
|
|
||||||
|
RUN ln -s ./resources/views/react/index.blade.php ./public/index.html
|
||||||
|
|
||||||
|
# Set permissions: directories 755, files 644
|
||||||
|
RUN chmod -R a=r,u+w,a+X .
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN composer install --no-dev --no-scripts --no-autoloader --ignore-platform-reqs
|
||||||
|
|
||||||
|
RUN composer dump-autoload --optimize
|
||||||
|
|
||||||
|
RUN php artisan storage:link
|
||||||
|
|
||||||
|
# Octane
|
||||||
|
RUN php artisan octane:install --server=frankenphp
|
||||||
|
|
||||||
|
# ==================
|
||||||
|
# InvoiceNinja image
|
||||||
|
# ==================
|
||||||
FROM dunglas/frankenphp:1-php8.3-bookworm
|
FROM dunglas/frankenphp:1-php8.3-bookworm
|
||||||
|
|
||||||
ARG USER=ninja
|
ARG user=ninja
|
||||||
|
|
||||||
# PHP modules
|
# PHP modules
|
||||||
ARG php_require="bcmath gd pdo_mysql zip"
|
ARG php_require="bcmath gd pdo_mysql zip"
|
||||||
ARG php_suggest="exif imagick intl pcntl soap saxon-12.5.0"
|
ARG php_suggest="exif imagick intl pcntl soap saxon-12.5.0"
|
||||||
ARG php_extra="opcache"
|
ARG php_extra="opcache"
|
||||||
|
|
||||||
ENV APP_DIR=/app
|
# Create a system user UID/GID=999
|
||||||
|
RUN useradd -r ${user}
|
||||||
# Create a system user
|
|
||||||
RUN useradd -r ${USER}
|
|
||||||
|
|
||||||
# Allow to bind to privileged ports
|
# Allow to bind to privileged ports
|
||||||
RUN setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp
|
RUN setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp
|
||||||
@@ -26,19 +50,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
xfonts-wqy \
|
xfonts-wqy \
|
||||||
# Install google-chrome-stable(amd64)/chromium(arm64)
|
# Install google-chrome-stable(amd64)/chromium(arm64)
|
||||||
&& if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
|
&& if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
|
||||||
mkdir -p /etc/apt/keyrings \
|
mkdir -p /etc/apt/keyrings \
|
||||||
&& curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | \
|
&& curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | \
|
||||||
gpg --dearmor -o /etc/apt/keyrings/google.gpg \
|
gpg --dearmor -o /etc/apt/keyrings/google.gpg \
|
||||||
&& echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google.gpg] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
|
&& echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google.gpg] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends google-chrome-stable \
|
&& apt-get install -y --no-install-recommends google-chrome-stable \
|
||||||
&& mkdir /config/google-chrome \
|
&& mkdir /config/google-chrome \
|
||||||
&& chown ${USER}: /config/google-chrome; \
|
&& chown ${user}: /config/google-chrome; \
|
||||||
elif [ "$(dpkg --print-architecture)" = "arm64" ]; then \
|
elif [ "$(dpkg --print-architecture)" = "arm64" ]; then \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
chromium \
|
chromium \
|
||||||
&& mkdir /config/chromium \
|
&& mkdir /config/chromium \
|
||||||
&& chown ${USER}: /config/chromium; \
|
&& chown ${user}: /config/chromium; \
|
||||||
fi \
|
fi \
|
||||||
# Cleanup
|
# Cleanup
|
||||||
&& apt-get purge -y gpg \
|
&& apt-get purge -y gpg \
|
||||||
@@ -48,46 +72,30 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
|
|
||||||
# Install PHP extensions
|
# Install PHP extensions
|
||||||
RUN install-php-extensions \
|
RUN install-php-extensions \
|
||||||
${php_require} \
|
${php_require} \
|
||||||
${php_suggest} \
|
${php_suggest} \
|
||||||
${php_extra} \
|
${php_extra}
|
||||||
@composer
|
|
||||||
|
|
||||||
# Configure PHP
|
# Configure PHP
|
||||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
RUN mv "${PHP_INI_DIR}/php.ini-production" "${PHP_INI_DIR}/php.ini"
|
||||||
|
|
||||||
|
# Create directory for artisan tinker (init.sh)
|
||||||
|
RUN mkdir /config/psysh \
|
||||||
|
&& chown ${user}: /config/psysh
|
||||||
|
|
||||||
|
# Change owner for caddy directories
|
||||||
|
RUN chown -R ${user}: \
|
||||||
|
/data/caddy \
|
||||||
|
/config/caddy
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/init.sh"]
|
||||||
|
|
||||||
|
CMD ["frankenphp", "php-cli", "artisan", "octane:frankenphp"]
|
||||||
|
|
||||||
|
# InvoiceNinja
|
||||||
|
COPY --from=composer --chown=${user}:${user} /app /app
|
||||||
|
|
||||||
# Add initialization script
|
# Add initialization script
|
||||||
COPY --chmod=0755 scripts/init.sh /usr/local/bin/init.sh
|
COPY --chmod=0755 scripts/init.sh /usr/local/bin/init.sh
|
||||||
|
|
||||||
# Prepare app directory
|
USER ${user}
|
||||||
RUN rm -rf ${APP_DIR}/* \
|
|
||||||
&& chown ${USER}: ${APP_DIR}
|
|
||||||
|
|
||||||
# Create directory for artisan tinker (init.sh)
|
|
||||||
RUN mkdir /config/psysh \
|
|
||||||
&& chown ${USER}: /config/psysh
|
|
||||||
|
|
||||||
# Change owner for caddy directories
|
|
||||||
RUN chown -R ${USER}: \
|
|
||||||
/data/caddy \
|
|
||||||
/config/caddy
|
|
||||||
|
|
||||||
USER ${USER}
|
|
||||||
|
|
||||||
# Setup InvoiceNinja
|
|
||||||
RUN curl -s "https://api.github.com/repos/invoiceninja/invoiceninja/releases/latest" | \
|
|
||||||
grep -o '"browser_download_url": "[^"]*invoiceninja.tar"' | \
|
|
||||||
cut -d '"' -f 4 | \
|
|
||||||
xargs curl -sL | \
|
|
||||||
tar -oxz -C ${APP_DIR} \
|
|
||||||
&& ln -s ${APP_DIR}/resources/views/react/index.blade.php ${APP_DIR}/public/index.html \
|
|
||||||
# Set permissions: directories 755, files 644
|
|
||||||
&& chmod -R a=r,u+w,a+X ${APP_DIR} \
|
|
||||||
# Install dependencies
|
|
||||||
&& composer install --working-dir=${APP_DIR} --no-dev --no-scripts --no-autoloader \
|
|
||||||
&& composer dump-autoload --working-dir=${APP_DIR} --optimize \
|
|
||||||
&& frankenphp php-cli ${APP_DIR}/artisan storage:link
|
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/init.sh"]
|
|
||||||
|
|
||||||
CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
|
|
||||||
|
|||||||
12
debian/docker-compose.yml
vendored
12
debian/docker-compose.yml
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
# name: invoiceninja
|
||||||
|
|
||||||
x-logging: &default-logging
|
x-logging: &default-logging
|
||||||
options:
|
options:
|
||||||
max-size: "10m"
|
max-size: "10m"
|
||||||
@@ -17,14 +19,14 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
# php artisan help octane:frankenphp
|
||||||
|
command: --log-level=info
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:8000"
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
environment:
|
environment:
|
||||||
LARAVEL_ROLE: app
|
LARAVEL_ROLE: app
|
||||||
# https://frankenphp.dev/docs/production/#preparing-your-app
|
|
||||||
SERVER_NAME: :80
|
|
||||||
<<: *volumes
|
<<: *volumes
|
||||||
# HEALTHCHECK from frankenphp image
|
# HEALTHCHECK from frankenphp image
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -43,6 +45,8 @@ services:
|
|||||||
app-worker:
|
app-worker:
|
||||||
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
# php artisan help queue:work
|
||||||
|
command: --verbose --sleep=3 --tries=3 --max-time=3600
|
||||||
deploy:
|
deploy:
|
||||||
mode: replicated
|
mode: replicated
|
||||||
replicas: 2
|
replicas: 2
|
||||||
@@ -59,6 +63,8 @@ services:
|
|||||||
app-scheduler:
|
app-scheduler:
|
||||||
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
# php artisan help schedule:work
|
||||||
|
command: --verbose
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
35
debian/scripts/init.sh
vendored
35
debian/scripts/init.sh
vendored
@@ -1,42 +1,57 @@
|
|||||||
#!/bin/sh -eu
|
#!/bin/sh -eu
|
||||||
|
|
||||||
app_dir=${APP_DIR:-/app}
|
# Fallback to app
|
||||||
role=${LARAVEL_ROLE:-app}
|
role=${LARAVEL_ROLE:-app}
|
||||||
|
|
||||||
if [ "$*" = 'frankenphp run --config /etc/caddy/Caddyfile --adapter caddyfile' ]; then
|
# Check for default CMD, flag(s) or empty CMD
|
||||||
|
if [ "$*" = 'frankenphp php-cli artisan octane:frankenphp' ] || [ "${1#-}" != "$1" ] || [ "$#" -eq "0" ]; then
|
||||||
|
|
||||||
|
# Run app
|
||||||
if [ "${role}" = "app" ]; then
|
if [ "${role}" = "app" ]; then
|
||||||
|
cmd="frankenphp php-cli artisan octane:frankenphp"
|
||||||
|
|
||||||
if [ "$APP_ENV" = "production" ]; then
|
if [ "$APP_ENV" = "production" ]; then
|
||||||
frankenphp php-cli "${app_dir}"/artisan optimize
|
frankenphp php-cli artisan optimize
|
||||||
fi
|
fi
|
||||||
|
|
||||||
frankenphp php-cli "${app_dir}"/artisan package:discover
|
frankenphp php-cli artisan package:discover
|
||||||
|
|
||||||
frankenphp php-cli "${app_dir}"/artisan migrate --force
|
# Run migrations (if any)
|
||||||
|
frankenphp php-cli artisan migrate --force
|
||||||
|
|
||||||
# If first IN run, it needs to be initialized
|
# If first IN run, it needs to be initialized
|
||||||
if [ "$(frankenphp php-cli "${app_dir}"/artisan tinker --execute='echo Schema::hasTable("accounts") && !App\Models\Account::all()->first();')" = "1" ]; then
|
if [ "$(frankenphp php-cli artisan tinker --execute='echo Schema::hasTable("accounts") && !App\Models\Account::all()->first();')" = "1" ]; then
|
||||||
echo "Running initialization..."
|
echo "Running initialization..."
|
||||||
|
|
||||||
frankenphp php-cli "${app_dir}"/artisan db:seed --force
|
frankenphp php-cli artisan db:seed --force
|
||||||
|
|
||||||
if [ -n "${IN_USER_EMAIL}" ] && [ -n "${IN_PASSWORD}" ]; then
|
if [ -n "${IN_USER_EMAIL}" ] && [ -n "${IN_PASSWORD}" ]; then
|
||||||
frankenphp php-cli "${app_dir}"/artisan ninja:create-account --email "${IN_USER_EMAIL}" --password "${IN_PASSWORD}"
|
frankenphp php-cli artisan ninja:create-account --email "${IN_USER_EMAIL}" --password "${IN_PASSWORD}"
|
||||||
else
|
else
|
||||||
echo "Initialization failed - Set IN_USER_EMAIL and IN_PASSWORD in .env"
|
echo "Initialization failed - Set IN_USER_EMAIL and IN_PASSWORD in .env"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Production setup completed"
|
echo "Production setup completed"
|
||||||
|
# Run worker
|
||||||
elif [ "${role}" = "worker" ]; then
|
elif [ "${role}" = "worker" ]; then
|
||||||
exec frankenphp php-cli "${app_dir}"/artisan queue:work -v --sleep=3 --tries=3 --max-time=3600
|
cmd="frankenphp php-cli artisan queue:work"
|
||||||
|
# Run scheduler
|
||||||
elif [ "${role}" = "scheduler" ]; then
|
elif [ "${role}" = "scheduler" ]; then
|
||||||
exec frankenphp php-cli "${app_dir}"/artisan schedule:work -v
|
cmd="frankenphp php-cli artisan schedule:work"
|
||||||
|
# Invalid role
|
||||||
else
|
else
|
||||||
echo "Invalid role: ${role}"
|
echo "Invalid role: ${role}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Append flag(s) to role cmd
|
||||||
|
if [ "${1#-}" != "$1" ]; then
|
||||||
|
set -- ${cmd} "$@"
|
||||||
|
else
|
||||||
|
set -- ${cmd}
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user