This project provides Docker images containing the bare minimum requirements to run your Laravel application. We use PHP's official CLI/ZTS images based on Alpine Linux to further reduce the size of these images.
You may notice that your favorite PHP extensions and NodeJS are missing from these images, but this is a feature ✨. The intention of these images is to provide the absolute minimum requirements so that you, the developer, pull these images, and further customize them with everything you need.
You can choose the PHP version you want to run by specifying it as the tag for your image.
Currently, we build base images for PHP versions 8.0
to 8.3
:
ghcr.io/iksaku/laravel-alpine:8.0
ghcr.io/iksaku/laravel-alpine:8.1
ghcr.io/iksaku/laravel-alpine:8.2
ghcr.io/iksaku/laravel-alpine:8.3
We also build images compatible with Laravel Octane, you can choose your favorite flavor from the following list:
Runtime | Supported PHP versions | Image name example |
---|---|---|
frankenphp |
8.2 -8.3 |
ghcr.io/iksaku/laravel-alpine:8.3-octane-frankenphp |
openswoole |
8.0 -8.3 |
ghcr.io/iksaku/laravel-alpine:8.3-octane-openswoole |
roadrunner |
8.0 -8.3 |
ghcr.io/iksaku/laravel-alpine:8.3-octane-roadrunner |
swoole |
8.0 -8.3 |
ghcr.io/iksaku/laravel-alpine:8.3-octane-swoole |
Pre-installed PHP extensions in these images follow Laravel's Requirements and also include a few extras for Database and Octane support:
Name | Availability |
---|---|
bcmath | ✓ |
ctype | ✓ |
curl | ✓ |
dom | ✓ |
fileinfo | ✓ |
intl | ✓ |
json | ✓ |
mbstring | ✓ |
mysqli | ✓ |
openssl | ✓ |
pcre | ✓ |
pdo | ✓ |
pdo_mysql | ✓ |
pdo_pgsql | ✓ |
pdo_sqlite | ✓ |
pgsql | ✓ |
redis | ✓ |
sqlite3 | ✓ |
tokenizer | ✓ |
xml | ✓ |
composer | ✓ |
pcntl | ✓ |
openswoole | Octane-only (OpenSwoole) |
sockets | Octane-only (RoadRunner) |
swoole | Octane-only (Swoole) |
Tip
You can always view the list of installed extensions from your terminal:
docker run --rm ghcr.io/iksaku/laravel-alpine:8.1 php -m
Our images come with mlocati's install-php-extension
binary available, so you can install additional PHP extensions that you may need:
FROM ghcr.io/iksaku/laravel-alpine:8.1
RUN install-php-extension \
ffi \
vips \
yaml
You can see all available extensions at install-php-extension
's repo.
As opposed to Laravel Sail, you don't need to import
this repository as a package nor publish our Dockerfile
assets most of the time,
you can use our images directly in your docker-compose.yml
file or use them
as a base for your custom Dockerfile
.
Before proceeding, it is important to know that our images dynamically adjust Group and User
permissions when your container starts, while Laravel Sail adjust the Group permissions
on build, so the first change you must make is to move the WWWGROUP
argument to be
part of the environment
variables of your docker-compose.yml
file:
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
- args:
- WWWGROUP: '${WWWGROUP}'
# ...
envrionment:
WWWUSER: '${WWWUSER}'
+ WWWGROUP: '${WWWGROUP}'
# ...
To run our images in Laravel Sail, you can replace the build
option with image
in your docker-compose.yml
file:
services:
laravel.test:
- build:
- context: ./vendor/laravel/sail/runtimes/8.1
+ image: ghcr.io/iksaku/laravel-alpine:8.1
Tip
You can always update to the latest version of your chosen image
using sail pull
📥.
Octane images also run in Laravel Sail; you need to change your image
reference to specify you want to run octane:
services:
laravel.test:
- image: ghcr.io/iksaku/laravel-alpine:8.1
+ image: ghcr.io/iksaku/laravel-alpine:8.1-octane-roadrunner
If you want to customize your image further, then work with the build
option in your
docker-compose.yml
file:
super-duper-project
├── app
├── bootstrap
│ ...
├── docker
│ └── super-duper-runtime
│ └── Dockerfile
├── docker-compose.yml
│ ...
services:
laravel.test:
build:
- image: ghcr.io/iksaku/laravel-alpine:8.1
+ context: ./docker/super-duper-runtime
Published images can also be used in production, but to run the best in-class service, it is 100% recommended that you take a look into customizing the image to your needs, as well as to make sure that the build process is tailored to your needs.
The following script can be a good starting point for most projects:
# Based on @fideloper's fly.io laravel template
# https://github.com/superfly/flyctl/blob/94fec0925c75cfe30921f1a4df25fa9cbf2877e9/scanner/templates/laravel/Dockerfile
FROM ghcr.io/iksaku/laravel-alpine:8.1
# Run the installed Laravel Scheduler in the background.
# You can replace the default entry by copying your own crontab
# file in container's /var/spool/cron/crontabs/root
RUN crond
# Copy our project files into the container
COPY . /var/www/html
# Install composer dependencies
RUN composer install --optimize-autoloader --no-dev
# Make sure our container has the correct permissions
# to tap into our project storage
RUN mkdir -p storage/logs \
&& chmod -R ug+w /var/www/html/storage \
&& chmod -R 755 /var/www/html
# (Optional) Allow requests when running behind a proxy (i.e., fly.io)
RUN sed -i 's/protected \$proxies/protected \$proxies = "*"/g' app/Http/Middleware/TrustProxies.php
When deploying your code to different environments, commonly staging
or production
, a
need to execute specific commands or script arises, mainly when dealing with Database migrations,
linking storage folders, or performing a general app optimization.
To help out with these tasks, our images support executing scripts inside a .deploy
directory before running the Laravel server.
To keep things simple, we do not check for a specific list of environments, instead we
execute deployment scripts when a RUN_DEPLOY_SCRIPTS
environment variable is available
and has a value of 1
; otherwise, we ignore deployment scripts and jump straight
into server execution.
Important
RUN_DEPLOY_SCRIPTS
is ignored when running in Laravel Sail to prevent unintended
side effects.
If you have multiple scripts, you can number them in the order they should be executed:
my-laravel-app/
├── .deploy/
│ ├── 01_migrate_database.sh
│ ├── 02_optimize_application.sh
├── app/
├── bootstrap/
│ ...
Important
Deploy scripts should be suffixed with the .sh
extension and will be run using
Alpine's sh
shell as we do not have bash
.
It is recommended that when you deploy your code to a production environment you run the following commands:
php artisan optimize
php artisan migrate --force
It is easy to add such commands to a before/after deploy hook on most cases, but
when deploying to Fly.io it is rather troublesome that you can't
execute these commands in your Dockerfile
, as it has no access to envrionment variables
during build.
Another way to execute deployment commands when deploying to Fly.io is by creating a
on_deploy.sh
script on your app's root directory, and then calling this script from
your fly.toml
file using the deploy.release_command
property:
#!/usr/bin/env sh
php artisan migrate --force
# fly.toml
# ...
[deploy]
release_command = "sh ./on_deploy.sh"
# ...
When using this method, Fly will spawn a temporary (or ephemeral) virtual machine with
access to your app's environment to execute this script, and later on, it will destroy such
VM and queue another VM to take over the given environment. This means that any file-based
changes done while executing the release_command
will not be persisted, so only procedures
that ping other services not in the VM, like Database migrations, will persist.
Use the above mentioned .deploy
directory if you are planning to execute commands like
artisan storage:link
or artisan optimize
.
Note
The image's default entrypoint will manage this command, making
your script execution to be done by the laravel
user, which is the
default one configured with all app permissions in your container.
Fly's support for multiple process groups allow to run multiple commands (or processes) in separate machines. This is useful when you want also run a queue worker or a scheduler:
# fly.toml
# ...
[processes]
# This is the default process group running our Laravel app
app = ""
# Run the Laravel scheduler using Alpine's crond in the foreground (for logs)
scheduler = "crond -f"
# Run the Laravel queue worker
worker = "php artisan queue:work"
For more information on how process groups work and how you can scale them, check out:
As this intends to be an alternative version of Laravel Sail images, most of the credit goes to the @laravel team itself for building and maintaining Laravel Sail for us 💖.
Also, much inspiration (and snippets) come from @fideloper's public work on Fly.io's Laravel Template 🔮.