Docker — Best setup for Development Testing and Production for PHP
I’m not a DevOps engineer, but I like the infrastructure as a code paradigm, so I try to use Docker wherever possible. And I also really like to tidy up the code and make everything as convenient and understandable for use as possible. I’m a PHP Developer, so all the examples will be related to PHP, but I think it won’t be a problem if you use another programming language.
Common beginner mistakes
Let’s start with Docker newbies’ most common problems, then move on.
More than one process per container
I often see how beginners try to stuff everything they need into one container. I’m not an exception either, I remember how I tried to configure Supervisor in a container… But then I realized that Docker is already Supervisor on steroids. Therefore, these should be separate containers if you need a database, web server, or message broker.
Same image for development and deployment
You should not use one image for development and deployment. Usually, during development, you need a different environment setting, for deployment you don’t need test frameworks or static code analyzers. Therefore, it is better to spread images for deployment and development.
Different containers for Stagging and Production
You don’t need to make a new build of the container every time for different environments, because you won’t have guarantees that it will work the same way. Therefore, it is best to use the same container for Staging and Production.
Directories structure
I don’t like it when the application code and the infrastructure code are mixed, so I separate the docker files from the application code like this:
.
└── project-directory
├── app
├── docker
├── var
├── .gitignore
└── docker-compose.yml
app/
— contains application files such as Symfony, Laravel, Slim, etc.
docker/
— contains Docker files such as Dockerfiles, Nginx configs, etc.
var/
— contains temporary Docker files such as database files, etc.
Now let’s see what’s inside the docker/
directory. I separate the files that will be used for application development and production.
.
└── docker
├── development
└── production
development/
— contains development Docker files.
production/
— contains production and staging Docker files.
Let’s consider the development
directory as an example, the structure of the production
directory will be similar.
.
└── development
├── nginx
├── php
├── php-cli
└── php-fpm
nginx/
— contains Nginx configurations and Dockerfile.
php/
— contains common configuration for php-cli
and php-fpm
containers.
php-cli/
— contains configuration specific for PHP CLI container. This container will be used to run console commands such as composer install
, composer require
, etc.
php-fpm/
— contains configuration specific for PHP FPM container. this container will be used to work with Nginx.
You can find more details in my repository. I will leave a link at the end of the article.
Dynamiс domain name changing
This is required to deploy the application in staging and production environments with different domain names. Instead of using Nginx configurations directly, I use templates to dynamically populate data from environment variables.
.
└── nginx
├── templates
│ └── default.conf.template
└── Dockerfile
Let’s see what is in the default.conf.template
file
server {
server_name ${SERVER_NAME};
root /app/public;
...
And in the Dockerfile
, we simply copy the contents of the templates/
directory to the corresponding directory inside the container.
FROM nginx:1.18-alpine
COPY ./nginx/templates /etc/nginx/templates
WORKDIR /app
Code examples
You can find more details in my GitHub repository: https://github.com/pogulailo/seadog