How To Deploy a PHP Application Using Docker-compose

Docker is an software program which is used for operating system level virtualization. It is also called containerization. PHP applications are mostly composed by a web server, language interpreter and a DBMS (Database) In this tutorial we will be using a complete PHP stack using docker. We will orchestrate containers for Nginx (the web-server), MySQL ( database system) and PHP language itself.

For this tutorial we will create a simple application that takes a list of cities from the database and displays it on the web page. This will help in the understanding and demonstrating the complete working.

Prerequisites

  • Docker CE Installed
  • Minimal working knowledge of docker
  • Knowledge about containerization

Step 1: Configuring the work environment

A basic docker based application is composed of multiple containers. It is difficult to manage all these manually. To solve this problem we use docker-compose, it helps manage multiple containers using a configuration file.

Use the following commands to install docker-compose

$ curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

We will create a folder to save all the files here. Then cd into it and it will be used as our working directory.

$ mkdir ~/docker
$ cd ~/docker

Create more folder using this command

$ mkdir php nginx app

In php folder we will have our custom php image, ngnix will have custom ngix image and the app folder will have source code and configuration files.

Step 2: Configure the PHP container

We will use php-fpm to connect to Nginx webserver. Inside the php folder create a file named Dockerfile and put the following contents into it.

FROM php:7.1-fpm-alpine3.4
RUN apk update--no-cache 
    && apk add--no-cache $PHPIZE_DEPS 
    && apk add--no-cache mysql-dev 
    && docker-php-ext-install pdo pdo_mysql

We are using the Alpine version here. Alpine is a small distribution which targets the containers.

$ docker build -t name-php php/

As mentioned above about the docker-compose yml configuration file, lets create the file

$ touch app/docker-compose.yml

Put the following configurations into the file

version: '2'
services:
  php:
    image: vultr-php
    volumes:
      -./:/app
    working_dir: /app

Version is the version of docker-compose.yml used here. Note that every service has a specific key inside the services block. The name specified here will be used to reference this specific container later. We also define a volume mapping.

volumes:
  - ./:/app

This tells docker-compose to map the current directory (./) to the /app directory inside the container. The last line will make sure that the commands will be executed from this folder i.e ./app

Orchestrate the containers using following commands

$ cd ~/docker/app
$ docker-compose up -d

To check that the php container executed. Use the following command:

$ docker ps

Step 3: Executing Commands inside the container

Use the following docker-compose command, make sure you are still inside the app folder.

$ docker-compose exec [service] [command]

The service placeholder refers to service key.

Run the following command in the docker-compose to check php version.

$ docker-compose exec php php -v

You will see the following message:

PHP 7.1.14 (cli) (built: Feb  7 2018 00:40:45) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

Step 4: Configuring the Nginx container

Like before we will create a custom image for Nginx. Use the following commands to do it.

$ cd ~/docker
$ touch nginx/Dockerfile

Put the following configurations into the Dockerfile

FROM nginx:1.13.8-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf

On this Docker file we simply copy a configuration file into our application setup.

$ touch nginx/default.conf

Now add the following configurations to the file

server {
    listen80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /app;
    index index.php;

    #server_name server_domain_or_IP;

    location / {
        try_files$uri$uri/ /index.php?$query_string;
    }

    location~ .php$ {
        try_files$uri /index.php =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Internally docker-compose creates a network and assigns the service name as the host name to each of the services defined. Build the Nginx image.

$ docker build -t name-nginx nginx/

Now docker-compose.yml file with following configurations:

version: '2'
services:
  php:
    image: vultr-php
    volumes:
      -./:/app
    working_dir: /app
  web:
    image: vultr-nginx
    volumes:
      -./:/app
    depends_on:
      -php
    ports:
      -80:80

Create a file called index.php using the following command

$ <?php phpinfo();

Before running these commands below make sure that port 80 is up and working

$ cd ~/docker/app
$ docker-compose up -d

Step 5: Configuration the MySQL container

Update the file ~/docker/app/docker-compose.yml using the following configurations

version: '2'
services:
  php:
    image: name-php
    volumes:
      -./:/app
    working_dir: /app
  web:
    image: name-nginx
    volumes:
      -./:/app
    depends_on:
      -php
    ports:
      -80:80
  mysql:
    image: mysql:5.7.21
    volumes:
      -./:/app
      - dbdata:/var/lib/mysql
    environment:
      -MYSQL_DATABASE=world
      -MYSQL_ROOT_PASSWORD=root
    working_dir: /app
volumes:
  dbdata:

Now lets download the sample MySQL database using the following command inside the app folder

$ curl -L http://downloads.mysql.com/docs/world.sql.gz -o world.sql.gz
$ gunzip world.sql.gz

Now orchestrate the container using the following command

$ docker-compose up -d

Now populate the world database

$ docker-compose exec -T mysql mysql -uroot -proot world < world.sql

Now let’s check that the data has successfully populated in the database. For that access the MySQL prompt in the container. Use the following command.

$ docker-compose exec mysql mysql -uroot -proot world

Inside the prompt, run the following query

select * from city limit10;

A list of data inside the database, in this case cities will be shown. Quit the prompt using following command.

mysql> exit

Step 6: Build PHP application

The containers are running, now lets create the PHP application. Go to the app/index.php file, and paste the following code in it.

<?php

$pdo = new PDO('mysql:host=mysql;dbname=world;charset=utf8', 'root', 'root');

$stmt = $pdo->prepare("
    select city.Name, city.District, country.Name as Country, city.Population
    from city
    left join country on city.CountryCode = country.Code
    order by Population desc
    limit 10
");
$stmt->execute();
$cities = $stmt->fetchAll(PDO::FETCH_ASSOC);

?>

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Vultr Rocks!</title>
</head>
<body>
    <h2>Most Populous Cities In The World</h2>
    <table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Country</th>
            <th>District</th>
            <th>Population</th>
        </tr>
    </thead>
    <tbody>
        <?phpforeach($cities as $city): ?>
            <tr>
                <td><?=$city['Name']?></td>
                <td><?=$city['Country']?></td>
                <td><?=$city['District']?></td>
                <td><?=number_format($city['Population'], 0)?></td>
            </tr>
        <?phpendforeach?>
    </tbody>
    </table>
</body>
</html>

Now if you access the IP address in your browser, you will see the list of cities that are most popular. Congratulations you have successfully deployed a PHP application using docker.

Check out these top 3 Cloud hosting services:

Was this article helpful?