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

Add support for FrankenPHP #54

Merged
merged 4 commits into from
Jan 18, 2024
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
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ _ide_helper.php
.phpunit.cache
rr
.rr.yaml
frankenphp
77 changes: 77 additions & 0 deletions .github/workflows/frankenphp-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: FrankenPHP test

on:
push:
branches:
- main
tags-ignore:
- '**'
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'

jobs:
build:
name: Build and Run Docker image
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
php: [ 8.1, 8.2, 8.3 ]
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup PHP with Composer and extensions
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php }}"
extensions: dom, curl, libxml, mbstring, zip
tools: composer:v2
coverage: none

- name: Get Composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"

- name: Cache PHP dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ matrix.setup }}
restore-keys: ${{ runner.os }}-composer-

- name: Create app directory
run: mkdir -p /var/www

- name: Install a fresh Laravel app
run: sudo composer create-project laravel/laravel app
working-directory: /var/www

- name: Install Laravel Octane
run: sudo composer require laravel/octane
working-directory: /var/www/app

- name: Install @rollup/rollup-linux-x64-musl
run: sudo npm i @rollup/rollup-linux-x64-musl --save-dev
working-directory: /var/www/app

- name: Copy required content to dockerize the app
run: sudo cp -R FrankenPHP.Dockerfile .dockerignore deployment/ /var/www/app/

- name: Build image
run: docker build -t app:local -f FrankenPHP.Dockerfile .
working-directory: /var/www/app

- name: Run the Docker container
run: docker run -d --rm -p 80:80 app:local
working-directory: /var/www/app

- name: Wait for the container
run: sleep 10s

- name: Check application health
run: curl -f -s -o /dev/null -w "%{http_code}" http://localhost
195 changes: 195 additions & 0 deletions FrankenPHP.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
ARG NODE_VERSION=20-alpine

ARG COMPOSER_VERSION=latest

FROM composer:${COMPOSER_VERSION} AS vendor

###########################################
# Build frontend assets with NPM
###########################################

FROM node:${NODE_VERSION} as build

ENV ROOT=/var/www/html

WORKDIR ${ROOT}

RUN npm config set update-notifier false && npm set progress=false

COPY package*.json ./

RUN if [ -f $ROOT/package-lock.json ]; \
then \
npm ci --no-optional --loglevel=error --no-audit; \
else \
npm install --no-optional --loglevel=error --no-audit; \
fi

COPY . .

RUN npm run build

###########################################

FROM php:8.3.1-cli-bookworm

LABEL maintainer="SMortexa <[email protected]>"

ARG WWWUSER=1000
ARG WWWGROUP=1000
ARG TZ=UTC

ENV DEBIAN_FRONTEND=noninteractive \
TERM=xterm-color \
WITH_HORIZON=false \
WITH_SCHEDULER=false \
OCTANE_SERVER=frankenphp \
NON_ROOT_USER=octane \
ROOT=/var/www/html

WORKDIR ${ROOT}

SHELL ["/bin/bash", "-eou", "pipefail", "-c"]

RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime \
&& echo ${TZ} > /etc/timezone

RUN apt-get update; \
apt-get upgrade -yqq; \
pecl -q channel-update pecl.php.net; \
apt-get install -yqq --no-install-recommends --show-progress \
apt-utils \
gnupg \
git \
curl \
wget \
nano \
rsync \
ncdu \
sqlite3 \
libcurl4-openssl-dev \
ca-certificates \
supervisor \
libmemcached-dev \
libz-dev \
libbrotli-dev \
libpq-dev \
libjpeg-dev \
libpng-dev \
librsvg2-bin \
libfreetype6-dev \
libssl-dev \
libwebp-dev \
libmcrypt-dev \
libldap2-dev \
libonig-dev \
libmagickwand-dev \
libzip-dev zip unzip \
libargon2-1 \
libidn2-0 \
libpcre2-8-0 \
librdkafka-dev \
libpcre3 \
libxml2 \
libxslt-dev \
libzstd1 \
libc-ares-dev \
procps \
postgresql-client \
postgis \
default-mysql-client \
libbz2-dev \
zlib1g-dev \
libicu-dev \
g++ \
# Install PHP extensions
&& docker-php-ext-install \
bz2 \
pcntl \
mbstring \
bcmath \
sockets \
pgsql \
pdo_pgsql \
opcache \
exif \
&& docker-php-ext-configure pdo_mysql && docker-php-ext-install pdo_mysql \
&& docker-php-ext-configure zip && docker-php-ext-install zip \
&& docker-php-ext-configure intl && docker-php-ext-install intl \
&& docker-php-ext-configure gd \
--prefix=/usr \
--with-jpeg \
--with-webp \
--with-freetype && docker-php-ext-install gd \
&& pecl -q install -o -f redis && docker-php-ext-enable redis \
&& pecl -q install -o -f rdkafka && docker-php-ext-enable rdkafka \
&& pecl -q install -o -f memcached && docker-php-ext-enable memcached \
&& pecl -q install -o -f igbinary && docker-php-ext-enable igbinary \
&& docker-php-ext-configure ldap --with-libdir=lib/$(gcc -dumpmachine) && docker-php-ext-install ldap \
&& apt-get -y autoremove \
&& apt-get clean \
&& docker-php-source delete \
&& pecl clear-cache \
&& rm -R /tmp/pear \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& rm /var/log/lastlog /var/log/faillog

