Simple Approach using Docker with Laravel, Nginx, and MySQL Server.

Shahjalal
Oceanize Lab Geeks
10 min readJul 11, 2019

--

I take a very simplistic approach to using Docker, and I want to share with you how we can too — without a bunch of overwhelming cruft. We can build hand-crafted Docker setups without any third party tools that contain what we need and nothing more.

Docker has become a frequently used solution for deploying applications. How it simplifies running and deploying applications in ephemeral containers.

Docker Compose has most simplified the development process by allowing developers to define their infrastructure, including application services, networks, and volumes, in a single file at docker composer.

In this article, we will build a web application using the Laravel framework, Nginx as the web server and MySQL as the database server, all inside Docker containers.

We will define the entire stack configuration in a docker-compose file, along with configuration files for PHP, MySQL, and Nginx.

So Let’s start

1st Step:-Downloading and Installing Laravel with dependency

In 1st step, we will get the latest Laravel Project and install the dependencies for the project, including Composer, the application-level package manager for PHP.
We will install these dependencies with Docker to avoid having to install Composer globally.

1st we go to our working directory then clone the laravel project as laravel-docker`.
For example you can make directory in desktop or root directory or any here you want.

But my case I make directory in root .

git clone https://github.com/laravel/laravel.git laravel-docker

Move into the directory laravel-docker

cd laravel-docker

Next we install composer globally and our project using this command

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

In here we using the -v and - -rm flags with docker run to creates an ephemeral container that will be bind-mounted to our current directory before being removed. It’s will copy the contents of ~/laravel-docker directory to the container and also ensure that the vendor folder Composer creates inside the container is copied to our current or working directory.

2nd step:-Create Docker compose file

Building our applications with Docker Compose simplifies the process of setting up and versioning our infrastructure. To set up our Laravel application, we will write a docker-compose file that defines our web server, database, and application services which configuration initialise and write code docker composer.

Open our favourite terminal and run the command to create docker-compose.yml

sudo vim  ~/laravel-docker/docker-compose.yml

This command make new file `docker-composer.yml` in our working directory and save with exit.

In this Docker composer file we are initialling our Different service. In our application we use three service these are `app`, `webserver`,`database server`.This 3 service initialising with other configuration in `docker-composer.yml`.

In docker-compose file, define a volume called lbdata under the db service definition to persist the MySQL database:

#MySQL Servicedb:   volumes:
- lbdata:/var/lib/mysql
networks:
- app-network

The volume lbdata persists the contents of the /var/lib/mysql directory present inside the container. It allows to stop and restart the db service without losing data.

At the bottom of the file(docker-composer.yml), add the definition for the lbdata volume:

#Volumes   volumes:
lbdata:
driver: local

Now we are able to use the volume anywhere across the application.

Now add the db service mysql configuration in docker-composer.yml

#MySQL Servicedb:
volumes:
- lbdata:/var/lib/mysql
- ./mysql/my.cnf:/etc/mysql/my.cnf

Finally, add the following bind mounts to the app service for the application code and configuration files:

#PHP Serviceapp:
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network

Finally, Docker Composer file look like and copy and paste bellow code in `docker-compose.yml`

version: '1.1'
services:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
image: php_service
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network
#Nginx Service
webserver:
image: nginx:alpine
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "88:80"
- "443:443"
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
networks:
- app-network
#MySQL Service
db:
image: mysql:5.7.22
container_name: db
restart: unless-stopped
tty: true
ports:
- "1306:3306"
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: root
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- lbdata:/var/lib/mysql/
- ./mysql/my.cnf:/etc/mysql/my.cnf
networks:
- app-network
#Docker Networks
networks:
app-network:
driver: bridge
#Volumes
volumes:
lbdata:
driver: local

3rd step:-Creating Docker file

Docker allows us to specify the environment inside of individual containers with a Dockerfile. Dockerfile enables to create custom images that we can use to install software required by our application and configure settings based on our requirements.

Now we create Docker file in our working directory

Sudo vim ~/laravel-docker/Dockerfile

In Dockerfile we will set the base image and specify necessary command and instruction to build the Laravel application.

Copy the code and paste in Dockerfile

FROM php:7.2-fpm# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/
# Set working directory
WORKDIR /var/www
# Install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
mysql-client \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www
# Copy existing application directory contents
COPY . /var/www
# Copy existing application directory permissions
COPY --chown=www:www . /var/www
# Change current user to www
USER www
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]

Dockerfile creates an image on top of the php:7.2-fpm Docker image. It’s Debian-based image that has the PHP FastCGI implementation PHP-FPM installed.

It’s also installs the prerequisite packages for Laravel: mcrypt, pdo_mysql, mbstring, and imagick with composer. It’s not mandatory.If anyone wants can avoided this part in docker.

The RUN directive specifies the commands to update, install, and configure settings inside the existing container.

The WORKDIR instruction specifies the /var/www directory as the working directory for the application.

We have created the www user, who has read/write access to the /var/www directory

Finally, the EXPOSE command exposes a port in the container, 9000, for the php-fpm server.

CMD specifies the command that should run once the container is created. Here, CMD specifies "php-fpm", which will start the server.

4th step:-php Configuration

In this step we configuration in php infrastructure.

As purpose to create `local.ini` to over write the actual php.ini for basic changes.

So Create the php directory:

mkdir ~/laravel-docker/php

Then, open the local.ini file and paste the code

upload_max_filesize=40M
post_max_size=40M
max_execution_time = 180
memory_limit = 3000M

In many cases, the values you enter should get larger as you go down the list from lines one to three. The upload_max_filesize should be the smallest while memory_limit should be the largest. The median should be post_max_size.That why we change the php configuration.

5th step:-nginx Configuring

With the PHP service configured, we can modify the Nginx service to use PHP-FPM as the FastCGI server to serve dynamic content. The FastCGI server is based on a binary protocol for interfacing interactive programs with a web server.

[What is FASTCGI?
FastCGI is a binary protocol for interfacing interactive programs with a web server. It is a variation on the earlier Common Gateway Interface (CGI). FastCGI’s main aim is to reduce the overhead related to interfacing between web server and CGI programs, allowing a server to handle more web page requests per unit of time.
For more information about FastCGI please visit https://en.wikipedia.org/wiki/FastCGI

]

To configure nginx, We will create an app.conf file with the service configuration in the

So create the nginx/conf.d/ directory bellow the command

mkdir -p ~/laravel-app/nginx/conf.d

Then Create `app.conf` configuration file bellow the command

sudo vim ~/laravel-app/nginx/conf.d/app.conf

Now we add the following code to the file to specify our Nginx configuration:

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;}}

reference: http://nginx.org/en/docs/beginners_guide.html

6th Step:-MySql Configuration

Configure MySQL, We will make the my.cnf file in the mysql folder. This is the file that we bind-mounted to /etc/mysql/my.cnf inside the container. This bind mount allows us to override the my.cnf settings as and when required.

For Example, how it’s works, we’ll add settings to the my.cnf file that we enable the general query log and specify the log file.

my.cnfgeneral_log = 1
general_log_file = /var/lib/mysql/general.log

7th step: — Containers Runs with Modifying Environment Settings

In before we have configured all service in docker-compose file and created all related service. So now, we will run the Container before run the container we will make copy file .env and make changes

cp .env.example .env

So Now we run Docker Container bellow the command

docker-compose up –d

when we run the command if the command is first time run that’s time its downloaded all images form docker hub into our local machine. We need to wait sometimes. The -d flag demonises the process, running containers in background.

If we want see our running docker Container run the command

docker ps

Output:

After that we can modify our env file on the app container to include specific details about our setup

So, Open the file using docker-compose exec, which allows to run specific commands in containers. To modify the env using the command

docker-compose exec app sudo vim .env

And modify the necessary information. In my case I changes bellow blocks

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=roor
DB_PASSWORD=root

In your case you change only DB_DATABASE, DB_USERNAME, DB_PASSWORD.

Next, set the application key for the Laravel application with the

php artisan key:generate

command. This command will generate a key and copy it to.env file, ensuring that user sessions and encrypted data remain secure.

Run the command output:

We have the environment settings required to run our application. To cache these settings into a file, which will boost your application’s load speed, run:

docker-compose exec app php artisan config:cache

Configuration settings will be loaded into /var/www/bootstrap/cache/config.php on the container.

So, Finally visit http://localhost:88/ in the. We will see the page welcome page in laravel. But my case I have some modified laravel welcome page That we can see different page

we run laravel application using Docker. Now we move to mysql database connection and try to implement default auth using migration.

Let’s start.

Step 8 :— MySQL Container Access by command

To accesses MySql, execute an interactive bash shell on the db container with docker-compose exec command

docker-compose exec db bash

Output

We successfully login our MySql Conatiner
In login terminal run the command to login mysql database accesses.
mysql -u root –p

In this part asked authorization, the output look like

Just enter the mysql root password. By the way default password is `root`.So we type root after that we can see screen like this.

Output

Run the show databases command to check for existing databases:

Output

Also we can run other command use <database_name> the command changes database and show tables it’s show list table in your database.

9th step:- Laravel Data Migrating and make auth

First, we need to test database connection to mysql by running the laravel. To check database connection we run the command

docker-compose exec app php artisan migrate

The command will migrated the default laravel table and the output will be

Output

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table

After that we will make default auth in laravel. To make default auth we run the command

docker-compose exec app php artisan make:auth

Output

Finally we visit the http://localhost:88/ in browser we can see the home page like

Some Important command

[N:B Some important command of laravel in specific container. When we change in .env or other configuration that time some operation not working properly. If not working that we can run some laravel command

## Project Build Informatin-docker-compose up --build[new build see the loger in console]
-docker-compose up -d [Only run the docker server like mysql, nginx and other but service run background]
-docker ps [check all running container]
-docker images [check all images in you local docker server]
## Database magration using docker*docker-compose exec [name of container] <your laravel command>*
-docker-compose exec app php artisan cache:clear
-docker-compose exec app php artisan view:clear
-docker-compose exec app php artisan route:clear
-docker-compose exec app php artisan clear-compiled
-docker-compose exec app php artisan config:cache]

--

--