/laravel-docker-lite

🐳🐘 Dockerized PHP/LARAVEL stack: Nginx, MySQL, MongoDB, PHP-FPM and Redis

Primary LanguageShellMIT LicenseMIT

This repository is no longer maintained/updated, see new repository https://github.com/allysonsilva/laravel-docker

Laravel+Docker

Use this repository to get started with developing your Laravel application in a Docker container.

This is a personal collection of Docker tools and images(Nginx, PHP-FPM, MySQL, Redis, MongoDB, Queue, Scheduler, and RabbitMQ) for applications in Laravel.

Overview

  1. Project Structure/Tree
  2. What's Inside/Softwares Included
  3. Getting Started
  4. Run the application

Project Structure/Tree

tree -a  -I '.git|.DS_Store' --dirsfirst
.
├── mongodb
│   ├── ssl
│   │   ├── .gitignore
│   │   ├── ca.pem
│   │   ├── client.pem
│   │   └── server.pem
│   └── mongod.conf
├── mysql
│   ├── ssl
│   │   ├── .gitignore
│   │   ├── ca.pem
│   │   ├── client-cert.pem
│   │   ├── client-key.pem
│   │   ├── server-cert.pem
│   │   └── server-key.pem
│   ├── my.cnf
│   └── mysql.env
├── nginx
│   ├── certs
│   │   ├── .gitignore
│   │   ├── fullchain.pem
│   │   └── privkey.pem
│   ├── configs
│   │   ├── addon.d
│   │   │   └── 10-realip.conf
│   │   ├── nginx.d
│   │   │   ├── 10-headers.conf
│   │   │   ├── 20-gzip-compression.conf
│   │   │   ├── 20-open-file-descriptors.conf
│   │   │   ├── 30-buffers.conf
│   │   │   ├── 40-logs.conf
│   │   │   ├── 50-timeouts.conf
│   │   │   ├── 60-misc.conf
│   │   │   └── 70-proxy.conf
│   │   ├── servers
│   │   │   └── app.conf
│   │   ├── snippets
│   │   │   ├── cache-static.conf
│   │   │   ├── deny.conf
│   │   │   ├── php-fpm.conf
│   │   │   ├── ssl-certificates.conf
│   │   │   └── ssl.conf
│   │   ├── fastcgi.conf
│   │   ├── mime.types
│   │   └── nginx.conf
│   ├── Dockerfile
│   └── docker-entrypoint.sh
├── php
│   ├── configs
│   │   ├── conf.d
│   │   │   ├── opcache.ini
│   │   │   └── xdebug.ini
│   │   ├── fpm
│   │   │   ├── php-fpm.conf
│   │   │   └── www.conf
│   │   ├── php-local.ini
│   │   └── php-production.ini
│   ├── queue
│   │   ├── templates
│   │   │   ├── laravel-horizon.conf.tpl
│   │   │   └── laravel-worker.conf.tpl
│   │   └── supervisord.conf
│   ├── scheduler
│   │   └── artisan-schedule-run
│   ├── vscode
│   │   └── launch.json
│   ├── Dockerfile
│   ├── app.env.example
│   ├── docker-entrypoint.sh
│   ├── queue.env.example
│   └── scheduler.env.example
├── redis
│   └── redis.conf
├── .dockerignore
├── .editorconfig
├── .env.example
├── .gitignore
├── Makefile
├── README.md
├── docker-compose.override.yml
└── docker-compose.yml

What's Inside/Softwares Included:

Getting Started

Organization

  • docker folder must match current repository folder.
    • The folder name is configurable via the LOCAL_DOCKER_PATH variable of the .env environment file.
  • src folder should contain Laravel application.
    • The folder name is configurable via the LOCAL_APP_PATH variable of the .env environment file.
.
├── docker
└── src

Clone the project

$ git clone https://github.com/AllysonSilva/laravel-docker-lite docker && cd docker
  • Copy the .env.example file in the root of the project to .env and customize.
  • Uncomment the pwd variable and fill it with result echo $PWD.
  • The LOCAL_DOCKER_PATH variable in the .env file must be the folder name of the docker project.
  • The LOCAL_APP_PATH variable that is in the .env file must be the folder name of the Laravel application project.

