{"id":26472926,"url":"https://github.com/usabilla/php-docker-template","last_synced_at":"2025-04-10T00:16:26.570Z","repository":{"id":36062022,"uuid":"103518100","full_name":"usabilla/php-docker-template","owner":"usabilla","description":"Docker images for PHP applications, CLI and FPM with shared socket","archived":false,"fork":false,"pushed_at":"2024-11-27T15:49:30.000Z","size":549,"stargazers_count":178,"open_issues_count":17,"forks_count":15,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-10T00:16:20.555Z","etag":null,"topics":["chapter-backend","docker","nginx","php","php-images","skeleton"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/usabillabv/php","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/usabilla.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-14T10:13:05.000Z","updated_at":"2024-12-07T21:08:03.000Z","dependencies_parsed_at":"2025-03-19T21:50:30.611Z","dependency_job_id":"e80832ae-fbee-4b3a-9430-525e459341c1","html_url":"https://github.com/usabilla/php-docker-template","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usabilla%2Fphp-docker-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usabilla%2Fphp-docker-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usabilla%2Fphp-docker-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usabilla%2Fphp-docker-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/usabilla","download_url":"https://codeload.github.com/usabilla/php-docker-template/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248131315,"owners_count":21052819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chapter-backend","docker","nginx","php","php-images","skeleton"],"created_at":"2025-03-19T21:50:22.655Z","updated_at":"2025-04-10T00:16:26.549Z","avatar_url":"https://github.com/usabilla.png","language":"Shell","readme":"# PHP Docker images template\n\n[![Usabilla Logo](https://usabilla.com/img/usabilla-logo-circle.svg)](https://usabilla.com/)\n\n[![Continuous Integration](https://github.com/usabilla/php-docker-template/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/usabilla/php-docker-template/actions/workflows/ci.yml)\n[![Docker hub](https://img.shields.io/badge/Docker%20Hub-00a5c9.svg?logo=docker\u0026style=flat\u0026color=00a5c9\u0026labelColor=00a5c9\u0026logoColor=white)](https://hub.docker.com/r/usabillabv/php/)\n[![Docker hub](https://img.shields.io/docker/pulls/usabillabv/php.svg?color=00a5c9\u0026labelColor=03566a)](https://hub.docker.com/r/usabillabv/php/)\n[![Docker hub](https://img.shields.io/microbadger/image-size/usabillabv/php/7.3-fpm-alpine3.11.svg?color=00a5c9\u0026labelColor=03566a)](https://hub.docker.com/r/usabillabv/php/)\n[![Usabilla Feedback Button](.github/static/img/badge-usabilla-leave-us-feedback.png)](https://d6tizftlrpuof.cloudfront.net/live/i/4f03f8e795fb10233e000000/50db3123f698e9156665fa0fb1a914932de5a334.html?reset\u0026project=php-docker-template\u0026source=github)\n\nA series of Docker images to run PHP Applications on Usabilla Style\n\n- [Using and extending](#using-and-extending)\n  - [Nginx](#for-nginx-customization)\n  - [PHP](#for-php-customization)\n    - [Healthcheck](#php-fpm-healthcheck)\n- [Architecture Decisions Records](#architecture-decisions-records)\n- [Basic architecture](#basic-architecture)\n- [The base images](#the-base-images)\n- [Alpine Linux situation](#alpine-linux-situation)\n- [The available tags](#the-available-tags)\n- [Adding more supported versions](#adding-more-supported-versions)\n- [Prometheus Exporter](#prometheus-exporter)\n- [Dockerfile example with Buildkit](#dockerfile-example)\n- [PHP FPM functional example](docs/examples/hello-world-fpm)\n- [Contributing](.github/CONTRIBUTING.md)\n- [License](LICENSE.md)\n\n## Architecture Decisions Records\n\nThis project adheres to ADRs, a [list can be found here](docs/adr/).\n\n## Version Support Policy\n\nOur policy on versions we support [is outlined in ADR0005](docs/adr/0005-define-a-policy-for-supported-versions-and-upgrades.md).\n\n## Basic architecture\n\nAll being based on the official images we provide:\n\n- PHP cli - Compiled without php-fpm, a simple php binary image\n- PHP fpm - Specifically designed to share the php-fpm socket towards a fastcgi compliant web sever\n- Nginx - Meant for PHP projects built on the PHP FPM image in this repository, since [it looks for a php-fpm socket\nand doesn't have access to the PHP code](docs/adr/0002-nginx-configuration-is-shaped-for-php-needs.md)\n\nThe fpm/HTTP server relationship:\n\n```text\n+------------------------------+-----+            +--------------------+\n|                              | :80 |            |                    |\n|  FastCGI HTTP container      +-----+            |  PHP fpm container |\n|                                    |            |                    |\n|                                    |            |                    |\n|       +-------------------------+  |            |  +--------------+  |\n|       |  /var/run/php|fpm.sock  |\u003c--------------+  |  Source code |  |\n|       +-------------------------+  |            |  +--------------+  |\n|                                    |            |                    |\n+------------------------------------+            +--------------------+\n```\n\n### Extra software\n\n- PHP\n  - Shush - Used for decrypting our secret variables using AWS KMS\n  - composer - To provide the installation of PHP projects\n- Nginx\n  - A location.d helper to enable/disable custom location configuration\n\n## The base images\n\nAll images are based on their official variants, being:\n\n- [PHP official image](https://hub.docker.com/_/php/)\n- [Nginx official image](https://hub.docker.com/_/alpine/)\n- Both PHP and Nginx images are based on [Alpine Linux](https://hub.docker.com/_/alpine/)\n\n## Alpine Linux situation\n\nEven though both of the images are based on the Alpine Linux, the PHP official repository gives us the option to choose\nbetween its versions, at this moment being `3.9` or `3.10`.\n\nMeanwhile on the official Nginx images we have no control over which Alpine version we use, this explains the tagging\nstrategy coming in the next section.\n\n## The available tags\n\nThe docker registry prefix is `usabillabv/php`, thus `usabillabv/php:OUR-TAGS`.\n\nIn order to provide upgrade path we intend to keep one or more versions of PHP and Nginx.\n\n[Currently Available tags on Docker hub](https://hub.docker.com/r/usabillabv/php/tags/)\n\nThe tag naming strategy consists of (Read as a regex):\n\n- PHP: `(phpMajor).(phpMinor)-(cli|fpm)-(alpine|future supported OSes)(alpineMajor).(alpineMinor)(-dev)?`\n  - Example: `7.3-fpm-alpine3.11`, `7.3-fpm-alpine3.11-dev`\n  - Note: The minor version might come followed by special versioning constraints in case of betas, etc. For instance\n   `7.3-rc-fpm-alpine3.11-dev`\n- Nginx: `nginx(major).(minor)(-dev)?`\n  - Example: `nginx1.15`, `nginx1.15-dev`\n\n## Adding more supported versions\n\nThe whole CI/CD pipeline is centralized in Makefile targets, the build of cli, fpm and http (for now only nginx) images\nhave their targets named as `build-cli`, `build-fpm` and `build-http`.\n\nWith the help of building scripts the addition of new versions is as easy as updating the Makefile with the desired new\nversion.\n\nAll the newly built versions are going to be automatically tagged and pushed upon CI/CD success, to see the output of\nyour new changes you can see the `(BUILD).tags` file in the `tmp` directory.\n\n### PHP\n\nIn this example adding PHP 7.4-rc for cli and fpm:\n\n```diff\nbuild-cli: clean-tags\n\t./build-php.sh cli 7.4 3.10\n\t./build-php.sh cli 7.4 3.11\n+\t./build-php.sh cli 7.4-rc 3.12\n\nbuild-fpm: clean-tags\n\t./build-php.sh fpm 7.4 3.10\n\t./build-php.sh fpm 7.4 3.11\n+\t./build-php.sh fpm 7.4-rc 3.12\n```\n\nBeing `./build-php.sh (cli/fpm) (PHP version) (Alpine version)`\n\n### Nginx\n\nIn this example adding Nginx 1.16:\n\n```diff\nbuild-http: clean-tags\n    ./build-nginx.sh 1.15 nginx\n    ./build-nginx.sh 1.14\n+   ./build-nginx.sh 1.16\n```\n\nBeing `./build-nginx.sh (nginx version) (extra tag)`\n\nNote you can add extra tags, this means if you want to make Nginx 1.16 our new default version you have to:\n\n```diff\nbuild-http: clean-tags\n-   ./build-nginx.sh 1.15 nginx\n+   ./build-nginx.sh 1.15\n    ./build-nginx.sh 1.14\n-   ./build-nginx.sh 1.16\n+   ./build-nginx.sh 1.16 nginx\n```\n\n### Important\n\nRemoving a version from the build will not remove it from the Docker registry, this has to be done manually when desired.\n\n## Using and extending\n\n### PHP FPM healthcheck\n\nThis image ships with the [php-fpm-healthcheck](https://github.com/renatomefi/php-fpm-healthcheck) which allows you to\nhealthcheck FPM independently of the Nginx setup, providing more compatibility with [the single process Docker\ncontainer](https://cloud.google.com/solutions/best-practices-for-building-containers#package_a_single_app_per_container).\n\nThis healthcheck provides diverse metrics to watch and can be configured according to your needs.\nMore information on how to use it can be found in the\n[official documentation](https://github.com/renatomefi/php-fpm-healthcheck#a-php-fpm-health-check-script).\n\nThe healthcheck can be found in the container `$PATH` as an executable:\n\n```console\n$ php-fpm-healthcheck\n$ echo $?\n0\n```\n\n## Basic usage\n\nSimply use the images as base of the application's `Dockerfile` and apply the necessary changes.\n\n```Dockerfile\n# syntax=docker/dockerfile:1.0.0-experimental\n\nFROM usabillabv/php:7.4-fpm-alpine3.12\n```\n\nIn usual cases it might not be necessary to extend the nginx images, unless you desire to extend its behavior, for\ninstance to serve static files.\n\n[Nginx customization](#for-nginx-customization)\n\n[PHP customization](#for-php-customization)\n\n## For Nginx customization\n\n### Document root configuration\n\nNginx is configured with only one virtual host, which is using `/opt/project/public` as the document root. Ideally we\nshould change this configuration to point to the `public` directory of our project, so that we expose only what's\nnecessary.\n\nIn order to do this you should override `NGINX_DOCUMENT_ROOT` environment variable in the `Dockerfile`, e.g.:  \n\n```Dockerfile\n# assuming that your project is mounted/copied to `/project` and it has a public\n# directory...\n\nENV NGINX_DOCUMENT_ROOT=\"/project/public\"\n```\n\n### Server name configuration\n\nThe default server name is `localhost` and that can also be overridden using an environment variable\n(`NGINX_SERVER_NAME`) in the `Dockerfile`, e.g.:\n\n```Dockerfile\nENV NGINX_SERVER_NAME=\"myawesomeservice myawesomeservice.usabilla.com\"\n```\n\n### Workers\n\nTo use the most of your server you can tweak the number of nginx workers and connections accepted by them, the default\nvalues are (respectively): `1` and `1024`.\n\nThese values can be overridden using environment variables (`NGINX_WORKERS_PROCESSES` and `NGINX_WORKERS_CONNECTIONS`)\nin the `Dockerfile`, e.g.:\n\n```Dockerfile\nENV NGINX_WORKERS_PROCESSES=\"4\"\nENV NGINX_WORKERS_CONNECTIONS=\"2048\"\n```\n\nDocumentation for [worker_processes](http://nginx.org/en/docs/ngx_core_module.html#worker_processes)\nand [worker_connections](http://nginx.org/en/docs/ngx_core_module.html#worker_connections).\n\n### Connection keep alive timeout\n\nThe default `keepalive_timeout` is `75` and that can also be overridden using an environment variable\n(`NGINX_KEEPALIVE_TIMEOUT`) in the `Dockerfile`, e.g.:\n\n```Dockerfile\nENV NGINX_KEEPALIVE_TIMEOUT=\"30\"\n```\n\nMore about it in the [Official documentation](http://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout).\n\n### Client body buffer size\n\nThe default `client_body_buffer_size` is `8k|16k` (depending on architecture), having it configurable helps to not\ncreate disk body buffers in apps that don't splitting it, e.g.:\n\n```Dockerfile\nENV NGINX_CLIENT_BODY_BUFFER_SIZE=\"64k\"\n```\n\nMore about it in the [Official documentation](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size).\n\n### Client max body size\n\nThe default `client_max_body_size` is `1m`, you can increase it in case of\nlarger payloads, e.g.:\n\n```Dockerfile\nENV NGINX_CLIENT_MAX_BODY_SIZE=\"8m\"\n```\n\nMore about it in the [Official documentation](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size).\n\n### Large client header buffers\n\nThe default `large_client_header_buffers` is `4 8k`, being `number size` you can\nincrease it in case of larger header payloads, e.g.:\n\n```Dockerfile\nENV NGINX_LARGE_CLIENT_HEADER_BUFFERS=\"8 128k\"\n```\n\nMore about it in the [Official documentation](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers).\n\n### Expose Nginx version\n\nBy default we are not exposing the nginx version in the `Server` header, that\ncan also be overridden using an environment variable (`NGINX_EXPOSE_VERSION`)\nin the `Dockerfile`, e.g.:\n\n```Dockerfile\nENV NGINX_EXPOSE_VERSION=\"on\"\n```\n\n### Cors configuration\n\nThere's a CORS helper available, it can be activated by running:\n\n```console\n$ docker-nginx-location.d-enable cors\n\n```\n\nOr by setting an environment variable:\n\n```Dockerfile\nENV NGINX_CORS_ENABLE=true\n```\n\nIt's also possible to customize the `Allow-Origin` but setting an environment variable in the `Dockerfile`, e.g.:\n\n```Dockerfile\nENV NGINX_CORS_ALLOW_ORIGIN=\"https://my-domain.cool\"\n```\n\n## For PHP customization\n\n### PHP-FPM Configuration\n\nTo allow tuning the FPM pool, some pool directives are configurable via the following environment variables.\nFor more information on these directives, see [the documentation](https://www.php.net/manual/en/install.fpm.configuration.php).\n\n| Directive               | Environment Variable            | Default                 |\n|-------------------------|---------------------------------|-------------------------|\n| pm                      | PHP_FPM_PM                      | dynamic                 |\n| pm.max_children         | PHP_FPM_PM_MAX_CHILDREN         | 5                       |\n| pm.start_servers        | PHP_FPM_PM_START_SERVERS        | 2                       |\n| pm.min_spare_servers    | PHP_FPM_PM_MIN_SPARE_SERVERS    | 1                       |\n| pm.max_spare_servers    | PHP_FPM_PM_MAX_SPARE_SERVERS    | 3                       |\n| pm.process_idle_timeout | PHP_FPM_PM_PROCESS_IDLE_TIMEOUT | 10                      |\n| pm.max_requests         | PHP_FPM_PM_MAX_REQUESTS         | 0                       |\n| access.format           | PHP_FPM_ACCESS_FORMAT           | %R - %u %t \\\"%m %r\\\" %s |\n\nAn example Dockerfile with customized configuration might look like:\n\n```Dockerfile\n# syntax=docker/dockerfile:1.0.0-experimental\n\nFROM usabillabv/php:7.3-fpm-alpine3.11\n\nENV PHP_FPM_PM=\"static\"\nENV PHP_FPM_PM_MAX_CHILDREN=\"70\"\nENV PHP_FPM_PM_START_SERVERS=\"10\"\nENV PHP_FPM_PM_MIN_SPARE_SERVERS=\"20\"\nENV PHP_FPM_PM_MAX_SPARE_SERVERS=\"40\" \nENV PHP_FPM_PM_PROCESS_IDLE_TIMEOUT=\"35\"\nENV PHP_FPM_PM_MAX_REQUESTS=\"500\"\nENV PHP_FPM_ACCESS_FORMAT {\\\\\\\"cpu_usage\\\\\\\":%C,\\\\\\\"memory_usage\\\\\\\":%M,\\\\\\\"duration_microsecond\\\\\\\":%d,\\\\\\\"script\\\\\\\":\\\\\\\"%f\\\\\\\",\\\\\\\"content_length\\\\\\\":%l,\\\\\\\"request_method\\\\\\\":\\\\\\\"%m\\\\\\\",\\\\\\\"pool_name\\\\\\\":\\\\\\\"%n\\\\\\\",\\\\\\\"process_id\\\\\\\":\\\\\\\"%p\\\\\\\",\\\\\\\"request_query_string\\\\\\\":\\\\\\\"%q\\\\\\\",\\\\\\\"request_uri_query_string_glue\\\\\\\":\\\\\\\"%Q\\\\\\\",\\\\\\\"request_uri\\\\\\\":\\\\\\\"%r\\\\\\\",\\\\\\\"request_url\\\\\\\":\\\\\\\"%r%Q%q\\\\\\\",\\\\\\\"remote_ip_address\\\\\\\":\\\\\\\"%R\\\\\\\",\\\\\\\"response_status_code\\\\\\\":%s,\\\\\\\"time\\\\\\\":\\\\\\\"%t\\\\\\\",\\\\\\\"remote_user\\\\\\\":\\\\\\\"%u\\\\\\\"}\n```\n\n### PHP configuration\n\nThe official PHP images ship with recommended\n[`ini` configuration files](https://github.com/docker-library/docs/tree/master/php#configuration) for both\ndevelopment and production. In order to guarantee a reasonable configuration, our images load these files by default\nin each image respectively at this path: `$PHP_INI_DIR/php.ini`.\n\nImages that wish to extend the ones provided in this repository can override these configurations easily by including\ncustomized configuration files in the `$PHP_INI_DIR/conf.d/` directory.\n\n### Installing \u0026 enabling PHP extensions\n\nThis image bundles helper scripts to manage PHP extensions (`docker-php-ext-configure`, `docker-php-ext-install`, and\n`docker-php-ext-enable`), so it's quite simple to install core and PECL extensions.\n\nMore about it in the [Official Documentation](https://github.com/docker-library/docs/blob/master/php/README.md#how-to-install-more-php-extensions).\n\n#### PHP Core extensions\n\nTo install a core extension that doesn't require any change in the way PHP is compiled you only need to use\n`docker-php-ext-install`, which will compile the extra extension and enable it.\n\nTo do it should include something like this to your `Dockerfile`:\n\n```Dockerfile\n# Enables opcache:\nRUN set -x \\\n    \u0026\u0026 apk add --no-cache gnupg \\\n    \u0026\u0026 docker-php-source-tarball download \\\n    \u0026\u0026 docker-php-ext-install opcache \\\n    \u0026\u0026 docker-php-source-tarball delete\n\n# Installs PDO driver for PostgreSQL (temporarily adding postgresql-dev to have\n# the necessary C libraries):\nRUN set -x \\\n    \u0026\u0026 apk add --no-cache gnupg postgresql-client postgresql-dev \\\n    \u0026\u0026 docker-php-source-tarball download \\\n    \u0026\u0026 docker-php-ext-install pdo_pgsql \\\n    \u0026\u0026 docker-php-source-tarball delete \\\n    \u0026\u0026 apk del gnupg postgresql-dev\n```\n\nSome core extensions, like GD, requires changes to PHP compilation. For that you\nshould also use `docker-php-ext-configure`, e.g.:\n\n```Dockerfile\n# Installs GD extension and the required libraries: \nRUN set -x \\\n    apk add --no-cache freetype-dev libjpeg-turbo-dev libpng-dev \\\n    \u0026\u0026 docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \\\n    \u0026\u0026 docker-php-ext-install gd\n```\n\n#### PECL extensions\n\nSome extensions are not provided with the PHP source, but are instead available through [PECL](https://pecl.php.net/),\nsee a full list of them [here](https://pecl.php.net/packages.php).\n\nTo install a PECL extension, use `pecl install` to download and compile it, then use `docker-php-ext-enable` to enable\nit:\n\n```Dockerfile\n# Installs ast extension (temporarily adding the necessary libraries):\nRUN set -x \\\n    \u0026\u0026 apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS \\\n    \u0026\u0026 pecl install ast \\\n    \u0026\u0026 docker-php-ext-enable ast \\\n    \u0026\u0026 apk del .phpize-deps\n```\n\nCheck if the extension is loaded after building it:\n\n```console\n$ docker build .\nSuccessfully built 5bcf0f7d49b0\n$ docker run --rm 5bcf0f7d49b0 php -m | grep ast\nast\n```\n\n```Dockerfile\n# Installs MongoDB Driver (temporarily adding the necessary libraries):\nRUN set -x \\\n    \u0026\u0026 apk add --no-cache --virtual .build-deps $PHPIZE_DEPS openssl-dev  \\\n    \u0026\u0026 pecl install mongodb-1.5.3 \\\n    \u0026\u0026 docker-php-ext-enable mongodb \\\n    \u0026\u0026 apk del .build-deps\n```\n\n#### Common extension helper scripts\n\nSome extensions are used across multiple projects but can have some complexities while installing so we ship helper\nscripts with the PHP images to install dependencies and enable the extension. The following helper scripts can be run\ninside projects' Dockerfile:\n\n- `docker-php-ext-rdkafka` for RD Kafka\n- `docker-php-ext-pdo-pgsql` for PDO Postgres\n\n#### Xdebug\n\nSince [Xdebug](https://xdebug.org) is a common extension to be used we offer two options:\n\n##### Dev image\n\nUse the `dev` image by appending `-dev` to the end of the tag, like: `usabillabv/php:7.3-fpm-alpine3.11-dev`.\n\nNot recommended if you're layering with your production images, using a different base image doesn't allow to you share\ncache among your Dockerfile targets.\n\nWe ship the image with a dev mode helper, which can install and configure Xdebug, as well as override the production\n`php.ini` with the recommended development version.\n\n##### Helper script\n\nInstalling and enabling the extensions\n\n```console\n$ docker-php-dev-mode xdebug\n```\n\nAs mentioned, we override the production `php.ini` with the recommended development version, which can be found\n[here](https://github.com/php/php-src/blob/master/php.ini-development).\n\nNext to that we provide some additional configuration to make it easier to start your debugging session. The contents\nof that configuration can be found [here](src/php/conf/available/xdebug.ini).\n\nBoth are enabled via the helper script, by running\n\n```console\n$ docker-php-dev-mode config\n```\n\n##### Setting up Xdebug\n\nXdebug 3 comes with new mechanism to enable it's functionalities. The most notable, is the introduction of the \n`xdebug.mode` setting, which controls which features are enabled. It can be specified via `.ini` files or by using the \nenvironment variable `XDEBUG_MODE`. To learn more about the different modes in which Xdebug can be configured, please \nrefer to the [Xdebug settings guide](https://xdebug.org/docs/all_settings#mode).\n\n##### Notable changes from Xdebug 2\n\nWith the introduction of the Xdebug mode in the v3 release, it is now mandatory to specify either `xdebug.mode=coverage` setting in .ini \nfile, or `XDEBUG_MODE=coverage` as environment variable, to use the code coverage analysis features. This impacts tools \nlike mutation tests.\n\nWe recommend setting the XDEBUG_MODE when booting up a new container. Here's an example on how it could look like:\n\n```shell\ndocker run -it \\\n  -e XDEBUG_MODE=coverage \\\n  -v \"\u003cHOST_PATH\u003e:\u003cCONTAINER_PATH\u003e\" \\\n  usabillabv/php:7.4-cli-alpine3.12-dev \\\n  vendor/bin/infection --test-framework-options='--testsuite=unit' -s --threads=12 --min-msi=100 --min-covered-msi=100\n```\n\nAnother notable change, is the Xdebug port change. The default port is now `9003` instead of `9000`. Check your IDE \nsettings to confirm the correct port is specified. \n\nFor the full upgrade guide, please refer to the [official upgrade guide](https://xdebug.org/docs/upgrade_guide).\n\n## Prometheus Exporter\n\nIn order to monitor applications many systems implement Prometheus to expose metrics, one challenge specially in PHP is how to expose those to Prometheus without having to, either implement an endpoint in our application, or add HTTP and an endpoint for non-interactive containers.\n\nThis prove has the aim to provide support for the sidecar pattern for monitoring.\n\nMore about [\"Make your application easy to monitor\" by Google](https://cloud.google.com/solutions/best-practices-for-operating-containers#make_your_application_easy_to_monitor)\n\n### Static File\n\nThe easiest way to solve this problem in the PHP ecosystem is to make your application write down the metrics to a text file, which then is shared via a volume to a sidecar container which can expose it to Prometheus.\n\nThe container we offer is a simple Nginx based on the same configuration as [the one for PHP-FPM](#for-nginx-customization), with the difference it only serves static content.\n\n#### Docker image\n\nThe image named `prometheus-exporter-file` is available via our docker registry under with the tags (from less to more specific versions):\n\n- `usabillabv/php:prometheus-exporter-file` - This has the behavior of latest\n- `usabillabv/php:prometheus-exporter-file1`\n- `usabillabv/php:prometheus-exporter-file1.0`\n\n#### Kubernetes Deployment Example\n\n```yaml\n# Pod v1 core Spec - https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#pod-v1-core\n\nspec:\n  template:\n    metadata:\n      annotations:\n        prometheus.io/path: /metrics\n        prometheus.io/port: \"5556\"\n        prometheus.io/scrape: \"true\"\n    spec:\n      containers:\n      - image: usabillabv/php:7.3-cli-alpine3.11\n        imagePullPolicy: IfNotPresent\n        volumeMounts:\n        - mountPath: /prometheus\n          name: prometheus-metrics\n      - image: usabillabv/php:prometheus-exporter-file1\n        imagePullPolicy: IfNotPresent\n        name: prometheus-exporter\n        env:\n        - name: NGINX_PORT\n          value: \"5556\"\n        ports:\n        - containerPort: 5556\n          name: http\n          protocol: TCP\n        volumeMounts:\n        - mountPath: /opt/project/public\n          name: prometheus-metrics\n      volumes:\n      - emptyDir: {}\n        name: prometheus-metrics\n\n```\n\nIn this example the PHP container *must* write down the metrics in the file `/prometheus/metrics`, the exporter container will have the same file mount at `/opt/project/public/metrics`.\nWhich will then be available via http as `http://pod:5556/metrics`, observe that the filename becomes the url which we configured the prometheus scrape to look for.\n\n### Open Census\n\n_To be created and/or documented_\n\nFor now please refer to: https://github.com/basvanbeek/opencensus-php-docker and https://github.com/census-instrumentation/opencensus-php\n\n## Dockerfile example\n\nThe Dockerfile in the example below is meant to centralize the production and development images in a single Dockerfile,\nsharing cached layers among the build steps, cleaning unnecessary files like tests, docs and readme files from the final\nresult via git archive.\n\nComposer auth is done via a secret mount to avoid layering credentials and keeping the layers lean.\n\nWe also run the image with the `app` user since doing it as `root` is considered a bad practice.\n\nTo be able to build this image you need [Docker buildkit](https://github.com/moby/buildkit) enabled, this is what\nempowers the `RUN` mounts and more, check its documentation\n[here](https://docs.docker.com/develop/develop-images/build_enhancements/).\n\n```Dockerfile\n# syntax=docker/dockerfile:1.0.0-experimental\n\n# The base target will serve as initial layer for dev and prod images,\n# thus all necessary global configurations, extensions and modules\n# should be put here\nFROM usabillabv/php:7.3-fpm-alpine3.11 AS base\n\n# When composer gets copied we want to make sure it's from the major version 1\nFROM composer:1 as composer\n\n# The source target is responsible to prepare the source code by cleaning it and\n# installing the necessary dependencies, it's later copied into the production\n# target, which then leaves no traces of the build process behind whilst making\n# the image lean\nFROM base as source\n\nENV COMPOSER_HOME=/opt/.composer\n\nRUN apk add --no-cache git\n\nCOPY --from=composer /usr/bin/composer /usr/bin/composer\n\nWORKDIR /opt/archived\n\n# Mount the current directory at `/opt/project` and run git archive\n# hadolint ignore=SC2215\nRUN --mount=type=bind,source=./,rw \\\n    mkdir -p /opt/project \\\n    \u0026\u0026 git archive --verbose --format tar HEAD | tar -x -C /opt/project\n\nWORKDIR /opt/project\n\n# Mount composer.auth to the project root and composer cache if available\n# then install the dependencies\n# hadolint ignore=SC2215\nRUN --mount=type=secret,id=composer.auth,target=/opt/project/auth.json \\\n    --mount=type=bind,source=.composer/cache,target=/opt/.composer/cache \\\n    composer install --no-interaction --no-progress --no-dev --prefer-dist --classmap-authoritative\n\n# Copy the source from its target and prepare permissions\nFROM base as prod\n\nWORKDIR /opt/project\n\nCOPY --chown=app:app --from=source /opt/project /opt/project\n\n# Install Xdebug and enable development specific configuration\n# also create a volume for the project which will later be mount via run\nFROM base AS dev\n\nCOPY --chown=app:app --from=composer /usr/bin/composer /usr/bin/composer\n\nRUN docker-php-dev-mode xdebug \\\n    \u0026\u0026 docker-php-dev-mode config\n\nVOLUME [ \"/opt/project\" ]\n\n```\n\n### Building this image as dev\n\n```console\n$ DOCKER_BUILDKIT=1 docker build -t \"my-project-dev:latest\" \\\n  --target=dev .\n```\n\n### Building this image as prod\n\nYou want to run this in your CI/CD environment, you can create the `composer.auth` file there, for this example let's\nget your computer's file and mount the secret.\n\n```console\n$ cp ~/.config/composer/auth.json .composer-auth.json\n$ DOCKER_BUILDKIT=1 docker build -t \"my-project-prod:latest\" \\\n  --target=prod \\\n  --secret id=composer.auth,src=.composer-auth.json\n```\n\n### Working example\n\nWe also have a simple, but fully functional PHP FPM example, [check it here](docs/examples/hello-world-fpm).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusabilla%2Fphp-docker-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusabilla%2Fphp-docker-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusabilla%2Fphp-docker-template/lists"}