RUN wget -q "https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64" \
-O /usr/bin/supercronic \
&& chmod +x /usr/bin/supercronic \
&& mkdir -p /etc/supercronic \
&& echo "*/1 * * * * php ${ROOT}/artisan schedule:run --verbose --no-interaction" > /etc/supercronic/laravel

RUN userdel --remove --force www-data \
&& groupadd --force -g ${WWWGROUP} ${NON_ROOT_USER} \
&& useradd -ms /bin/bash --no-log-init --no-user-group -g ${WWWGROUP} -u ${WWWUSER} ${NON_ROOT_USER}

RUN chown -R ${NON_ROOT_USER}:${NON_ROOT_USER} ${ROOT} /var/{log,run}

RUN chmod -R a+rw /var/{log,run}

USER ${NON_ROOT_USER}

COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} --from=vendor /usr/bin/composer /usr/bin/composer
COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} composer* ./

RUN composer install \
--no-dev \
--no-interaction \
--no-autoloader \
--no-ansi \
--no-scripts \
--audit

COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} . .

RUN mkdir -p \
storage/framework/{sessions,views,cache,testing} \
storage/logs \
bootstrap/cache

COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} deployment/octane/FrankenPHP/supervisord.frankenphp.conf /etc/supervisor/conf.d/
COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} deployment/supervisord.scheduler.conf /etc/supervisor/conf.d/
COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} deployment/supervisord.horizon.conf /etc/supervisor/conf.d/
COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} deployment/start-container /usr/local/bin/start-container
COPY --chown=${NON_ROOT_USER}:${NON_ROOT_USER} deployment/php.ini /usr/local/etc/php/conf.d/99-octane.ini

RUN composer install \
--classmap-authoritative \
--no-interaction \
--no-ansi \
--no-dev \
&& composer clear-cache \
&& php artisan storage:link

ADD --chown=${NON_ROOT_USER}:${NON_ROOT_USER} https://github.com/dunglas/frankenphp/releases/download/v1.0.3/frankenphp-linux-x86_64 ./frankenphp

RUN chmod +x /usr/local/bin/start-container frankenphp

RUN cat deployment/utilities.sh >> ~/.bashrc

EXPOSE 80

ENTRYPOINT ["start-container"]

HEALTHCHECK --start-period=5s --interval=2s --timeout=5s --retries=8 CMD php artisan octane:status || exit 1
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<a href="https://github.com/exaco/laravel-octane-dockerfile/pulls"><img alt="GitHub closed pull requests" src="https://img.shields.io/github/issues-pr-closed/exaco/laravel-octane-dockerfile"></a>
<a href="https://github.com/exaco/laravel-octane-dockerfile/actions/workflows/tests.yml"><img alt="GitHub Workflow Status" src="https://github.com/exaco/laravel-octane-dockerfile/actions/workflows/roadrunner-test.yml/badge.svg"></a>
<a href="https://github.com/exaco/laravel-octane-dockerfile/actions/workflows/tests.yml"><img alt="GitHub Workflow Status" src="https://github.com/exaco/laravel-octane-dockerfile/actions/workflows/swoole-test.yml/badge.svg"></a>
<a href="https://github.com/exaco/laravel-octane-dockerfile/actions/workflows/tests.yml"><img alt="GitHub Workflow Status" src="https://github.com/exaco/laravel-octane-dockerfile/actions/workflows/frankenphp-test.yml/badge.svg"></a>