Customize Running in Development

docker-compose -f docker-compose.yml -f docker-compose.override.yml up app webserver database redis queue scheduler

Build Images

To build the images it is necessary to configure the .env file with the information that will be used when the docker-compose up command is executed.

make config-docker-env \
    local_docker_path=./docker \
    local_app_path=./src \
    app_domain=domain.xyz \
    remote_src=/var/www/domain.xyz \
    app_image_name=app:1.0 \
    webserver_image_name=webserver:1.0
  • app_domain must match the domain that will be used in the application. Used exclusively in the webserver container in server_name Nginx settings.

  • remote_src must match the same path in PHP (app) and Nginx (webserver) containers. Because the webserver container sends the index.php file path to PHP-FPM, so if the paths are different in both containers, a project execution error will occur.

Laravel/APP PHP-FPM

  • The construction/configuration of this image is used for applications in Laravel.
  • Used multi-stage builds in your Dockerfile.
    • In the first stage use the image of Composer to manage the system dependencies (To speed up the download process hirak/prestissimo is used).
    • In the second stage use the Node.js image to build the dependencies of the Front-end using the yarn manager.
    • In the third and final stage, the results of the previous stages are used to copy the necessary files to the project image.

How to use

  • $APP_ENV: Set the environment where the Laravel application will be configured. This variable can be defined at the moment of image build through arguments(--build-arg APP_ENV=production||local), or if the image is already created, then it can be replaced by the parameter --env "APP_ENV=production||local" when running the container.
  • WORKDIR corresponds to the variable $REMOTE_SRC.
  • php.ini: Configured at the time of image build and is set according to the value passed to $APP_ENV. If the value of $APP_ENV is local then php.ini will match the files php-local.ini, if the value of $APP_ENV is production then the contents of php.ini will correspond to the file php-production.ini.
    • Can be overridden by volume pointing to the php.ini file path: /usr/local/etc/php/php.ini.
  • php-fpm.conf: GLOBAL PHP-FPM configuration found /usr/local/etc/php-fpm.conf.
  • www.conf: Specific configuration for pool [www] found /usr/local/etc/php-fpm.d/www.conf.

Configure/Build

Use the following command to build the image:

make build-app \
    app_env=production||local \
    remote_src=/var/www/domain.xyz \
    local_app_path=./src \
    local_docker_path=./docker \
    app_image_name=app:1.0

If you want to customize the image construction according to your arguments, use the docker build command directly:

docker build -t app:1.0 -f ./php/Dockerfile \
    --build-arg USER_NAME=app \
    --build-arg USER_UID=$UID \
    --build-arg USER_GID=$(id -g) \
    --build-arg APP_ENV=production||local \
    --build-arg REMOTE_SRC=/var/www/domain.xyz \
    --build-arg LOCAL_APP_PATH=./app \
    --build-arg LOCAL_DOCKER_PATH=./docker \
./../

Nginx Webserver

Image will be used as REVERSE PROXY.

Use the following command to build the image:

make build-webserver \
    app_domain=domain.xyz \
    remote_src=/var/www/domain.xyz \
    webserver_image_name=webserver:1.0
  • app_domain is used for setting server_name in app.conf file.

  • remote_src must have the same value used in the make build-app command. So there is no conflict in the communication of the services of the reverse proxy (NGINX) with the service CGI (PHP-FPM).

  • Use the Let's Encrypt to generate SSL certificates and perform the NGINX SSL configuration to use the HTTPS protocol.

    • Folder nginx/certs/ should contain the files created by Let's Encrypt. It should contain the files: cert.pem, chain.pem, dhparam4096.pem, fullchain.pem, privkey.pem.

Run the application

Copy the files from the php folder to the docker root folder(./docker/php/app.env.example move to ./docker/app.env): app.env.example, queue.env.example, scheduler.env.example, and set to the values that will be used in the environment. Remove the suffix .env.example, leaving only .env.

APP_KEY: If the application key is not set, your user sessions and other encrypted data will not be secure!

There are three ways to execute the application container:

PHP-FPM(default)

Runs the container with the PHP-FPM processes running.

