Reading Time: 6 mins. 

Overview

Docker Virtualization, known for its simple and convenient way of deploying applications is the best-to-go option for every developer and organisation. With its container-based technology, and built-in features such as docker compose, docker images, docker volumes, docker hub and so on, it has further streamlined the development process as you can define the infrastructure along with volumes, networks and applications in a single file. Also, it offers the flexibility to run multiple applications on the provided host or directly executing the container within the host environment per se. 

Here, in this article, a basic working environment will be created by setting Nginx as a web server and MySQL as the database, all within separate Docker containers. The entire stack including the config. files such as PHP, Nginx and MySQL will be defined in the docker-compose file. 

Prerequisites

Step 1: Creating the project folders

You need to create the following files and directories to get started with the demo project. 

Folder Overview:

file-hierarchy-docker

Step 2: Creating the required config. files

i) Nginx site configuration

Get started with the nginx folder using the command below

cd Docker-demo/nginx

Next, open the file, site.conf using the below command.

sudo nano Docker-demo/nginx/site.conf
server {
    server_name docker-demo.com;
    root /var/www/html;
    index index.php index.html index.htm;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    # PHP-FPM Configuration Nginx
    location ~ \.php$ {
        try_files $uri = 404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param REQUEST_URI $request_uri;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Note: It is the fastcgi_pass php:9000; that guides Nginx on how to connect with PHP containers. 

ii) Creating index.php file:

To get started with the webcontent folder, type:

cd Docker-demo/webcontent

Next create a file called index.php

sudo touch index.php

To open the created index.php file, type:

sudo nano index.php
<!doctype html>
<style>
  body { text-align: center; padding: 150px;background-color:blue }
  h1 { text-align:center;font-size: 25px;color:white  }
  body { font: 16px Helvetica, sans-serif; color: #333; }
  article { display: block; text-align: left; width: 650px; margin: 0 auto; }
  a { color: #DC8100; text-decoration: none; }
  a:hover { color: #333; text-decoration: none; }
</style>
<article>
    <h1>Welcome to Docker-demo project</h1>
    <h1>We have installed Nginx , Php-fpm and Mysql</h1>
</article>

iii) Creating php.ini file:

Since the php.ini file copied to the php container is used here, we can straightway make changes in the php.ini file. Post then just restart the container for the changes to get applied.

In case, if you make changes within the php code of the index.php file, you need not to restart the container. All the changes will immediately get applied once the browser page reloads. Here, “depends_on” – restricts the container from running before other container (on which it depends on)

Step 3: Creating docker-compose yaml file

In the docker yaml file, we are going to integrate the following services,

  • Nginx 
  • PHP 
  • MySQL 

Next, open the yaml file using the below command.

sudo nano docker-compose.yml
version: '3'
services:
 # Nginx server configuration   
  web:
    image: nginx:1.17
    container_name: webserver
    depends_on:
      - docker-mysql
      - php
    links:
      - docker-mysql
      - php
    volumes:
      - ./webcontent:/var/www/html
      - ./nginx:/etc/nginx/conf.d/
    ports:
      - "8080:80"
 # Php-fpm configuration
  php:
    image: php:7.2-fpm
    volumes:
      - ./webcontent:/var/www/html
      - ./php:/usr/local/etc/php/php.ini
 # Mysql configuration
  docker-mysql:
    image: mysql:5.7
    container_name: docker-mysql-demo
    restart: always
    environment:
        - MYSQL_DATABASE=docker_demo
        - MYSQL_ROOT_PASSWORD=root123
        - MYSQL_USER=root
        - MYSQL_PASSWORD=root123
    ports:
        - "3306:3306"
    volumes:
        - /dbdata:/var/lib/mysql

Note: Make sure that you stick with the syntax to avoid errors as the docker yaml file is case sensitive.

Step 4: Proceeding with data persistence

Docker comes with a number of flexible features that ensure that every other required task can be done within the Docker software itself. One such powerful offering is Docker Volumes where you can persist (save data) the database, config files, applications, etc. In simple words, Docker Volumes helps in back up and persistence beyond the container’s lifecycle. 

Now to get started with the MySQL database persistence using Docker Volume, go to docker-compose file wherein under the db service define a volume called dbdata. 

Next add dbdata in the docker-compose yaml file as shown below:

volumes:
  dbdata:

Note: Include these lines at the end of the docker yaml file. Once you have included it, it will look like the following code.

 # Mysql configuration
  docker-mysql:
    image: mysql:5.7
    container_name: docker-mysql-demo
    restart: always
    environment:
        - MYSQL_DATABASE=docker_demo
        - MYSQL_ROOT_PASSWORD=root123
        - MYSQL_USER=root
        - MYSQL_PASSWORD=root123
    ports:
        - "3306:3306"
    volumes:
        - /dbdata:/var/lib/mysql
volumes:
  Dbdata:

Step 5: Running the docker container

First, we will run the docker yaml file using docker-compose followed by checking the docker container status, port and shell access. 

Let’s run the yaml file, and it can be achieved via two commands.

i) Docker-compose up

We can run the docker yaml file using the Docker-compose up command but it will end up displaying increased logs or verbose. 

ii) Docker-compose up -d

This Docker-compose up -d command helps you to quickly run the docker-compose yaml file without displaying any verbose. 

Here, we are proceeding with the latter command. 

Docker-compose up -d

Note: If you already have the images, you can directly use it in Docker. If not, download the image using the pull command from Docker Hub. 

demo@user:~/home/test/Docker-demo$ docker-compose up -d

Output

Pulling php (php:7.2-fpm)...
7.2-fpm: Pulling from library/php
6ec8c9369e08: Pull complete
081a822af595: Pull complete
bb5bea655fca: Pull complete
1e5d9e6a44c7: Pull complete
b80bd0206e9a: Pull complete
bfb5a20e684a: Pull complete
23e1412dbc42: Pull complete
e4ef974d5fe7: Pull complete
9be689db73a4: Pull complete
79c3308fcac3: Pull complete
90214107f387: Pull complete
Digest: sha256:d79ee8b9ac56c5fe206552b37ba42fc1ee38b59213817d15fbb3444e93778605
Status: Downloaded newer image for php:7.2-fpm
Pulling web (nginx:1.17)...
1.17: Pulling from library/nginx
afb6ec6fdc1c: Already exists
b90c53a0b692: Pull complete
11fa52a0fdc0: Pull complete
Digest: sha256:6fff55753e3b34e36e24e37039ee9eae1fe38a6420d8ae16ef37c92d1eb26699
Creating docker-mysql-demo ... done
Creating test_php_1         ... done
Creating webserver       ... done

Post downloading the image from Docker Hub, the Docker containers will automatically be up and running. 

Note – If the image is already in local you will get a following output directly

demo@user:~/home/user/Docker-demo$ docker-compose up -d

Output

Starting test_php_1 ... done
Starting docker-mysql-demo ... done
Starting webserver        ... done

To check the docker container status, type:

demo@user:~/home/user/Docker-demo$ docker ps -a

Output

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
db260bdd50db        nginx:1.17          "nginx -g 'daemon of…"   9 minutes ago       Up 9 minutes        0.0.0.0:8080->80/tcp                webserver
d779a91f0a70        mysql:5.7           "docker-entrypoint.s…"   9 minutes ago       Up 9 minutes        0.0.0.0:3306->3306/tcp, 33060/tcp   docker-mysql-demo
a934abeff223        php:7.2-fpm         "docker-php-entrypoi…"   9 minutes ago       Up 9 minutes        9000/tcp                            test_php_1

To check the docker image status, type:

Docker images -a

Output

REPOSITORY           TAG                IMAGE ID            CREATED           SIZE
php                 7.2-fpm             bf06dbdd13ab        7 days ago        398MB
mysql                  5.7                 9cfcce23593a        7 weeks ago     448MB
nginx                 1.17                9beeba249f3e        2 months ago    127MB

Step 6: Adding domain to etc hosts

Either you need to add a container ip address or localhost url in etc hosts. Here, we are going with the localhost url.

Open the etc file using the following command.

sudo nano /etc/hosts
127.0.0.1 docker-demo.com

Note: Include the same domain, docker-demo.com as you used in the nginx site configuration.

Step 7: Verification

To directly access the docker container shell, enter the below command.

Docker exec -it webserver bash

Hit the localhost domain which you have added in etc hosts. http://docker-demo.com

Conclusion

Just to emphazise, if you have noticed, it is the Docker that plays a vital role in simplifying the development process. Want to read more about Docker and its number of capabilities, read our blog post on A Brief Introduction to Docker and Its Terminologies Setting up a stack with Nginx as a web server and MySQL as the database with required PHP config. files is not an easy and one-step process. With Docker Compose which allows you to create multiple containers, you can define the infrastructure along with the required config. files within a single file using a single command.