Provides an opinionated, extensible PHP docker image build & run concept, which unifies common scenarios to build and run PHP applications / jobs in a container world. It ships with default configurations for nginx and php-fpm, supports the most important configurations to be set via environment variables and makes it easy to check external services (like a DBMS, cache, object-store) before proceeding with the container startup.
- extends official docker php images
- provides generic build and life cycle infrastructure for containerized PHP applications (well prepared for kubernetes)
- shipped as PHP 7.1.x and 7.2.x flavor
- there is a (build>base already run / build>base only prepared) flavor for each PHP version
- general run concept:
docker run --rm -t claranet/php:1.1.14-php7.2.5 <main-section> [subsection] [subsection-args, ...]
- overview:
docker run --rm -t claranet/php:1.1.14-php7.2.5 help
- supplied services
- nginx
- phpfpm
- crond
Build image locally:
# generates local/claranet/php:1.1.14-php7.2.5
./bin/image.sh build
System requirements: To be able to build this docker image, you need docker
, gettext
(envsubst) and the bash
.
The concept is based on the good old .d
directory concept from debian. There are 3 levels we need to discuss
- main section
- subsection
- steps
A quick visual overview gives (see more details below)
A main section is collection of subsections
which share an abstract topic. For example on default we provide the following
main sections by default:
- build
- start
- stop
- test
Main sections are identified by looking for a .d
directory within docker/
. The entrypoint is designed to look up
available main sections automatically. So you are able to introduce new main sections in your custom derivate of this
image by adding an additional .d
directory.
To execute all subsections of a main section, you need to call the main section from /entrypoint.sh
. So running all
build subsections is done by calling /entrypoint.sh build
.
Note: not all main sections are able to run all subsections! (e.g. start
). See configure sections
for more details regarding this topic.
Each main section must have at least one subsection. Subsections exist in order to organize related, self-contained steps
(scripts). Subsections can be executed directly by specifying the subsection after the main section. So calling only
the subsection base
from the main section build
, you need to execute /entrypoint.sh build base
.
Subsections are directories within a main section - naming doesn't matter!
Calling a subsection results in a execution of all steps contained in the subsection. Steps are executed in alphanumeric order.
Note: you can describe subsections in the /entrypoint.sh help
by configuring them
Context
A step lives inside a subsection, so the hierarchy looks like main section > subsection > step
. A step is represented in
form of a script. This script can be referenced by a symlink or live directly inside the subsection. Only bash scripts
are currently supported. A step will be sourced by the caller, which makes all functions / vars from previous steps and
docker/*.inc.sh
files available to the script itself.
Each step current dir is set to $WORKDIR
before executing the step.
Shared steps
Some steps are required in multiple subsections. To overcome the need of reimplementing / having duplicated steps
steps can be references via symlinks. The Claranet PHP image already makes use of this and provides a directory
called docker/shared_steps/
. You can find scripts there, which will be referenced by multiple subsections.
If you need a step in multiple subsections, please make use of this mechanism!
Main sections and subsections share the same way how they can be configured. A section may contain a file named META
.
If available, this file will be included by /entrypoint.sh help
and in the run to iterate of all subsections
(e.g. /entrypoint.sh build
).
The help method uses the SECTION_DESCRIPTION
to print more details about the available sections. In case of a main section
it will be able to print a multi line string - standing by it's own. In case of a subsection the content should be
kept short and one-line only - as it gets print after the subsection name.
META
file schema:
# a one line description text which will be printed inside the help message
# Default: no description specified (see Configure Sections in documentation)
SECTION_DESCRIPTION="...your description..."
# AFFECT MAIN SECTIONS ONLY
# if false => requires the user to call a subsection directly
# and prohibits running all subsections by calling the main section only
# Default: true
CATCH_ALL_EXECUTION="<true|false>"
The docker image build is, despite the recommendation, outsourced in multiple shell scripts, living within the section build
. The build process is split in at least 2 subsections (parts): base
and deps
. The user is able and encouraged to add custom subsections and overwrite or enhance current subsections.
base:
The subsection base
prepares the image OS by...
- configure APT sources
- install APT packages (listed in
SYSTEM_PACKAGES
env var) - install / compile PHP modules
- install / configure PHP composer
- install nodejs and npm
- install git and configure it to use HTTPS instead of SSH for cloning
- install the newrelic daemon / php module if
ENABLE_NEWRELIC
is set totrue
If you are lucky, you shouldn't be required to run this subsection in your customized image.
In order to speed up the build process for images based on this one, we already run the base
subsection while building this image. If you need a lot of customization, you might need to run the base subsection by your own - this is why we also provide a -nobase
flavoured image! The -nobase
flavour comes with all the prepared scripts from build > base
, but those script haven't been executed yet.
However, you should run the base
subsection before running any other subsection!
deps:
Deps is a prepared-only subsection. It is meant to install application specific dependencies like npm or composer packages; apply code patches or do any other task to make the application code runnable.
This subsection should be called by the depending custom docker image!
Checkout default values in the Dockerfile.
To easy docker builds, we provide a few handy options here
Name | Default value | Description |
---|---|---|
ERROR_EXIT_CODE | 1 | Docker build RUN step error code on failure; handy for debugging |
ENABLE_CLEANUP | true | If true, prevents cache clearing, removing of build packages/download artifacts |
ENABLE_GCP | false | Enable GCP optimizations (e.g. use GCP APT mirror) |
RUN_BUILD_BASE | true | Switch to disable build > base for the -nobase flavoured image |
GITLAB_SERVER_NAME | Normaly the content of $CI_SERVER_NAME in gitlab-ci jobs; ONBUILD only |
|
GITLAB_USER | gitlab-ci-token | The token user to auth against gitlab; ONBUILD only |
GITLAB_TOKEN | emtpy | The actual token to auth against gitlab; ONBUILD only |
Name | Description |
---|---|
WORKDIR | Docker WORKDIR, exposed as env var to easy scripting |
BUILD_LOG | Path to the build log file |
ENABLE_PATCHES | Enables/disables deps > apply patches step |
Name | Description |
---|---|
ENABLE_GCP | If true, enables GCP optimizations |
GOOGLE_ASSET_BUCKET_ENABLED | Enable bucket support in nginx |
ASSET_BUCKET_NAME | The GCP Cloud Storage name, will be used for the nginx config |
ASSET_VERSION | A string which indicates the asset version, e.g. the commit SHA |
Name | Description |
---|---|
PATH | OS PATH variable |
BUILD_PACKAGES | APT packages, removed by CLEANUP, if ENABLE_CLEANUP is true |
SYSTEM_PACKAGES | APT packages |
JESSIE_PACKAGE_MAP | Maps Debian stretch to jessie package names <stretch-name>:<jessie-name> |
ENABLE_NEWRELIC | If true, install the newrelic daemon + php module at build time (base ) |
Nginx does not support environment variables by itself (except if you enable the lua script support...). So we are using envsubst
before enabling configs from /etc/nginx/sites-available/*.conf
.
Name | Description |
---|---|
NGINX_SITES_AVAILABLE | Path to the sites-available/ directory |
NGINX_SITES_ENABLED | Path to the sites-enabled/ directory |
PHPFPM_HOST | IP/Domain where to find the php-fpm fastcgi service |
PHPFPM_PORT | Port of the php-fpm fastcgi service |
DOCUMENT_ROOT | Default document root for the default vhost |
COMPRESS_FILE_MATCH | Extended regex for matching files which should be compressed for nginx |
COMPRESS_FILE_PATHS | Where to look for files to be compressed during build time |
Name | Description |
---|---|
ENABLE_NODEJS | Install nodejs at build time base |
NODEJS_VERSION | Major version (e.g. 8 or 10 ) |
ENABLE_BOWER | Install bower at build time deps |
NPM | Name of the npm cli binary (npm or yarn ) |
NPM_BUILD_PACKAGES | APT packages to be able to compile packages at build time deps |
NPM_ARGS | Additional arguments for $NPM install |
We are exposing most of the important php.ini
settings via environment variables and
use the ini-env-var substitution feature from PHP for that.
Name | Description |
---|---|
PHP | The PHP binary name |
FPM | The PHP-FPM binary name |
NEWRELIC_PHP_VERSION | The newrelic php module package version, only useful, if ENABLE_NEWRELIC is true |
PHP_EXTENSIONS_STARTUP_ONLY | A list of modules which shouldn't be enabled at build time |
PHP_EXTENSIONS_STARTUP_ENABLE | A list of modules, which should get enabled at container startup |
PHP_EXTENSIONS | List of modules which should get compiled at build time (build base) |
PHP_BUILD_PACKAGES | APT packages required to compile extensions |
PHP_INI_DIR | Where to look for and store php ini files? |
PHP_INI_ALLOW_URL_FOPEN | PHP ini allow_url_fopen value |
PHP_INI_DATE_TIMEZONE | PHP ini date.timezone value |
PHP_INI_INCLUDE_PATH | PHP ini include_path value |
PHP_INI_MAX_EXECUTION_TIME | PHP ini max_execution_time value |
PHP_INI_MAX_INPUT_TIME | PHP ini max_input_time value |
PHP_INI_MAX_INPUT_VARS | PHP ini max_input_vars value |
PHP_INI_MEMORY_LIMIT | PHP ini memory_limit value |
PHP_INI_ERROR_LOG | PHP ini error_log value |
PHP_INI_POST_MAX_SIZE | PHP ini post_max_size value |
PHP_INI_APC_ENABLED | PHP ini apc_enabled value |
PHP_INI_APC_SHM_SIZE | PHP ini apc_shm_size value |
PHP_INI_OPCACHE_ENABLE | PHP ini opcache_enable value |
PHP_INI_OPCACHE_ENABLE_CLI | PHP ini opcache_enable_cli value |
PHP_INI_OPCACHE_MEMORY_CONSUMPTION | PHP ini opcache_memory_consumption value |
PHP_INI_OPCACHE_VALIDATE_TIMESTAMPS | PHP ini opcache_validate_timestamps value |
PHP_INI_FILE_UPLOADS | PHP ini file_uploads value |
PHP_INI_UPLOAD_MAX_FILESIZE | PHP ini upload_max_filesize value |
PHP_INI_MAX_FILE_UPLOADS | PHP ini max_file_uploads value |
PHP_INI_SHORT_OPEN_TAG | PHP ini _short_open_tag |
PHP_INI_NEWRELIC_APPNAME | PHP ini newrelic_appname value |
PHP_INI_NEWRELIC_FRAMEWORK | PHP ini newrelic_framework value |
PHP_INI_NEWRELIC_LICENSE | PHP ini newrelic_license value |
BLACKFIRE_AGENT | URL of the blackfire agent |
CONSOLE | Composer console command name |
CODECEPT | The codeception cli command name (with path) |
CODECEPTION_ARGS | Args which should get added to the codeception cli command name |
COMPOSER_VERSION | Specify the composer version, which gets installed in build > base |
COMPOSER_ARGS | Additional composer install arguments, passed in build > deps subsection |
COMPOSER_DUMP_ARGS | Args applied to the composer autodump command |
Name | Description |
---|---|
ENABLE_SMTP | Enable / Disable ssmtp configuration and therefor mailing |
SMTP_ENCRYPTION | Connection encryption used, e.g. tls (is STARTTLS) or ssl |
SMTP_AUTH_METHOD | Method used to authenticate against the SMTP server e.g. login |
SMTP_HOST | IP or domain of the SMTP service |
SMTP_PORT | Port of the SMTP service |
SMTP_USERNAME | Username used in conjunction with SMTP_AUTH_METHOD |
SMTP_PASSWORD | Password used in conjunction with SMTP_AUTH_METHOD |
SMTP_TIMEOUT | Connection timeout for established SMTP service connections |
- uses filesystem meta information cache
- configurable via
DOCUMENT_ROOT
,PHPFPM_HOST
andPHPFPM_PORT
environment variables
php-fpm
The php-fpm configuration is designed to match a generic pattern - optimized to leverage the usual load per container. Normally you shouldn't be required to change the fpm configuration at all - if your container needs to handle more requests, launch another one and balance the traffic.substitute
If you still need to extend the php-fpm config - the start > phpfpm
subsection is prepared to launch different
fpm pools. To launch e.g. a pool named wordpress
, after you added the pools config to the container:
/entrypoint.sh start phpfpm wordpress
It will start the default
phpfpm pool if no other pool name is given.
NOTE: On default, OPCACHE is enabled and won't revalidate filesystem changes.
php.ini
In order to allow PHP config customization, this image uses the PHP ini parsers ability to substitute ENV vars for ini values. See available PHP env vars for more details.
A list of module, coming with this docker image:
Name | Source | Enabled |
---|---|---|
bcmath | core | yes |
bz2 | core | yes |
gd | core | yes |
gmp | core | yes |
intl | core | yes |
json | core | yes |
mbstring | core | yes |
opcache | core | yes |
dom | core | yes |
curl | core | yes |
pgsql | core | yes |
pdo_pgsql | core | yes |
mysqlnd | core | yes |
pdo_mysql | core | yes |
ldap | core | yes |
soap | core | yes |
zip | core | yes |
xdebug | pecl | no |
imagick | pecl | no |
redis | pecl | no |
APCu | pecl | no |
To overcome the vixie-cron (debian default) environment variables issue (they are not propagated to launched cron-jobs), this image uses busybox' crond.
Cronjobs can be configured in the docker/etc/cron.d directory. You can put there a file per username (e.g. named root) with cronjob entries based on the normal cron config syntax and COPY
those files via your Dockerfile
to /etc/cron.d/
within the image.
# Cron config syntax
# m h dom mon dow command
* * * * * mytask
Those files will be linked to /var/spool/cron/crontabs/
when start > crond
gets executed.
Mailing via CLI is an easy topic with this image. Set ENABLE_SMTP
to true
and ssmtp will be pre-configured on the start
subsections crond
, pre-deployment
and post-deployment
. After that, you can use the ssmtp
tool to send your mails synchronously.
For example:
ssmtp to@local <<EOF
To: to@local
From: from@local
Subject: [claranet] This is a nice mail
Helo,
from CLI
Regards,
Me - the CLI
EOF