Set the CONTAINER_ROLE environment variable when running the PHP container so that its value is app.

exec /usr/local/sbin/php-fpm -y /usr/local/etc/php-fpm.conf --nodaemonize --force-stderr

Queue

Container/service responsible for managing Queue in the application.

Set the CONTAINER_ROLE environment variable when running the PHP container so that its value is queue.

Container with PID 1 executed by supervisor to manage processes. Can have two configurations:

  • Many processes running in the Laravel artisan queue:work for queue management.
  • Used for debugging and development, the Horizon is a robust and simplistic queue management panel. A single process in a supervisor configuration by running the artisan horizon command.
exec /usr/bin/supervisord --nodaemon --configuration /etc/supervisor/supervisord.conf

Mandatory environment variables

  • LARAVEL_QUEUE_MANAGER: This environment variable defines the container context, and can have the following values:
    • worker: Configure the supervisor to run many processes in the Laravel command artisan queue:work.
    • horizon: Configure the supervisor to run a single Horizon process artisan horizon.

Scheduler

Container/service responsible for managing Scheduler in the application.

Set the CONTAINER_ROLE environment variable when running the PHP container so that its value is scheduler.

  • Container with PID 1 executed by cron.
  • Environment variables APP_KEY and APP_ENV are required when executing the container.
  • Environment variables available for PHP processes thanks to the printenv > /etc/environment script in container entrypoint.
  • Container run as root as a cron service request.

Running a single scheduling command

* * * * * {{USER}} /usr/local/bin/php {{REMOTE_SRC}}artisan schedule:run --no-ansi >> /usr/local/var/log/php/cron-laravel-scheduler.log 2>&1
exec /usr/sbin/crond -l 2 -f -L /var/log/cron.log

docker-compose up

Some points to consider:

Only port 80 and 443 are tight to the internet for security reasons.

Change the passwords present in the files: mysql.env, redis.conf and the docker-compose.yml variables which are: RABBITMQ_USERNAME, RABBITMQ_PASSWORD, MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD.

This project use the following ports:

Server Port
Nginx 80
Nginx 443

Set the WEBSERVER_PORT_HTTP environment variable for HTTP connections and WEBSERVER_PORT_HTTPS for HTTPS connections.

Helpers commands

To access the MySQL via Terminal/Console:

mysql -h 127.0.0.1 -P 30062 -uapp -p'ExBkhs^NGuA6r_Fu' \
    --ssl-ca=mysql/ssl/ca.pem \
    --ssl-cert=mysql/ssl/client-cert.pem \
    --ssl-key=mysql/ssl/client-key.pem

To access the Redis container database:

docker exec -it redis redis-cli -n 0 -p 6379 -a '.7HVhf(Yh+9CF-58' --no-auth-warning

To access the MongoDB via Terminal/Console:

mongo --ssl \
      --sslCAFile ./mongodb/ssl/ca.pem --sslPEMKeyFile ./mongodb/ssl/client.pem \
      --host 127.0.0.1 --port 29019 -u 'root' -p 'jyA7LF_7dX7.pmH' --authenticationDatabase admin

Install PHP modules

docker exec -it app /bin/bash

# After
$ /usr/local/bin/docker-php-ext-configure xdebug
$ /usr/local/bin/docker-php-ext-install xdebug

Installing package with composer

docker run --rm -v $(pwd):/app composer require laravel/horizon

Updating PHP dependencies with composer

docker run --rm -v $(pwd):/app composer update

Testing PHP application with PHPUnit

docker-compose exec -T app ./vendor/bin/phpunit --colors=always --configuration ./app

Fixing standard code with PSR2

docker-compose exec -T app ./vendor/bin/phpcbf -v --standard=PSR2 ./app

Analyzing source code with PHP Mess Detector

docker-compose exec -T app ./vendor/bin/phpmd ./app text cleancode,codesize,controversial,design,naming,unusedcode

Contributing

If you find an issue, or have a special wish not yet fulfilled, please open an issue on GitHub providing as many details as you can (the more you are specific about your problem, the easier it is for us to fix it).

Pull requests are welcome, too 😁! Also, it would be nice if you could stick to the best practices for writing Dockerfiles.

License

MIT License