mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-06-15 13:32:43 +01:00
Added public build
This commit is contained in:
61
.github/workflows/build-public.yml
vendored
Normal file
61
.github/workflows/build-public.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
on:
|
||||
push:
|
||||
|
||||
name: Build
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Install dependencies"
|
||||
uses: php-actions/composer@v6
|
||||
if: steps.cache-vendor.outputs.cache-hit != 'true' # Skip if cache hit
|
||||
with:
|
||||
command: install
|
||||
dev: no
|
||||
only_args: --no-ansi --no-interaction --no-scripts --prefer-dist --ignore-platform-reqs --classmap-authoritative
|
||||
php_version: 8.3
|
||||
|
||||
- name: "Use Node.js"
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: "Install npm dependencies"
|
||||
run: npm ci
|
||||
|
||||
- name: "Build"
|
||||
run: npm run build
|
||||
|
||||
- name: "Login to GitHub Container Registry"
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: "Docker meta"
|
||||
id: "meta"
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: solidtime/solidtime
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: "Build and push"
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
System Requirements:
|
||||
* Docker
|
||||
* PHP 8.2
|
||||
* PHP 8.3
|
||||
* Composer
|
||||
|
||||
```bash
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"korridor/laravel-model-validation-rules": "^3.0",
|
||||
"laravel/framework": "^11.0",
|
||||
"laravel/jetstream": "^5.0",
|
||||
"laravel/octane": "^2.3",
|
||||
"laravel/passport": "^12.0",
|
||||
"laravel/tinker": "^2.8",
|
||||
"nwidart/laravel-modules": "^11.0.3",
|
||||
|
||||
176
composer.lock
generated
176
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1481cd817f30abf0429363c9ad89b5dd",
|
||||
"content-hash": "4296162fd8b0dc950f30b50ee266bbb1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@@ -3496,6 +3496,91 @@
|
||||
},
|
||||
"time": "2024-02-28T15:07:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-diactoros",
|
||||
"version": "3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-diactoros.git",
|
||||
"reference": "74cfb9a7522ffd2a161d1ebe10db2fc2abb9df45"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/74cfb9a7522ffd2a161d1ebe10db2fc2abb9df45",
|
||||
"reference": "74cfb9a7522ffd2a161d1ebe10db2fc2abb9df45",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0",
|
||||
"psr/http-factory": "^1.0.2",
|
||||
"psr/http-message": "^1.1 || ^2.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-factory-implementation": "^1.1 || ^2.0",
|
||||
"psr/http-message-implementation": "^1.1 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-libxml": "*",
|
||||
"http-interop/http-factory-tests": "^0.9.0",
|
||||
"laminas/laminas-coding-standard": "~2.5.0",
|
||||
"php-http/psr7-integration-tests": "^1.3",
|
||||
"phpunit/phpunit": "^9.6.16",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"vimeo/psalm": "^5.22.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laminas": {
|
||||
"config-provider": "Laminas\\Diactoros\\ConfigProvider",
|
||||
"module": "Laminas\\Diactoros"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions/create_uploaded_file.php",
|
||||
"src/functions/marshal_headers_from_sapi.php",
|
||||
"src/functions/marshal_method_from_sapi.php",
|
||||
"src/functions/marshal_protocol_version_from_sapi.php",
|
||||
"src/functions/normalize_server.php",
|
||||
"src/functions/normalize_uploaded_files.php",
|
||||
"src/functions/parse_cookie_header.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Laminas\\Diactoros\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "PSR HTTP Message implementations",
|
||||
"homepage": "https://laminas.dev",
|
||||
"keywords": [
|
||||
"http",
|
||||
"laminas",
|
||||
"psr",
|
||||
"psr-17",
|
||||
"psr-7"
|
||||
],
|
||||
"support": {
|
||||
"chat": "https://laminas.dev/chat",
|
||||
"docs": "https://docs.laminas.dev/laminas-diactoros/",
|
||||
"forum": "https://discourse.laminas.dev",
|
||||
"issues": "https://github.com/laminas/laminas-diactoros/issues",
|
||||
"rss": "https://github.com/laminas/laminas-diactoros/releases.atom",
|
||||
"source": "https://github.com/laminas/laminas-diactoros"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://funding.communitybridge.org/projects/laminas-project",
|
||||
"type": "community_bridge"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-16T16:06:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/fortify",
|
||||
"version": "v1.21.1",
|
||||
@@ -3833,6 +3918,95 @@
|
||||
},
|
||||
"time": "2024-03-19T20:10:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/octane",
|
||||
"version": "v2.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/octane.git",
|
||||
"reference": "4890de0c6a79bd163a52b99b91c727cf0020cc2c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/octane/zipball/4890de0c6a79bd163a52b99b91c727cf0020cc2c",
|
||||
"reference": "4890de0c6a79bd163a52b99b91c727cf0020cc2c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laminas/laminas-diactoros": "^3.0",
|
||||
"laravel/framework": "^10.10.1|^11.0",
|
||||
"laravel/serializable-closure": "^1.3.0",
|
||||
"nesbot/carbon": "^2.66.0|^3.0",
|
||||
"php": "^8.1.0",
|
||||
"symfony/console": "^6.0|^7.0",
|
||||
"symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0"
|
||||
},
|
||||
"conflict": {
|
||||
"spiral/roadrunner": "<2023.1.0",
|
||||
"spiral/roadrunner-cli": "<2.6.0",
|
||||
"spiral/roadrunner-http": "<3.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.6.1",
|
||||
"inertiajs/inertia-laravel": "^0.6.9|^1.0",
|
||||
"laravel/scout": "^10.2.1",
|
||||
"laravel/socialite": "^5.6.1",
|
||||
"livewire/livewire": "^2.12.3|^3.0",
|
||||
"mockery/mockery": "^1.5.1",
|
||||
"nunomaduro/collision": "^6.4.0|^7.5.2|^8.0",
|
||||
"orchestra/testbench": "^8.5.2|^9.0",
|
||||
"phpstan/phpstan": "^1.10.15",
|
||||
"phpunit/phpunit": "^10.4",
|
||||
"spiral/roadrunner-cli": "^2.6.0",
|
||||
"spiral/roadrunner-http": "^3.3.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/roadrunner-worker",
|
||||
"bin/swoole-server"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Octane\\OctaneServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Octane": "Laravel\\Octane\\Facades\\Octane"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Octane\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Supercharge your Laravel application's performance.",
|
||||
"keywords": [
|
||||
"frankenphp",
|
||||
"laravel",
|
||||
"octane",
|
||||
"roadrunner",
|
||||
"swoole"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/octane/issues",
|
||||
"source": "https://github.com/laravel/octane"
|
||||
},
|
||||
"time": "2024-04-01T13:36:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
"version": "v12.0.2",
|
||||
|
||||
240
config/octane.php
Normal file
240
config/octane.php
Normal file
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Laravel\Octane\Contracts\OperationTerminated;
|
||||
use Laravel\Octane\Events\RequestHandled;
|
||||
use Laravel\Octane\Events\RequestReceived;
|
||||
use Laravel\Octane\Events\RequestTerminated;
|
||||
use Laravel\Octane\Events\TaskReceived;
|
||||
use Laravel\Octane\Events\TaskTerminated;
|
||||
use Laravel\Octane\Events\TickReceived;
|
||||
use Laravel\Octane\Events\TickTerminated;
|
||||
use Laravel\Octane\Events\WorkerErrorOccurred;
|
||||
use Laravel\Octane\Events\WorkerStarting;
|
||||
use Laravel\Octane\Events\WorkerStopping;
|
||||
use Laravel\Octane\Listeners\CloseMonologHandlers;
|
||||
use Laravel\Octane\Listeners\EnsureUploadedFilesAreValid;
|
||||
use Laravel\Octane\Listeners\EnsureUploadedFilesCanBeMoved;
|
||||
use Laravel\Octane\Listeners\FlushOnce;
|
||||
use Laravel\Octane\Listeners\FlushTemporaryContainerInstances;
|
||||
use Laravel\Octane\Listeners\ReportException;
|
||||
use Laravel\Octane\Listeners\StopWorkerIfNecessary;
|
||||
use Laravel\Octane\Octane;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Server
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the default "server" that will be used by Octane
|
||||
| when starting, restarting, or stopping your server via the CLI. You
|
||||
| are free to change this to the supported server of your choosing.
|
||||
|
|
||||
| Supported: "roadrunner", "swoole", "frankenphp"
|
||||
|
|
||||
*/
|
||||
|
||||
'server' => env('OCTANE_SERVER', 'swoole'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Force HTTPS
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When this configuration value is set to "true", Octane will inform the
|
||||
| framework that all absolute links must be generated using the HTTPS
|
||||
| protocol. Otherwise your links may be generated using plain HTTP.
|
||||
|
|
||||
*/
|
||||
|
||||
'https' => env('OCTANE_HTTPS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Listeners
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All of the event listeners for Octane's events are defined below. These
|
||||
| listeners are responsible for resetting your application's state for
|
||||
| the next request. You may even add your own listeners to the list.
|
||||
|
|
||||
*/
|
||||
|
||||
'listeners' => [
|
||||
WorkerStarting::class => [
|
||||
EnsureUploadedFilesAreValid::class,
|
||||
EnsureUploadedFilesCanBeMoved::class,
|
||||
],
|
||||
|
||||
RequestReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
...Octane::prepareApplicationForNextRequest(),
|
||||
//
|
||||
],
|
||||
|
||||
RequestHandled::class => [
|
||||
//
|
||||
],
|
||||
|
||||
RequestTerminated::class => [
|
||||
// FlushUploadedFiles::class,
|
||||
],
|
||||
|
||||
TaskReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
//
|
||||
],
|
||||
|
||||
TaskTerminated::class => [
|
||||
//
|
||||
],
|
||||
|
||||
TickReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
//
|
||||
],
|
||||
|
||||
TickTerminated::class => [
|
||||
//
|
||||
],
|
||||
|
||||
OperationTerminated::class => [
|
||||
FlushOnce::class,
|
||||
FlushTemporaryContainerInstances::class,
|
||||
// DisconnectFromDatabases::class,
|
||||
// CollectGarbage::class,
|
||||
],
|
||||
|
||||
WorkerErrorOccurred::class => [
|
||||
ReportException::class,
|
||||
StopWorkerIfNecessary::class,
|
||||
],
|
||||
|
||||
WorkerStopping::class => [
|
||||
CloseMonologHandlers::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Warm / Flush Bindings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The bindings listed below will either be pre-warmed when a worker boots
|
||||
| or they will be flushed before every new request. Flushing a binding
|
||||
| will force the container to resolve that binding again when asked.
|
||||
|
|
||||
*/
|
||||
|
||||
'warm' => [
|
||||
...Octane::defaultServicesToWarm(),
|
||||
],
|
||||
|
||||
'flush' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Swoole Tables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using Swoole, you may define additional tables as required by the
|
||||
| application. These tables can be used to store data that needs to be
|
||||
| quickly accessed by other workers on the particular Swoole server.
|
||||
|
|
||||
*/
|
||||
|
||||
'tables' => [
|
||||
'example:1000' => [
|
||||
'name' => 'string:1000',
|
||||
'votes' => 'int',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Swoole Cache Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using Swoole, you may leverage the Octane cache, which is powered
|
||||
| by a Swoole table. You may set the maximum number of rows as well as
|
||||
| the number of bytes per row using the configuration options below.
|
||||
|
|
||||
*/
|
||||
|
||||
'cache' => [
|
||||
'rows' => 1000,
|
||||
'bytes' => 10000,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| File Watching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following list of files and directories will be watched when using
|
||||
| the --watch option offered by Octane. If any of the directories and
|
||||
| files are changed, Octane will automatically reload your workers.
|
||||
|
|
||||
*/
|
||||
|
||||
'watch' => [
|
||||
'app',
|
||||
'bootstrap',
|
||||
'config',
|
||||
'database/**/*.php',
|
||||
'public/**/*.php',
|
||||
'resources/**/*.php',
|
||||
'routes',
|
||||
'composer.lock',
|
||||
'.env',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Garbage Collection Threshold
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When executing long-lived PHP scripts such as Octane, memory can build
|
||||
| up before being cleared by PHP. You can force Octane to run garbage
|
||||
| collection if your application consumes this amount of megabytes.
|
||||
|
|
||||
*/
|
||||
|
||||
'garbage' => 50,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maximum Execution Time
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following setting configures the maximum execution time for requests
|
||||
| being handled by Octane. You may set this value to 0 to indicate that
|
||||
| there isn't a specific time limit on Octane request execution time.
|
||||
|
|
||||
*/
|
||||
|
||||
'max_execution_time' => 30,
|
||||
|
||||
/**
|
||||
* Custom swoole config
|
||||
*
|
||||
* @source https://github.com/exaco/laravel-octane-dockerfile?tab=readme-ov-file#recommended-swoole-options-in-octanephp
|
||||
*/
|
||||
'swoole' => [
|
||||
'options' => [
|
||||
'http_compression' => true,
|
||||
'http_compression_level' => 6, // 1 - 9
|
||||
'compression_min_length' => 20,
|
||||
'package_max_length' => 20 * 1024 * 1024, // 20MB
|
||||
'open_http2_protocol' => true,
|
||||
'document_root' => public_path(),
|
||||
'enable_static_handler' => true,
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
laravel.test:
|
||||
build:
|
||||
context: ./docker/8.3
|
||||
context: ./docker/local/8.3
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
WWWGROUP: '${WWWGROUP}'
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
|
||||
volumes:
|
||||
- 'sail-pgsql:/var/lib/postgresql/data'
|
||||
- './docker/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql'
|
||||
- './docker/local/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql'
|
||||
networks:
|
||||
- sail
|
||||
healthcheck:
|
||||
@@ -76,7 +76,7 @@ services:
|
||||
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
|
||||
volumes:
|
||||
- 'sail-pgsql-test:/var/lib/postgresql/data'
|
||||
- './docker/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql'
|
||||
- './docker/local/pgsql/create-testing-database.sql:/docker-entrypoint-initdb.d/10-create-testing-database.sql'
|
||||
networks:
|
||||
- sail
|
||||
healthcheck:
|
||||
|
||||
121
docker/prod/Dockerfile
Normal file
121
docker/prod/Dockerfile
Normal file
@@ -0,0 +1,121 @@
|
||||
# Accepted values: 8.3 - 8.2
|
||||
ARG PHP_VERSION=8.3
|
||||
|
||||
ARG DOCKER_FILES_BASE_PATH="docker/prod"
|
||||
|
||||
ARG COMPOSER_VERSION=latest
|
||||
|
||||
###########################################
|
||||
|
||||
FROM composer:${COMPOSER_VERSION} AS vendor
|
||||
|
||||
FROM php:${PHP_VERSION}-cli-bookworm AS base
|
||||
|
||||
LABEL maintainer="solidtime <hello@solidtime.io>"
|
||||
LABEL org.opencontainers.image.title="solidtime"
|
||||
LABEL org.opencontainers.image.description="solidtime is a modern open source timetracker for Freelancers and Agencies"
|
||||
LABEL org.opencontainers.image.source="https://github.com/solidtime-io/solidtime"
|
||||
LABEL org.opencontainers.image.licenses="AGPL"
|
||||
|
||||
ARG WWWUSER=1000
|
||||
ARG WWWGROUP=1000
|
||||
ARG TZ=UTC
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
TERM=xterm-color \
|
||||
WITH_HORIZON=false \
|
||||
WITH_SCHEDULER=false \
|
||||
OCTANE_SERVER=swoole \
|
||||
USER=octane \
|
||||
ROOT=/var/www/html \
|
||||
COMPOSER_FUND=0 \
|
||||
COMPOSER_MAX_PARALLEL_HTTP=24
|
||||
|
||||
WORKDIR ${ROOT}
|
||||
|
||||
SHELL ["/bin/bash", "-eou", "pipefail", "-c"]
|
||||
|
||||
RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime \
|
||||
&& echo ${TZ} > /etc/timezone
|
||||
|
||||
ADD --chmod=0755 https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
|
||||
|
||||
RUN apt-get update; \
|
||||
apt-get upgrade -yqq; \
|
||||
apt-get install -yqq --no-install-recommends --show-progress \
|
||||
apt-utils \
|
||||
curl \
|
||||
wget \
|
||||
nano \
|
||||
ncdu \
|
||||
ca-certificates \
|
||||
supervisor \
|
||||
libsodium-dev \
|
||||
# Install PHP extensions
|
||||
&& install-php-extensions \
|
||||
bz2 \
|
||||
pcntl \
|
||||
mbstring \
|
||||
bcmath \
|
||||
sockets \
|
||||
pgsql \
|
||||
pdo_pgsql \
|
||||
opcache \
|
||||
exif \
|
||||
pdo_mysql \
|
||||
zip \
|
||||
intl \
|
||||
gd \
|
||||
redis \
|
||||
rdkafka \
|
||||
memcached \
|
||||
igbinary \
|
||||
ldap \
|
||||
swoole \
|
||||
&& apt-get -y autoremove \
|
||||
&& apt-get clean \
|
||||
&& docker-php-source delete \
|
||||
&& 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} ${USER} \
|
||||
&& useradd -ms /bin/bash --no-log-init --no-user-group -g ${WWWGROUP} -u ${WWWUSER} ${USER}
|
||||
|
||||
RUN chown -R ${USER}:${USER} ${ROOT} /var/{log,run} \
|
||||
&& chmod -R a+rw /var/{log,run}
|
||||
|
||||
RUN cp ${PHP_INI_DIR}/php.ini-production ${PHP_INI_DIR}/php.ini
|
||||
|
||||
USER ${USER}
|
||||
|
||||
COPY --chown=${USER}:${USER} --from=vendor /usr/bin/composer /usr/bin/composer
|
||||
|
||||
COPY --chown=${USER}:${USER} . .
|
||||
|
||||
RUN mkdir -p \
|
||||
storage/framework/{sessions,views,cache,testing} \
|
||||
storage/logs \
|
||||
bootstrap/cache && chmod -R a+rw storage
|
||||
|
||||
COPY --chown=${USER}:${USER} docker/prod/deployment/supervisord.*.conf /etc/supervisor/conf.d/
|
||||
COPY --chown=${USER}:${USER} docker/prod/deployment/php.ini ${PHP_INI_DIR}/conf.d/99-octane.ini
|
||||
COPY --chown=${USER}:${USER} docker/prod/deployment/start-container /usr/local/bin/start-container
|
||||
|
||||
RUN php artisan storage:link
|
||||
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
RUN cat docker/prod/deployment/utilities.sh >> ~/.bashrc
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT ["start-container"]
|
||||
|
||||
HEALTHCHECK --start-period=5s --interval=2s --timeout=5s --retries=8 CMD php artisan octane:status || exit 1
|
||||
21
docker/prod/LICENSE
Normal file
21
docker/prod/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Exa Company
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
128
docker/prod/README.md
Normal file
128
docker/prod/README.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Laravel Octane Dockerfile
|
||||
<a href="/LICENSE"><img alt="License" src="https://img.shields.io/github/license/exaco/laravel-octane-dockerfile"></a>
|
||||
<a href="https://github.com/exaco/laravel-octane-dockerfile/releases"><img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/exaco/laravel-octane-dockerfile"></a>
|
||||
<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>
|
||||
|
||||
|
||||
Production-ready Dockerfiles for [Laravel Octane](https://github.com/laravel/octane)
|
||||
powered web services and microservices.
|
||||
|
||||
The Docker configuration provides the following setup:
|
||||
|
||||
- PHP 8.2 and 8.3 official Debian-based images
|
||||
- Preconfigured JIT compiler and OPcache
|
||||
|
||||
## Container modes
|
||||
|
||||
You can run the Docker container in different modes:
|
||||
|
||||
| Mode | `CONTAINER_MODE` | HTTP server |
|
||||
| --------------------- | ---------------- | ------------------- |
|
||||
| HTTP Server (default) | `http` | FrankenPHP / Swoole / RoadRunner |
|
||||
| Horizon | `horizon` | - |
|
||||
| Scheduler | `scheduler` | - |
|
||||
| Worker | `worker` | - |
|
||||
|
||||
## Usage
|
||||
|
||||
### Building Docker image
|
||||
1. Clone this repository:
|
||||
```
|
||||
git clone --depth 1 git@github.com:exaco/laravel-octane-dockerfile.git
|
||||
```
|
||||
2. Copy cloned directory content including `deployment` directory, `Dockerfile`, and `.dockerignore` into your Octane powered Laravel project
|
||||
3. Change the directory to your Laravel project
|
||||
4. Build your image:
|
||||
```
|
||||
docker build -t <image-name>:<tag> -f <your-octane-driver>.Dockerfile .
|
||||
```
|
||||
### Running Docker container
|
||||
|
||||
```bash
|
||||
# HTTP mode
|
||||
docker run -p <port>:80 --rm <image-name>:<tag>
|
||||
|
||||
# Horizon mode
|
||||
docker run -e CONTAINER_MODE=horizon --rm <image-name>:<tag>
|
||||
|
||||
# Scheduler mode
|
||||
docker run -e CONTAINER_MODE=scheduler --rm <image-name>:<tag>
|
||||
|
||||
# HTTP mode with Horizon
|
||||
docker run -e WITH_HORIZON=true -p <port>:80 --rm <image-name>:<tag>
|
||||
|
||||
# HTTP mode with Scheduler
|
||||
docker run -e WITH_SCHEDULER=true -p <port>:80 --rm <image-name>:<tag>
|
||||
|
||||
# HTTP mode with Scheduler and Horizon
|
||||
docker run -e WITH_SCHEDULER=true -e WITH_HORIZON=true -p <port>:80 --rm <image-name>:<tag>
|
||||
|
||||
# Worker mode
|
||||
docker run -e CONTAINER_MODE=worker -e WORKER_COMMAND="php /var/www/html/artisan foo:bar" --rm <image-name>:<tag>
|
||||
|
||||
# Running a single command
|
||||
docker run --rm <image-name>:<tag> php artisan about
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Recommended `Swoole` options in `octane.php`
|
||||
|
||||
```php
|
||||
// config/octane.php
|
||||
|
||||
return [
|
||||
'swoole' => [
|
||||
'options' => [
|
||||
'http_compression' => true,
|
||||
'http_compression_level' => 6, // 1 - 9
|
||||
'compression_min_length' => 20,
|
||||
'package_max_length' => 20 * 1024 * 1024, // 20MB
|
||||
'open_http2_protocol' => true,
|
||||
'document_root' => public_path(),
|
||||
'enable_static_handler' => true,
|
||||
]
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
## Utilities
|
||||
|
||||
Also, some useful Bash functions and aliases are added in `utilities.sh` that maybe help.
|
||||
|
||||
## Notes
|
||||
|
||||
- Laravel Octane logs request information only in the `local` environment.
|
||||
- Please be aware of `.dockerignore` content
|
||||
|
||||
## ToDo
|
||||
- [x] Add support for PHP 8.3
|
||||
- [x] 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
|
||||
- [x] Add support for FrankenPHP
|
||||
- [x] Add support for the full-stack apps (Front-end assets)
|
||||
- [ ] Add support `testing` environment and CI
|
||||
- [x] Add support for the Laravel scheduler
|
||||
- [ ] Add support for Laravel Dusk
|
||||
- [x] Support more PHP extensions
|
||||
- [x] Add tests
|
||||
- [ ] Add Alpine-based images
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing! If you find an issue, or have a better way to do something, feel free to open an
|
||||
issue, or a PR.
|
||||
|
||||
## Credits
|
||||
- [SMortexa](https://github.com/smortexa)
|
||||
- [All contributors](https://github.com/exaco/laravel-octane-dockerfile/graphs/contributors)
|
||||
|
||||
## License
|
||||
|
||||
This repository is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
29
docker/prod/deployment/php.ini
Normal file
29
docker/prod/deployment/php.ini
Normal file
@@ -0,0 +1,29 @@
|
||||
[PHP]
|
||||
post_max_size = 100M
|
||||
upload_max_filesize = 100M
|
||||
expose_php = 0
|
||||
realpath_cache_size = 16M
|
||||
realpath_cache_ttl = 360
|
||||
|
||||
[Opcache]
|
||||
opcache.enable = 1
|
||||
opcache.enable_cli = 1
|
||||
opcache.memory_consumption = 256M
|
||||
opcache.use_cwd = 0
|
||||
opcache.max_file_size = 0
|
||||
opcache.max_accelerated_files = 32531
|
||||
opcache.validate_timestamps = 0
|
||||
opcache.file_update_protection = 0
|
||||
opcache.interned_strings_buffer = 16
|
||||
opcache.file_cache = 60
|
||||
|
||||
[JIT]
|
||||
opcache.jit_buffer_size = 128M
|
||||
opcache.jit = function
|
||||
opcache.jit_prof_threshold = 0.001
|
||||
opcache.jit_max_root_traces = 2048
|
||||
opcache.jit_max_side_traces = 256
|
||||
|
||||
[zlib]
|
||||
zlib.output_compression = On
|
||||
zlib.output_compression_level = 9
|
||||
33
docker/prod/deployment/start-container
Normal file
33
docker/prod/deployment/start-container
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
container_mode=${CONTAINER_MODE:-http}
|
||||
octane_server=${OCTANE_SERVER}
|
||||
echo "Container mode: $container_mode"
|
||||
|
||||
initialStuff() {
|
||||
php artisan optimize:clear; \
|
||||
php artisan event:cache; \
|
||||
php artisan config:cache; \
|
||||
php artisan route:cache;
|
||||
}
|
||||
|
||||
if [ "$1" != "" ]; then
|
||||
exec "$@"
|
||||
elif [ ${container_mode} = "http" ]; then
|
||||
echo "Octane Server: $octane_server"
|
||||
initialStuff
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.swoole.conf
|
||||
elif [ ${container_mode} = "horizon" ]; then
|
||||
initialStuff
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.horizon.conf
|
||||
elif [ ${container_mode} = "scheduler" ]; then
|
||||
initialStuff
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.scheduler.conf
|
||||
elif [ ${container_mode} = "worker" ]; then
|
||||
initialStuff
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.worker.conf
|
||||
else
|
||||
echo "Container mode mismatched."
|
||||
exit 1
|
||||
fi
|
||||
17
docker/prod/deployment/supervisord.horizon.conf
Normal file
17
docker/prod/deployment/supervisord.horizon.conf
Normal file
@@ -0,0 +1,17 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=%(ENV_USER)s
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:horizon]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=php %(ENV_ROOT)s/artisan horizon
|
||||
user=%(ENV_USER)s
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
stopwaitsecs=3600
|
||||
27
docker/prod/deployment/supervisord.scheduler.conf
Normal file
27
docker/prod/deployment/supervisord.scheduler.conf
Normal file
@@ -0,0 +1,27 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=%(ENV_USER)s
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:scheduler]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=supercronic -overlapping /etc/supercronic/laravel
|
||||
user=%(ENV_USER)s
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:clear-scheduler-cache]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=php %(ENV_ROOT)s/artisan schedule:clear-cache
|
||||
user=%(ENV_USER)s
|
||||
autostart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
42
docker/prod/deployment/supervisord.swoole.conf
Normal file
42
docker/prod/deployment/supervisord.swoole.conf
Normal file
@@ -0,0 +1,42 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=%(ENV_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 %(ENV_ROOT)s/artisan octane:start --server=swoole --host=0.0.0.0 --port=8000
|
||||
user=%(ENV_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 %(ENV_ROOT)s/artisan horizon
|
||||
user=%(ENV_USER)s
|
||||
autostart=%(ENV_WITH_HORIZON)s
|
||||
autorestart=true
|
||||
stdout_logfile=%(ENV_ROOT)s/horizon.log
|
||||
stopwaitsecs=3600
|
||||
|
||||
[program:scheduler]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=supercronic -overlapping /etc/supercronic/laravel
|
||||
user=%(ENV_USER)s
|
||||
autostart=%(ENV_WITH_SCHEDULER)s
|
||||
autorestart=true
|
||||
stdout_logfile=%(ENV_ROOT)s/scheduler.log
|
||||
|
||||
[program:clear-scheduler-cache]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=php %(ENV_ROOT)s/artisan schedule:clear-cache
|
||||
user=%(ENV_USER)s
|
||||
autostart=%(ENV_WITH_SCHEDULER)s
|
||||
autorestart=false
|
||||
stdout_logfile=%(ENV_ROOT)s/scheduler.log
|
||||
16
docker/prod/deployment/supervisord.worker.conf
Normal file
16
docker/prod/deployment/supervisord.worker.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=%(ENV_USER)s
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:worker]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=%(ENV_WORKER_COMMAND)s
|
||||
user=%(ENV_USER)s
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
12
docker/prod/deployment/utilities.sh
Normal file
12
docker/prod/deployment/utilities.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
tinker() {
|
||||
if [ -z "$1" ]; then
|
||||
php artisan tinker
|
||||
else
|
||||
php artisan tinker --execute="\"dd($1);\""
|
||||
fi
|
||||
}
|
||||
|
||||
# Commonly used aliases
|
||||
alias ..="cd .."
|
||||
alias ...="cd ../.."
|
||||
alias art="php artisan"
|
||||
Reference in New Issue
Block a user