Containerizing a Simple PHP Application with Docker

PHP is a server-side scripting language designed for web development, but which can also be used as a general-purpose programming language. You can use Docker to containerize your php application, whether it is running natively, or is using Apache for serving web content.

The goal of this short post is to show how easy it is to run a simple php application, both natively or with Apache server, in a Docker container. Nothing fancy there, but this will help to grasp the steps to dockerize a php application or any other application built in a different language, as the same approach applies for most of the steps described here.

In this post, I am assuming you have a basic knowledge on how to run common operations on containers and what is a Dockerfile, so I’ll not detail all the steps related to those commands. The Docker host used to show these example is running a CentOS Linux release 7.4.1708 (Core).

PHP App with Command Line


A PHP app does not need a web server to run, you just write your code and run it in the PHP cli. We have here a test.php script located in ~/myapp that looks like this:

$ ls ~/myapp
test.php

The below php script will display a long format of today’s date.

$ cat test.php
<?php
echo "Hello. Today's date is: ".date('l jS \of F Y h:i:s A');
?>

In my Docker host, php is not installed.

$ php -v
bash: php: command not found...

And we will use Docker to host a php environment to run our script.

In a Single Command

To run a docker php container with our test.php, the following command will do it!

$ docker run -v ~/myapp:/myapp -w /myapp php php test.php
Hello. Today's date is: Sunday 16th of September 2018 09:01:01 AM
  • -v is to map a the ~/app application directory the /myapp folder in the php container.
  • -w is to specify that the working directory is /myapp. This will allow to run the script without the need to specify the full path.
  • php to pull the latest php image from Docker Hub. If your application is running with a specific version of php, a tag can be specified. For instance, php:7.2-cli
  • php to invoke the php cli.
  • test.php is the name of the script .

Our container started a php environment, and displayed today’s date then exited.

$ docker ps -a
CONTAINER ID        IMAGE       COMMAND                  CREATED          STATUS                     PORTS       NAMES
ee9ab36e0634        php         "docker-php-entrypoi…"   9 seconds ago    Exited (0) 8 seconds ago               lucid_hoover

Using Dockerfile

More commonly, you will probably want to do it using a Dockerfile to build the image that includes your php script. Here is the syntax of the Dockerfile.

$ cat Dockerfile
FROM php
COPY . /myapp
WORKDIR /myapp
CMD ["php", "test.php"]
  • The COPY directive is to copy the app directory (~/myapp) content to the /myapp folder inside the container.
  • The WORKDIR is make /myapp the default working directory, where all the php files have been copied.
  • The CMD directive is to run the test.php script for php cli.

If you don’t know what a Dockerfile is, it is a text document containing all the commands you might want to call from the command line to build a custom image. These commands are typically grouped within one file to assemble the image, and this text file is called Dockerfile. More on this here.

Below command will build a php image named php-app with your newly added test.php script, using your Dockerfile.

$ docker build -t php-app .

Sending build context to Docker daemon  4.096kB
Step 1/4 : FROM php
 ---> 4a05f96f44b5
Step 2/4 : COPY . /myapp
 ---> 5b645455e1bd
Step 3/4 : WORKDIR /myapp
 ---> Running in 5d6e495d1573
Removing intermediate container 5d6e495d1573
 ---> 5ad81652d6fd
Step 4/4 : CMD ["php", "test.php"]
 ---> Running in 43b6ddfe7569
Removing intermediate container 43b6ddfe7569
 ---> 8cecacf3c6cd
Successfully built 8cecacf3c6cd
Successfully tagged php-app:latest

We can check that the php-app image has been built successfully and is available in the local registry.

$ docker images
REPOSITORY       TAG          IMAGE ID         CREATED          SIZE
php-app          latest       8cecacf3c6cd     3 minutes ago    367MB
php              apache       a7d68dad7584     31 hours ago     378MB
php              7.2-cli      656f0f210b0f     31 hours ago     368MB

We can now run a container from that image.

$ docker run php-app
Hello. Today's date is: Sunday 16th of September 2018 09:16:47 AM

PHP App with with Apache


While running a PHP app natively can be run quite easily, you will want most of the time to run it with an Apache server to serve web content. For this, there’s a version of the PHP container that’s packaged with the Apache web server, and its tagged php:apache.

For this example, I have an index.php file that looks like this:

$ cat index.php

<!DOCTYPE HTML>  
<html>

<head>
	<title>
	Test Hello World PHP Script
	</title>
</head>

<body>
	<?php
	echo "<h3>Hello World!. This PHP application is containerized with Docker</h3>"
	?>
</body>

</html>

We will use the php:apache image available in Docker Hub to pull our container that will serve this php page.

In a Single Command

The command above will run the container and makes its port 80 exposed to the external world.

$ docker run -d -p 80:80 -v ~/myapp:/var/www/html php:apache
e67b35fd3a4a2a4d2fff7f0ec00446ee1f114d8e2c7c62414d5d5ef83a8c2eee
  • -d to run the container in the background.
  • -p to map the external port 80 to the container internal port 80.
  • -v to map the ~/app application directory the /var/www/html Apache default root folder.

My container is running and listening on port 80 via the Docker host port 80.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
39824ec8e775        php:apache          "docker-php-entrypoi…"   19 minutes ago      Up 19 minutes       0.0.0.0:80->80/tcp   hardcore_mcclintock
$ docker port hardcore_mcclintock
80/tcp -> 0.0.0.0:80

My Docker host IP is 192.168.16.22. Let’s browse it!

Cool! It’s Working.

Using Dockerfile

This time, the docker file will be only two lines.

FROM php:apache
COPY . /var/www/html

To build the image.

$ docker build -t my-php-web-app .

Sending build context to Docker daemon   5.12kB
Step 1/2 : FROM php:apache
 ---> a7d68dad7584
Step 2/2 : COPY . /var/www/html
 ---> 5339433f9ca6
Successfully built 5339433f9ca6
Successfully tagged my-php-web-app:latest

Image is there now on the Docker host.

$ docker images
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
my-php-web-app            latest              5339433f9ca6        40 seconds ago      378MB
php-app                   latest              8cecacf3c6cd        About an hour ago   367MB
php                       apache              a7d68dad7584        32 hours ago        378MB
php                       7.2-cli             656f0f210b0f        32 hours ago        368MB

Let’s now run the container from my-php-web-app image.

$ docker run -d -p 80:80 my-php-web-app

Because you have already used port 80 for the previous running container, you’ll have either to remove it or to map to another port to be able to run this container.

And test is successful!

 

Admittedly, this was a very basic example. In production you would use Docker-compose to deploy a multi-tier application running in multi containers on a Docker Swarm cluster, but going through those basic steps showed how easy it is to run php applications without actually having php, thanks to containers.

Trying something more exciting?


That was a very basic example. If you want try something more interesting, try this script which is a PHP form validation example. Copy and paste the code in your php page, try to run it in a container and enjoy Docker containerization super power.

 

Leave a Comment

Your email address will not be published. Required fields are marked *