Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rootless Docker/Optimized build #932

Merged
merged 8 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
**.DS_Store
.env
.devcontainer
.dockerignore
.editorconfig
.git
node_modules
vendor
.github
**.gitignore
.php-cs-fixer.dist.php
.prettierrc.json
.vscode
Dockerfile
bounties.md
compose.yml
contributing.md
contributor_license_agreement.md
database/database.sqlite
docker/README.md
node_modules
phpstan.neon
phpunit.xml
readme.md
PseudoResonance marked this conversation as resolved.
Show resolved Hide resolved
storage/debugbar/*.json
storage/logs/*.log
storage/framework/cache/data/*
storage/framework/sessions/*
storage/framework/testing
storage/framework/views/*.php
storage/logs/*.log
vendor
6 changes: 4 additions & 2 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ jobs:
VERSION=${{ steps.build_info.outputs.version_tag }}
labels: ${{ steps.docker_meta.outputs.labels }}
tags: ${{ steps.docker_meta.outputs.tags }}
cache-from: type=gha,scope=tagged${{ matrix.os }}
cache-to: type=gha,scope=tagged${{ matrix.os }},mode=max

- name: Build and Push (main)
uses: docker/build-push-action@v6
Expand All @@ -84,5 +86,5 @@ jobs:
VERSION=dev-${{ steps.build_info.outputs.short_sha }}
labels: ${{ steps.docker_meta.outputs.labels }}
tags: ${{ steps.docker_meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: type=gha,scope=${{ matrix.os }}
cache-to: type=gha,scope=${{ matrix.os }},mode=max
106 changes: 71 additions & 35 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,69 +1,103 @@
# syntax=docker.io/docker/dockerfile:1.7-labs
# Pelican Production Dockerfile

# ================================
# Stage 1: Build PHP Dependencies
# Stage 1: Build PHP Base Image
# ================================
FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine AS composer
FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine AS base

ADD --chmod=0755 https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
PseudoResonance marked this conversation as resolved.
Show resolved Hide resolved

RUN install-php-extensions bcmath gd intl zip opcache pcntl posix pdo_mysql

RUN rm /usr/local/bin/install-php-extensions

# ================================
# Stage 2-1: Composer Install
# ================================
FROM --platform=$TARGETOS/$TARGETARCH base AS composer

WORKDIR /build

COPY . ./
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

# Install required libraries and PHP extensions
RUN apk update && apk add --no-cache \
libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev icu-dev \
zip unzip curl \
&& docker-php-ext-install bcmath gd intl zip opcache pcntl posix pdo_mysql
# Copy bare minimum to install Composer dependencies
COPY composer.json composer.lock ./

RUN composer install --no-dev --optimize-autoloader
RUN composer install --no-dev --no-interaction --no-autoloader --no-scripts
PseudoResonance marked this conversation as resolved.
Show resolved Hide resolved

# ================================
# Stage 2: Build Frontend Assets
# Stage 2-2: Yarn Install
# ================================
FROM --platform=$TARGETOS/$TARGETARCH node:20-alpine AS yarn

WORKDIR /build

COPY --from=composer /build .
# Copy bare minimum to install Yarn dependencies
COPY package.json yarn.lock ./

RUN yarn config set network-timeout 300000 \
&& yarn install --frozen-lockfile \
&& yarn run build
&& yarn install --frozen-lockfile

# ================================
# Stage 3: Build Final Application Image
# Stage 3-1: Composer Optimize
# ================================
FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine
FROM --platform=$TARGETOS/$TARGETARCH composer AS composerbuild

WORKDIR /var/www/html
# Copy full code to optimize autoload
COPY --exclude=Caddyfile --exclude=docker/ . ./

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
RUN composer dump-autoload --optimize

# Install additional required libraries
RUN apk update && apk add --no-cache \
libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev icu-dev \
PseudoResonance marked this conversation as resolved.
Show resolved Hide resolved
zip unzip curl caddy ca-certificates supervisor
# ================================
# Stage 3-2: Build Frontend Assets
# ================================
FROM --platform=$TARGETOS/$TARGETARCH yarn AS yarnbuild

# Copy PHP extensions and configuration from Composer stage
COPY --from=composer /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=composer /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
WORKDIR /build

COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=yarn /build .
# Copy full code
COPY --exclude=Caddyfile --exclude=docker/ . ./
COPY --from=composer /build .

RUN touch .env
RUN yarn run build

# Set permissions for Laravel directories
RUN chmod -R 755 storage bootstrap/cache \
&& chown -R www-data:www-data ./
# ================================
# Stage 4: Build Final Application Image
# ================================
FROM --platform=$TARGETOS/$TARGETARCH base AS final

# Add Laravel scheduler to crontab
RUN echo "* * * * * php /var/www/html/artisan schedule:run >> /dev/null 2>&1" | crontab -u www-data -
WORKDIR /var/www/html

# Install additional required libraries
RUN apk update && apk add --no-cache \
caddy ca-certificates supervisor supercronic

COPY --chown=root:www-data --chmod=640 --from=composerbuild /build .
COPY --chown=root:www-data --chmod=640 --from=yarnbuild /build/public ./public

# Set permissions
# First ensure all files are owned by root and restrict www-data to read access
RUN chown root:www-data ./ \
&& chmod 750 ./ \
# Files should not have execute set, but directories need it
&& find ./ -type d -exec chmod 750 {} \; \
# Symlink to env/database path, as www-data won't be able to write to webroot
&& ln -s /pelican-data/.env ./.env \
&& ln -s /pelican-data/database/database.sqlite ./database/database.sqlite \
# Create necessary directories
&& mkdir -p /pelican-data /var/run/supervisord /etc/supercronic \
# Finally allow www-data write permissions where necessary
&& chown -R www-data:www-data /pelican-data ./storage ./bootstrap/cache /var/run/supervisord \
&& chmod -R u+rwX,g+rwX,o-rwx /pelican-data ./storage ./bootstrap/cache /var/run/supervisord

# Configure Supervisor
RUN cp .github/docker/supervisord.conf /etc/supervisord.conf && \
mkdir /var/log/supervisord/
COPY docker/supervisord.conf /etc/supervisord.conf
COPY docker/Caddyfile /etc/caddy/Caddyfile
# Add Laravel scheduler to crontab
COPY docker/crontab /etc/supercronic/crontab

COPY docker/entrypoint.sh ./docker/entrypoint.sh

HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost/up || exit 1
Expand All @@ -72,5 +106,7 @@ EXPOSE 80 443

VOLUME /pelican-data

ENTRYPOINT [ "/bin/ash", ".github/docker/entrypoint.sh" ]
USER www-data

ENTRYPOINT [ "/bin/ash", "docker/entrypoint.sh" ]
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]
1 change: 1 addition & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ x-common:
services:
panel:
image: ghcr.io/pelican-dev/panel:latest
build: .
PseudoResonance marked this conversation as resolved.
Show resolved Hide resolved
restart: always
networks:
- default
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions docker/crontab
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* * * * * php /var/www/html/artisan schedule:run
20 changes: 4 additions & 16 deletions .github/docker/entrypoint.sh → docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
#!/bin/ash -e

#mkdir -p /var/log/supervisord/ /var/log/php8/ \

## check for .env file and generate app keys if missing
if [ -f /pelican-data/.env ]; then
alexevladgabriel marked this conversation as resolved.
Show resolved Hide resolved
## check for .env file or symlink and generate app keys if missing
if [ -f /var/www/html/.env ]; then
echo "external vars exist."
rm -rf /var/www/html/.env
else
echo "external vars don't exist."
rm -rf /var/www/html/.env
# webroot .env is symlinked to this path
touch /pelican-data/.env

## manually generate a key because key generate --force fails
Expand All @@ -26,10 +23,7 @@ else
echo -e "APP_INSTALLED=false" >> /pelican-data/.env
fi

mkdir /pelican-data/database
ln -s /pelican-data/.env /var/www/html/
chown -h www-data:www-data /var/www/html/.env
ln -s /pelican-data/database/database.sqlite /var/www/html/database/
mkdir /pelican-data/database /var/www/html/storage/logs/supervisord 2>/dev/null

if ! grep -q "APP_KEY=" .env || grep -q "APP_KEY=$" .env; then
echo "Generating APP_KEY..."
Expand All @@ -45,10 +39,6 @@ php artisan migrate --force
echo -e "Optimizing Filament"
php artisan filament:optimize

## start cronjobs for the queue
echo -e "Starting cron jobs."
crond -L /var/log/crond -l 5

export SUPERVISORD_CADDY=false

## disable caddy if SKIP_CADDY is set
Expand All @@ -59,7 +49,5 @@ else
export SUPERVISORD_CADDY=true
fi

chown -R www-data:www-data /pelican-data/.env /pelican-data/database
alexevladgabriel marked this conversation as resolved.
Show resolved Hide resolved

echo "Starting Supervisord"
exec "$@"
20 changes: 12 additions & 8 deletions .github/docker/supervisord.conf → docker/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ username=dummy
password=dummy

[supervisord]
logfile=/var/log/supervisord/supervisord.log ; supervisord log file
alexevladgabriel marked this conversation as resolved.
Show resolved Hide resolved
logfile=/var/www/html/storage/logs/supervisord/supervisord.log ; supervisord log file
logfile_maxbytes=50MB ; maximum size of logfile before rotation
logfile_backups=2 ; number of backed up logfiles
loglevel=error ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
nodaemon=false ; run supervisord as a daemon
pidfile=/var/run/supervisord/supervisord.pid ; pidfile location
nodaemon=true ; run supervisord as a daemon
minfds=1024 ; number of startup file descriptors
minprocs=200 ; number of process descriptors
user=root ; default user
childlogdir=/var/log/supervisord/ ; where child log files will live

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
Expand All @@ -30,7 +28,6 @@ autorestart=true

[program:queue-worker]
command=/usr/local/bin/php /var/www/html/artisan queue:work --tries=3
user=www-data
alexevladgabriel marked this conversation as resolved.
Show resolved Hide resolved
autostart=true
autorestart=true

Expand All @@ -39,5 +36,12 @@ command=caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
autostart=%(ENV_SUPERVISORD_CADDY)s
autorestart=%(ENV_SUPERVISORD_CADDY)s
priority=10
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/fd/1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point in switching to redirect_stderr instad of the stderr_events_enabled and why did you disable the stdout_events_enabled?

Copy link
Contributor Author

@PseudoResonance PseudoResonance Jan 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no event listener configured, so stdout_events_enabled and stderr_events_enabled are pointless.

Also sorry, I had to check and confirm it to be sure and forgot to mention. The redirect options redirect logs to stdout/stderr as expected of the name, but the events redirect it to special event listeners that can ex: send emails on errors.

stdout_logfile_maxbytes=0
redirect_stderr=true

[program:supercronic]
command=supercronic /etc/supercronic/crontab
autostart=true
autorestart=true
redirect_stderr=true
Loading