In this article, we are going to use Docker Compose to run our Laravel application using Nginx, PHP, and MySQL. In the end, we will get three separate service containers.
- An
app
service container - A
db
service container to run MySQL - An
nginx
service container
Project Directory Structure
First, create a directory with the name laravelapp
that contains the Laravel project and docker related settings. We will keep the docker-compose.yml
file in the root of the current docker project.
- laravelapp
- .docker
- db
- src
- docker-compose.yml
.docker
This directory contains all the containers related configuration such as PHP, Nginx, MySQL and Docerfiledb
directory mapping with the MySQL containersrc
directory contains the Laravel projectdocker-compose.ym
l file contains all the containers settings
Now download the Laravel from the Github repository and extract the zip file under laravelapp/src
directory.
The next step is to create a Dockerfile
under laravelapp/.docker/nginx
directory. We required this file to create our custom images that include the PHP 7.4, Composer and System User.
Setup Dockerfile
Our Dockerfile starts with php:7.4-fpm
official image from docker hub and takes user and uid from docker-compose file to create a system user. Next, we will install all the Laravel dependencies and PHP extensions that we require to run the Laravel application.
Next, we will install the composer that we require to install the Laravel packages. Later we will create a system user and assign it under www-data
and the root
group.
The final step for the Dockerfile is to set the working directory and assign the system user.
Copy the following content and paste it to your Dockerfile.
FROM php:7.4-fpm
# Get argument defined in docker-compose file
ARG user
ARG uid
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
&& docker-php-ext-install pdo_mysql \
&& docker-php-ext-install mbstring \
&& docker-php-ext-install exif \
&& docker-php-ext-install pcntl \
&& docker-php-ext-install bcmath \
&& docker-php-ext-install gd \
&& docker-php-source delete
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Get latest Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
chown -R $user:$user /home/$user
# Set working directory
WORKDIR /var/www
USER $user
Create Multiple Containers with Docker Compose
The Docker Compose helps us to build a fully customizable environment with multiple containers. We will run three containers for the Laravel application i.e. app, nginx and db containers. The app
container will start with the help of the Dockerfile that we recently created. And we will use the official images for nginx
and db
containers
Let’s start by creating a docker-compose.yml
file at the root of your project directory i.e. laravelapp
.
We start the docker-compose file with version and each container will be defined under the services prefix.
version: "3.7"
services:
The app container
Let’s start with the app container.
version: "3.7"
services:
app:
build:
args:
user: dean
uid: 1001
context: ./.docker
dockerfile: Dockerfile
image: laravelapp
container_name: laravelapp-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./src:/var/www
- ./.docker/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
networks:
- laravelapp
build:
section holds argumentsuser
anduid
that we have accessed in our Dockerfile. Thecontext
is the path of our Dockerfile.image:
holds the name of the application, in our case laravelapp is the name of this image.container_name:
holds the name of the container.restart:
The container always restarts, until it stopped.working_dir:
Sets the default working directory for this container.volumes:
It is used to share the local files with a particular container. As you can see we have set the volume./src:/var/www
, where./src
directory holds the Laravel application that will be shared to/var/www
container’s directory.networks:
Sets the service to use a network i.e.laravelapp
.
The db container
version: "3.7"
services:
....
....
....
db:
image: mysql:5.7
container_name: laravelapp-db
restart: unless-stopped
environment:
MYSQL_DATABASE: 'lara_db'
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_PASSWORD: 'lara_password'
MYSQL_USER: 'lara_user'
volumes:
- ./db/mysql:/var/lib/mysql
- ./.docker/mysql/my.cnf:/etc/mysql/my.cnf
networks:
- laravelapp
image:
Define the name of the docker image and the version. You can find the MySQL image from the docker hub.container_name:
holds the name of the container.restart:
The container always restarts, until it stopped.environment:
Define the database environment that you can find from the official MySQL image.volumes:
andnetworks:
are the same as the app container.
The Nginx Container
version: "3.7"
services:
....
....
....
nginx:
image: nginx:1.17-alpine
container_name: laravelapp-nginx
restart: unless-stopped
ports:
- 8008:80
volumes:
- ./src:/var/www
- ./.docker/nginx:/etc/nginx/conf.d
networks:
- laravelapp
image:
Define the name of the docker image and the version. You can find the Official Nginx image from the docker hub.container_name:
holds the name of the container.restart:
The container always restarts, until it stopped.ports:
Sets the ports where 8008 to the web server running on 80 inside the nginx container.volumes:
andnetworks:
are the same as the app container.
Nginx Configuration File for Docker
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
The following configuration file let Nginx server to listen on port 80 and use the index.php
file. The document root for our Laravel application is public
directory which is located under /var/www
directory.
Make sure to use the container name i.e.
app
instead oflocalhost
forfastcgi_pass
parameter.
PHP Configuration File for Docker
Create uploads.ini
file under .docker/php
directory and set the configuration as required.
file_uploads = On
memory_limit = 64M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 900
MySQL Configurtion File for Docker
Create my.cnf
file under .docker/mysql
directory and add the required configuration.
[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log
Final Docker Compose File
version: "3.7"
services:
app:
build:
args:
user: dean
uid: 1001
context: ./.docker
dockerfile: Dockerfile
image: laravelapp
container_name: laravelapp-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./src:/var/www
- ./.docker/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
networks:
- laravelapp
db:
image: mysql:5.7
container_name: laravelapp-db
restart: unless-stopped
environment:
MYSQL_DATABASE: 'lara_db'
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_PASSWORD: 'lara_password'
MYSQL_USER: 'lara_user'
volumes:
- ./db/mysql:/var/lib/mysql
- ./.docker/mysql/my.cnf:/etc/mysql/my.cnf
networks:
- laravelapp
nginx:
image: nginx:1.17-alpine
container_name: laravelapp-nginx
restart: unless-stopped
ports:
- 8008:80
volumes:
- ./src:/var/www
- ./.docker/nginx:/etc/nginx/conf.d
networks:
- laravelapp
Now run the following command to build your image.
docker-compose build
The command might take some time depends on the internet and the local image and will give you the following output.
Step 1/10 : FROM php:7.4-fpm
---> 14098ddb1a4e
Step 2/10 : ARG user
---> Using cache
---> 33aea6c3ff59
Step 3/10 : ARG uid
---> Using cache
---> 03fa25740298
Step 4/10 : RUN apt-get update && apt-get install -y git curl libpng-dev libonig-dev libxml2-dev zip unzip && docker-php-ext-install pdo_mysql && docker-php-ext-install mbstring && docker-php-ext-install exif && docker-php-ext-install pcntl && docker-php-ext-install bcmath && docker-php-ext-install gd && docker-php-source delete
---> Using cache
---> a15df90680bd
Step 5/10 : RUN apt-get clean && rm -rf /var/lib/apt/lists/*
---> Using cache
---> b79d72fdfb85
Step 6/10 : RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
---> Using cache
---> 369da557c7d4
Step 7/10 : RUN useradd -G www-data,root -u $uid -d /home/$user $user
---> Using cache
---> 7306589c9f2e
Step 8/10 : RUN mkdir -p /home/$user/.composer && chown -R $user:$user /home/$user
---> Using cache
---> bc6d6f5a255f
Step 9/10 : WORKDIR /var/www
---> Using cache
---> 1f9f25b46e60
Step 10/10 : USER $user
---> Using cache
---> cbd29387097c
Successfully built cbd29387097c
Successfully tagged laravelapp:latest
Now run your containers with the following command.
docker-compose up -d
It will give you the following output.
Creating laravelapp-nginx ... done
Creating laravelapp-db ... done
Creating laravelapp-app ... done
Now you can check the running containers through the following command.
docker ps
And you will see the following output.
CONTAINER ID IMAGE STATUS PORTS
67527d83832a nginx:1.17-alpine Up 7 minutes 0.0.0.0:8008->80/tcp
f29812e8f5be laravelapp Up 7 minutes 9000/tcp
fa218dd63b3d mysql:5.7 Up 7 minutes 3306/tcp, 33060/tcp
Working With Laravel in Docker Container
Now we have multiple options for working with Laravel in Docker container.
Get Access Through Container ID
The first option to access the Laravel development environment by accessing the container with Container ID.
Run the following command to get the container id.
docker ps
And you will get the following output
CONTAINER ID NAMES IMAGE STATUS PORTS
67527d83832a laravelapp-nginx nginx:1.17-alpine Up 19 hours 0.0.0.0:8008->80/tcp
f29812e8f5be laravelapp-app laravelapp Up 19 hours 9000/tcp
fa218dd63b3d laravelapp-db mysql:5.7 Up 19 hours 3306/tcp, 33060/tcp
Our Laravel app is running on f29812e8f5be
container id. To access this container, we need to run the following command.
docker exec -it f29812e8f5be bash
The above command provides you the access to the Laravel working directory where you can run the composer or artisan commands.
dean@f29812e8f5be:/var/www$ php artisan -V
The above command will output you the current version of Laravel.
Laravel Framework 8.20.1
I already installed Laravel by running the
composer install
command.
Access Through Container Name
The second option to access the Laravel Development environment through Container Name.
docker-compose exec app php artisan -V
Please note that we have used the docker-compose
instead of the docker
. Where the app is suffix from the Laravel app container.
Name Command State Ports
-------------------------------------------------------------------------------
laravelapp-app docker-php-entrypoint php-fpm Up 9000/tcp
laravelapp-db docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
laravelapp-nginx nginx -g daemon off; Up 0.0.0.0:8008->80/tcp
We hope this article will help you to learn the how to containerize laravel, nginx and mysql with docker compose. If you like it then please follow us on Facebook and Twitter.