How to dockerize your PHP application for AWS Fargate?

Andreas Wittig – 12 Jul 2019

This blog post is an excerpt of our book Rapid Docker on AWS.

The biggest game-changer for Docker on AWS was the announcement of AWS Fargate. Operating Docker containers could not be easier. With AWS Fargate, you launch Docker containers in the cloud without any need of managing virtual machines.

How to dockerize your PHP application for AWS Fargate?

All you need is a Docker image of your application. You will learn how to dockerize your PHP web application for the use with AWS Fargate in the following.

What is a Docker image?

A Docker image is similar to a virtual machine image, such as an Amazon Machine Image (AMI) that is used to launch an EC2 instance. The Docker image contains an operating system, the runtime environment, 3rd party libraries, and your application. The following figure illustrates how you can fetch an image and start a container on any platform.

Distribute your application among multiple machines with a Docker image

Two containers: NGINX and PHP-FPM

But how do you create a Docker image for your web application? By creating a script that builds the image step by step: a so-called Dockerfile.

Our example is a PHP application written in PHP without using any frameworks. The project’s folder structure:

  • conf the configuration directory (contains .ini files)
  • css the stylesheet directory (contains .css files)
  • img the images directory (contains .gif files)
  • lib the libraries directory (contains .php files)
  • index.php the main file

Add a docker directory containing the Docker configuration (e.g., the Dockerfile).

A typical setup to serve a PHP application consists of:

  1. A web server (for example NGINX)
  2. A PHP process (for example PHP-FPM)

Therefore, we need to run two processes: NGINX and PHP-FPM. However, a container should only run exactly one process at a time. Which means we need to build two images. The following figure shows the two containers: the NGINX container receives the request from the client and forwards PHP requests to the PHP-FPM container. Both containers run on the same host to avoid additional network latency.

Proxy pattern: NGINX and PHP-FPM containers running on the same machine

Building the NGINX image

Start with creating a Docker image for NGINX. NGINX serves the static files. In our example application, the static files are stored in the css and img directory already. On top of that, NGINX forwards PHP requests to PHP-FPM.

The following snippet shows the configuration file docker/nginx/default.conf which tells NGINX to serve static files from /var/www/html and forward PHP requests to PHP-FPM. You do not need to make any changes to the NGINX configuration when dockerizing your web application.

server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php;
# pass the PHP scripts to FastCGI server
# listening on 127.0.0.1:9000
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
include fastcgi_params;
}
}

Next, you need a Dockerfile for building your own NGINX image. The following snippet shows the Dockerfile docker/nginx/Dockerfile that we created for our sample application.

The first instruction defines the base image. When creating an image, we don’t have to start from scratch. We can use a pre-built base image.

FROM nginx:1.14

The next instruction copies the NGINX configuration file from your disk to the Docker image.

COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf

The next two instructions copy the css and img directories from your local disk to the NGINX root directory /var/www/html/ in the Docker image.

Depending on where you are storing the static files of your web application, you’ll need to modify these instructions accordingly. Make sure you are copying all static files to /var/www/html/.

COPY css /var/www/html/css
COPY img /var/www/html/img

The next instruction runs the chown command to transfer ownership of all static files to the nginx user. The nginx user is part of the base image.

RUN chown -R nginx:nginx /var/www/html

The Dockerfile is ready. It’s time to build your first image.

docker build -t php-basic-nginx:latest -f docker/nginx/Dockerfile .

The following snippet explains the docker build command in more detail.

docker build                 => Docker command to build a new image
-t php-basic-nginx:latest => Add a tag (name) to the new image
-f docker/nginx/Dockerfile => Location of the Dockerfile
. => Use the current directory as the
build context (all paths, e.g.
in COPY, are relative to the
build context)

The next step is building the PHP-FPM image. The following snippets show the Dockerfile docker/php-fpm/Dockerfile used by our sample application.

Are you looking for more details? Our book Rapid Docker on AWS contains the full source code of the PHP example application.

Building the PHP-FPM image

The first instruction defines the base image. We are using a base image with PHP 7.3 pre-installed for our sample application.

FROM php:7.3-fpm-stretch

It is followed by enabling the PHP configuration optimized for production workloads and installing the PHP extensions pdo and pdo_mysql.

# PHP
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN docker-php-ext-install -j$(nproc) pdo pdo_mysql

The following instructions copy the PHP files from your disk to the root directory of PHP-FPM.

When dockerizing your application, you will most likely need to modify these COPY instructions to make sure all PHP files are copied to the image. Also, as you add new PHP files to your application, make sure to add them to this list as well.

# Copy PHP files
COPY index.php /var/www/html/
COPY lib /var/www/html/lib
RUN chown -R www-data:www-data /var/www/html

The following instructions tell Docker that PHP-FPM will expose port 9000 and start the PHP-FPM process by default. You do not need to change anything here.

# Expose and start PHP-FPM
EXPOSE 9000
CMD ["php-fpm"]

Next, use the docker build command to create your PHP-FPM image:

docker build -t php-basic-php-fpm:latest -f docker/php-fpm/Dockerfile .

What’s next?

You have successfully built two Docker images: NGINX and PHP-FPM. The following steps are missing to start Docker containers based on your images with AWS Fargate.

  1. Push both images to a Docker registry (e.g., ECR).
  2. Create an ECS cluster.
  3. Create an ECS launch configuration.
  4. Create an ECS service.

Sounds complicated? Our book Rapid Docker on AWS contains Infrastructure as Code templates helping you to set up all the missing steps in about 15 minutes.

Andreas Wittig

Andreas Wittig

I’m the author of Amazon Web Services in Action. I work as a software engineer, and independent consultant focused on AWS and DevOps.

You can contact me via Email, Twitter, and LinkedIn.

Briefcase icon
Hire me
Cover of Rapid Docker on AWS

New book: Rapid Docker on AWS

A rapid way to get your web application up and running on AWS. Made for web developers and DevOps engineers who want to dockerize their web applications and run their containers on Amazon Web Services. Prior knowledge of Docker and AWS is not required.

Buy icon
Buy now
Marbot Logo

Incident Management for Slack

Team up to solve incidents with our chatbot marbot. Never miss a critical alert. Escalate alerts from your AWS infrastructure among your team members. Strong integrations with all parts of your AWS infrastructure: CloudWatch, Elastic Beanstalk, RDS, EC2, ...

Slack icon
Try for free