A pretty configurable, production-ready, and multi-stage Dockerfile for [Laravel Octane](https://github.com/laravel/octane)
Expand All @@ -18,11 +19,11 @@ The Docker configuration provides the following setup:

You can run the Docker container in different modes:

| Mode | `CONTAINER_MODE` | HTTP server |
|------------------|----------------------|------------|
| HTTP Server (default) | `http` | Swoole / RoadRunner |
| Horizon | `horizon` | - |
| Scheduler | `scheduler` | - |
| Mode | `CONTAINER_MODE` | HTTP server |
| --------------------- | ---------------- | ------------------- |
| HTTP Server (default) | `http` | Swoole / RoadRunner |
| Horizon | `horizon` | - |
| Scheduler | `scheduler` | - |

## Usage

Expand Down Expand Up @@ -90,6 +91,7 @@ Also, some useful Bash functions and aliases are added in `utilities.sh` that ma
## ToDo
- [x] Add support for PHP 8.3
- [ ] Add support for worker mode
- [ ] Build assets with Bun
- [ ] Create standalone and self-executable app
- [x] Add support for Horizon
- [x] Add support for RoadRunner
Expand Down
4 changes: 2 additions & 2 deletions RoadRunner.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ FROM composer:${COMPOSER_VERSION} AS vendor

FROM php:${PHP_VERSION}-cli-bookworm

LABEL maintainer="Seyed Morteza Ebadi <[email protected]>"
LABEL maintainer="SMortexa <[email protected]>"

ARG WWWUSER=1000
ARG WWWGROUP=1000
Expand Down Expand Up @@ -150,7 +150,7 @@ RUN userdel --remove --force www-data \

RUN chown -R ${NON_ROOT_USER}:${NON_ROOT_USER} ${ROOT} /var/{log,run}

RUN chmod -R ug+rw /var/{log,run}
RUN chmod -R a+rw /var/{log,run}

USER ${NON_ROOT_USER}

Expand Down
4 changes: 2 additions & 2 deletions Swoole.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ FROM composer:${COMPOSER_VERSION} AS vendor

FROM php:${PHP_VERSION}-cli-bookworm

LABEL maintainer="Seyed Morteza Ebadi <[email protected]>"
LABEL maintainer="SMortexa <[email protected]>"

ARG WWWUSER=1000
ARG WWWGROUP=1000
Expand Down Expand Up @@ -151,7 +151,7 @@ RUN userdel --remove --force www-data \

RUN chown -R ${NON_ROOT_USER}:${NON_ROOT_USER} ${ROOT} /var/{log,run}

RUN chmod -R ug+rw /var/{log,run}
RUN chmod -R a+rw /var/{log,run}

USER ${NON_ROOT_USER}

Expand Down
42 changes: 42 additions & 0 deletions deployment/octane/FrankenPHP/supervisord.frankenphp.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[supervisord]
nodaemon=true
user=%(ENV_NON_ROOT_USER)s
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid

[program:octane]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan octane:start --server=frankenphp --host=0.0.0.0 --port=80 --admin-port=2019
user=%(ENV_NON_ROOT_USER)s
autostart=true
autorestart=true
environment=LARAVEL_OCTANE="1"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

[program:horizon]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan horizon
user=%(ENV_NON_ROOT_USER)s
autostart=%(ENV_WITH_HORIZON)s
autorestart=true
stdout_logfile=/var/www/html/horizon.log
stopwaitsecs=3600

[program:scheduler]
process_name=%(program_name)s_%(process_num)02d
command=supercronic -overlapping /etc/supercronic/laravel
user=%(ENV_NON_ROOT_USER)s
autostart=%(ENV_WITH_SCHEDULER)s
autorestart=true
stdout_logfile=/var/www/html/scheduler.log

[program:clear-scheduler-cache]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan schedule:clear-cache
user=%(ENV_NON_ROOT_USER)s
autostart=%(ENV_WITH_SCHEDULER)s
autorestart=false
stdout_logfile=/var/www/html/scheduler.log
Loading
Loading