Back to Home

Another Docker article for a newbie [nginx + php-fpm + postgresql + mongodb]

docker · docker-compose

Another Docker article for a newbie [nginx + php-fpm + postgresql + mongodb]

image

Good day to all. Inspired by a whole set of articles on the topic of raising the environment on the docker, I decided to share my experience on this issue.

I’ll make a reservation right away, this article is “from a newbie to a newbie”, so I’ll try to tell in detail about all the difficulties and issues that I had in setting up the environment in Docker.

Welcome to cat!

So, all that I will describe below, I will do on the laptop of the famous “fruit company”, but since I did the same on VDS under Centos 7 earlier, I will do a little digression with a description of how I did it on VDS .

We will begin naturally in registration on docker hub, which will act as a version control system, but only for our containers. Docker hub with free use allows you to have only 1 private repository, so we will mark each individual image with the appropriate tags - nginx, php7-fpm. I will not describe the creation of a repository, I think no one will have problems with this.

Now we can install docker itself on our workstation - in my case, this description is here .

When installing Docker on a Mac, we immediately have the docker toolbox installed , which contains the docker-compose tool we need . We will use it to combine our containers about a common environment.

Install docker-compose on Centos 7
Unfortunately, on VDS, I had to install it separately through pip .
yum -y install python-pip
pip install docker-compose

Next, log in to our Docker:

docker login

Now our private repositories are available to us (although the truth is empty there), the truth is empty there now, but we will fix it soon :)

For my project I made the following file structure:

├── contaners                    # Директория с кастомными образами для docker
│   ├── fpm
│   │   ├── Dockerfile
│   │   └── conf
│   │       └── fpm.conf        # Необходимые настройки fpm, у меня файл пустой:)
│   └── nginx
│       ├── Dockerfile
│       └── conf
│           └── nginx.conf
├── database                     # Директоря для хранения баз данных
├── docker-compose.yml
├── logs                         # Директоря для хранения логов
└── php-code                     # Директоря с php кодом
    ├── html
    └── index.php

Why do I need php-code / html
In the absence of the html directory, the image of the nginx container does not start, somewhere I found that the problem is solved by specifying WORKDIR in the Dockerfile, but this directory is still needed.

For the project, I will use custom images for nginx and fpm, so I put them in separate directories. Custom images are described using the Dockerfile . Here are mine:

./contaners/fpm/Dockerfile
FROM php:fpm
MAINTAINER nickname 
RUN apt-get update && apt-get install -y \
        libmcrypt-dev \
        && apt-get install -y libpq-dev \
        && docker-php-ext-install -j$(nproc) mcrypt \
        && pecl install mongodb
        && docker-php-ext-enable mongodb
RUN docker-php-ext-install mbstring
RUN docker-php-ext-install exif
RUN docker-php-ext-install opcache
RUN docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
    && docker-php-ext-install pgsql pdo_pgsql
COPY conf/ /usr/local/etc/php-fpm.d/
CMD ["php-fpm"]


./contaners/nginx/Dockerfile

FROM nginx:latest
MAINTAINER nickname 
COPY ./conf /etc/nginx/conf.d/


./contaners/nginx/conf/nginx.conf
server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    error_log  /etc/logs/nginx/nginx_error.log;
    access_log /etc/logs/nginx/nginx_access.log;
    root /var/www;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass fpm:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

The script from the official PHP image from the Docker Hub makes it easy to install the necessary extensions:
docker-php-ext-install

or

docker-php-ext-enable  # в случае, если расширение уже установлено (как у меня через pecl)

All the preparatory work has been carried out, now we need to describe how our containers will interact. As I already wrote, we will do this through docker-compose and the interaction rules must be described in the docker-compose.yml file . Here is my:

./docker-compose.yml
nginx:
 dockerfile: ./Dockerfile # путь до докер файла указываем относительно директории в build
 build: ./contaners/nginx
 ports:
  - 80:80
 volumes:
  - ./logs:/etc/logs/nginx
 volumes_from:
  - fpm:rw
 environment:
  - NGINX_HOST=localhost
  - NGINX_PORT=80
 command: nginx -g "daemon off;" # Можно было указать в докер-фале, но можно и здесь)
 links:
  - fpm
