In this post I will show how you can use the docker-compose tool to containerize a PHP web app that uses the MySQL database. Both the web app and the database will be containerized in two separate containers - one for PHP with Apache and the other with MySQL.
Source Code: https://github.com/medhatelmasry/docker-php-mysql
Companion Video: https://youtu.be/g9qU5o0Dlps
The only pre-requisite is that you have Docker installed on your computer. Download Docker Desktop from https://www.docker.com/get-started.
First, let us create a folder named php-mysql-app for our solution under your working folder:mkdir php-mysql-appcd php-mysql-app
Create another directory under php-mysql-app named src to hold our PHP web app:
mkdir src
Inside the php-mysql-app/src create a text file named index.php and add to it the following PHP source code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Show databases in MySQL server</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Show databases in MySQL server</h1>
<?php
getenv('MYSQL_DBHOST') ? $db_host=getenv('MYSQL_DBHOST') : $db_host="localhost";
getenv('MYSQL_DBPORT') ? $db_port=getenv('MYSQL_DBPORT') : $db_port="3306";
getenv('MYSQL_DBUSER') ? $db_user=getenv('MYSQL_DBUSER') : $db_user="root";
getenv('MYSQL_DBPASS') ? $db_pass=getenv('MYSQL_DBPASS') : $db_pass="";
getenv('MYSQL_DBNAME') ? $db_name=getenv('MYSQL_DBNAME') : $db_name="";
if (strlen( $db_name ) === 0)
$conn = new mysqli("$db_host:$db_port", $db_user, $db_pass);
else
$conn = new mysqli("$db_host:$db_port", $db_user, $db_pass, $db_name);
// Check connection
if ($conn->connect_error)
die("Connection failed: " . $conn->connect_error);
if (!($result=mysqli_query($conn,'SHOW DATABASES')))
printf("Error: %s\n", mysqli_error($conn));
echo "<h3>Databases</h3>";
while($row = mysqli_fetch_row( $result ))
echo $row[0]."<br />";
$result -> free_result();
$conn->close();
?>
</div>
</body>
</html>
The above code first reads the following environment variables in order to construct an appropriate connection string to connect to a MySQL database:
MYSQL_DBHOST | The MySQL server name |
MYSQL_DBPORT | The port number that the MySQL server listens on |
MYSQL_DBUSER | The username that will be used to connect to the MySQL database server |
MYSQL_DBPASS | The password that will be used to connect to the MySQL database server |
MYSQL_DBNAME | The MySQL database name that the app will connect to. This is optional. |
The above code simply displays a list of databases that exist in the MySQL server.
Next, let us return back to the parent php-mysql-app folder, with:
cd ..
We need to create a docker image that will contain the Apache web server, the PHP runtime, and our PHP web app. A suitable image for this purpose is: php:7.3-apache.
Create a text file named Dockerfile and add to it the following content:
FROM php:7.3-apache#Install git and MySQL extensions for PHPRUN apt-get update && apt-get install -y gitRUN docker-php-ext-install pdo pdo_mysql mysqliRUN a2enmod rewriteCOPY src /var/www/html/EXPOSE 80/tcpEXPOSE 443/tcp
Above are instructions to create a Docker image that will contain Apache, PHP and our web app. I describe each line below:
FROM php:7.3-apache | Base image php:7.3-apache will be used |
the three RUN commands | These RUN commands enable the appropriate MySQL extensions so that your app can talk to MySQL |
COPY src /var/www/html/ | contents of the folder on the host computer are copied to /var/www/html in the container |
EXPOSE 80/tcp | Port 80 will be exposed in the container |
EXPOSE 443/tcp | Port 443 will be exposed in the container |
We will next compose a docker yml file that orchestrates the entire system which involves two containers: a MySQL database server container and a container that holds our PHP web application. In the php-mysql-app folder of your application, create a text file named docker-compose.yml and add to it the following content:
version: '3.8'volumes:datafiles:services:mysql:image: mysql:8.0.0container_name: mysql8environment:- MYSQL_ROOT_PASSWORD=secret- MYSQL_TCP_PORT=3306volumes:- datafiles:/var/lib/mysqlrestart: alwayswebsite:container_name: php73build:context: .dockerfile: Dockerfileenvironment:- MYSQL_DBHOST=mysql- MYSQL_DBPORT=3306- MYSQL_DBUSER=root- MYSQL_DBPASS=secret#- MYSQL_DBNAME=ports:- 8080:80- 8083:443depends_on:- mysql
Below is an explanation of what the docker-compose.yml file does.
We will be having two containers. Each container is considered to be a service. The first service is named mysql and will host the MySQL database server. The second service is named website and will host our PHP web app.
The most current version of docker-compose is version 3.8. This explains our docker-compose file.
The MySQL Container
Image mysql:8.0.0 will be used for the MySQL container.
A name mysql8 is given for the container that hosts the MySQL database server.
The root password will be secret when MySQL is configured. This is set by the MYSQL_ROOT_PASSWORD environment variable. Also, MySQL is configured to listen on port number 3306 - this happens to be the default MySQL port number.
A volume named datafiles is declared that will host MySQL data outside of the container. This ensures that even if the MySQL container is decommissioned, data will not be lost.
restart: always is so that if the container stops, it will be automatically restarted.
The PHP Web Application Container
A name php73 is given for the container that hosts the PHP web application.
The container will be built using the instructions in the Dockerfile file and the context used is the current directory.
The environment variables needed by the web app are:
- MYSQL_DBHOST representing the network location of the MySQL server
- MYSQL_DBPORT is the port number that the database server listens on.
- MYSQL_DBUSER is the username that will be used to connect to the database server
- MYSQL_DBPASS is the password that will be used to connect to the database server
Port 80 in the website container is mapped to port 8080 on the host computer and port 443 in the website container is mapped to port 8083 on the host computer.
depends_on indicates that the PHP web app relies on the MySQL container (mysql) to properly function.
Running the yml file
To find out if this all works, go to a terminal window and run the following command:
docker-compose up
Point your browser to http://localhost:8080/ and you should see the main PHP web page.
In my case, I experienced the following page:
Clean-up
To clean up your docker artifacts, follow these steps:
1) Hit CTRL C in the terminal window and enter the following command:
docker-compose down
This command will stop and remove the two containers pertaining to MySQL and PHP. It will also clear the virtual network that gets created by docker. It, however, does not delete the PHP web app image created by Dockerfile.
2) To delete the PHP web app image, first list all images with:
docker images
Identify the IMAGE-ID of website image. Use the IMAGE-ID with the following command to delete the image. As an example, I will be using IMAGE-ID 055e8e5694bc.
docker rmi 055e8e5694bc
3) Finally, we need to create the volume that was created that saves the MySQL data files. Run the following command to view volumes:
docker volume ls
I experienced the following volume name:
DRIVER VOLUME NAMElocal dockerphptutorial_datafiles
To remove the volume, use the appropriate name with the following command:
docker volume rm dockerphptutorial_datafiles
I hope you found this article useful.
No comments:
Post a Comment