fpm:
 dockerfile: ./Dockerfile
 build: ./contaners/fpm
 volumes:
  - ./php-code:/var/www:rw

Note on specifying relative paths
If we indicate relative paths to files and directories, then they must necessarily begin with a period (as an indication of the current directory), i.e., for example, such a path contaners / nginx / Dockerfile will be interpreted incorrectly .

Now you can run our containers:

docker-compose up -d

argument -d
the -d argument is specified in order to untie the operation of containers from the console, i.e. run in daemon mode

That's all, our containers work and link, but I did something wrong, namely - we always refer to the Dockerfile to launch the container, this is not very convenient. Let's do it like this:

docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
2d6263b52380        test_nginx          "nginx -g 'daemon off"   8 minutes ago       Up 8 minutes        443/tcp, 0.0.0.0:8080->80/tcp        test_nginx_1
04370a9e1c73        test_fpm            "php-fpm"                8 minutes ago       Up 8 minutes        9000/tcp                             test_fpm_1
docker tag 2d6263b52380 my-login/repo:nginx
docker tag 2d6263b52380 my-login/repo:fpm
docker push my-login/repo:nginx
docker push my-login/repo:php7-fpm

Now our containers are managed through the docker hub and Dockerfiles we no longer need.
Fix docker-compose.yml:

./docker-compose.yml
nginx:
 image: my-login/repo:nginx
 ports:
  - 80:80
 volumes:
  - ./logs:/etc/logs/nginx
 volumes_from:
  - fpm:rw
 environment:
  - NGINX_HOST=localhost
  - NGINX_PORT=80
 command: nginx -g "daemon off;" # Можно было указать в докер-фале, но можно и здесь)
 links:
  - fpm
fpm:
 image: my-login/repo:php7-fpm
 volumes:
  - ./php-code:/var/www:rw

And now I realized that I forgot to add the pcntl extension for php. But this is easy to fix.
First, connect to the desired container:

docker exec -it 04370a9e1c73 bash

And add the necessary extension:

docker-php-ext-install pcntl

Well, we added it to the container, but we wanted to use the docker hub as a VCS - so we need to commit the changes:

docker commit -m "added pcntl ext" 04370a9e1c73 my-login/repo:php7-fpm

and push to the repository:

docker push my-login/repo:php7-fpm

Add more database containers (postgresql and mongodb):

./docker-compose.yml
nginx:
 image: my-login/repo:nginx
 ports:
  - 80:80
 volumes:
  - ./logs:/etc/logs/nginx
 volumes_from:
  - fpm:rw
 environment:
  - NGINX_HOST=localhost
  - NGINX_PORT=80
 command: nginx -g "daemon off;"
 links:
  - fpm
fpm:
 image: my-login/repo:php7-fpm
 volumes:
  - ./php-code:/var/www:rw
links:
  - mongo
  - postgres
mongo:
 image: mongo
 ports:
  - 27017:27017 # Проброс портов для внешнего доступа 
 volumes:
 - ./database/mongo:/data/db
postgres:
 image: postgres:latest
 ports:
  - 5432:5432 # Проброс портов для внешнего доступа 
 volumes:
  - ./database/postgres:/data/postgres
 environment:
  POSTGRES_PASSWORD: 
  POSTGRES_USER: postgres
  PGDATA : /data/postgres

And now we execute:

docker-compose up -d

Docker will add us new containers to already launched ones. But I opened the ports for external access, but we specified the password only for PostgreSql, we need to do the same for mongodb - how to do it (and not only) is described in detail here .

Add the Initial Admin Use For MongoDB
docker exec -it some-mongo mongo admin
connecting to: admin
> db.createUser({ user: 'jsmith', pwd: 'some-initial-password', roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] });
Successfully added user: {
    "user" : "jsmith",
    "roles" : [
        {
            "role" : "userAdminAnyDatabase",
            "db" : "admin"
        }
    ]
}


Databases from php are now available on postgres and mongo hosts respectively, i.e. to connect, for example, to mongodb, we must write the following:

$manager = new MongoDB\Driver\Manager("mongodb://mongo:27017");

That's all, thanks for your attention. Please note that everything described is solely my own experience and does not claim to be the ideal approach to setting up the environment through docker.

Read Next