PHP(Phalcon) + Nginx + Mysql with Docker compose - Part 1

by Lovefield

Back End /

Hi, I'm Lovefield.

With the recent I use of Docker, the blog has also been changed to Docker-based. This blog is based on Phalcon. Phalcon was a more challenging framework than we thought. It took a lot of trials and errors to get Phalcon on the Docker before he could make it. This article is going to talk about how to utilize Phalcon in a Docker environment.

First the directory structure, I assign one folder per container considering the management aspect when using docker-compose.

- mysql
- php
- nginx
- phalcon

The “mysql/data” folder is a space for string DB data, used to keep data intact with or without container behavior. The asset folder in the “php” folder is the place where ini files are created. The .conf will also be created for the “nginx” folder.The reason for creating a separate “phalcon” folder is to distinguish between the actual drive file and the setup file.

Now, write the docker-compose.yml file.

version: "3"

Write "3" in "version" to use the latest version. We will use a total of 3 containers, so please write "mysql", "php", and "nginx" in "services".

Shall we set up the "mysql" container first?

   container_name: mysql
   image: mysql:8.0.22
       MYSQL_DATABASE: app
       MYSQL_USER: user
       MYSQL_PASSWORD: user_pw
       MYSQL_ROOT_PASSWORD: root_pw
   command: ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
       - ./mysql/data:/var/lib/mysql:rw
       - "3306:3306"
   restart: always
           max-size: "1m"
           max-file: "3"

Type "mysql:8.0.22" in the "image" entry to use Mysql 8. It means that "mysql:8.0.22" is taken from the list in the Docker image hub and used.
The "environment" entry sets the factors to be used within the container.
The name of the DB is "MYSQL_DATABASE".
Username as "MYSQL_USER".
User password with "MYSQL_PASSWORD".
Set the root account password to "MYSQL_ROOT_PASSWORD".

The "command" entry is a command to execute after the container is executed. Mysql 8 is set to character set to utf8 by default, but it adds related commands just in case.The "volume" entry is a list that will match the path within the container with the current directory. Write "./mysql/data:/var/lib/mysql:rw" to place all data in the relevant folder. At the end, ":rw" is an option that grants permission to read and write.
The "ports" entry matches the external port with the internal port of the container.
The "restart" entry is an option to restart when the container is stopped due to a problem.
The "logging" entry is literally to log, this time saving up to 1mb records per file and limiting it to up to three.

Next, let's set up a "php" container.

   container_name: php
       context: ./php
       dockerfile: dockerfile
           - WITH_XDEBUG=true
   working_dir: /var/www/html
       - ./php/asset/timezone.ini:/usr/local/etc/php/conf.d/timezone.ini
       - ./php/asset/file.ini:/usr/local/etc/php/conf.d/file.ini
       - ./phalcon:/var/www/html:rw
   command: bash -c "php-fpm"
   restart: always
           max-size: "1m"
           max-file: "3"

The "php" container is difficult to use images. You are going to use the docker file for additional settings, so please specify the docker file as a "build" entry instead of an "image"."args" is the factor to use when executing dockerfile. We need to install Xdebug to debug php. But, there is no reason to run a heavy Xdebug on a real server. "args" is a factor for whether or not Xdebug is installed.

In the "php" folder, create a dockerfile to use in the container.

# using php7.4-fpm image
FROM php:7.4-fpm

# install default library
RUN apt-get update && apt-get install -y \
       libfreetype6-dev \
       libpng-dev \
       zlib1g-dev \
       g++ \
       libicu-dev \
       libmcrypt4 \
       libzip-dev \
   && docker-php-ext-install pdo_mysql \
   && docker-php-ext-install mysqli \
   && docker-php-ext-install zip

# install composer
RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Whether or not to install Xdebug

# install Xdebug
RUN set -eux; \
   if [ $WITH_XDEBUG = "true" ] ; then \
       pecl install xdebug; \
       docker-php-ext-enable xdebug; \
       echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "display_startup_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "display_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "xdebug.idekey=PHPSTORM" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
       echo "xdebug.remote_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
   fi ;

# phalcon version setting

RUN set -xe && \
   # install PSR
   curl -LO https://github.com/jbboehr/php-psr/archive/v${PSR_VERSION}.tar.gz && \
   tar xzf ${PWD}/v${PSR_VERSION}.tar.gz && \
   # install Phalcon
   curl -LO https://github.com/phalcon/cphalcon/archive/v${PHALCON_VERSION}.tar.gz && \
   tar xzf ${PWD}/v${PHALCON_VERSION}.tar.gz && \
   docker-php-ext-install -j $(getconf _NPROCESSORS_ONLN) \
       ${PWD}/php-psr-${PSR_VERSION} \
       ${PWD}/cphalcon-${PHALCON_VERSION}/build/${PHALCON_EXT_PATH} \
   && \
   # remove tmp file
   rm -r \
       ${PWD}/v${PSR_VERSION}.tar.gz \
       ${PWD}/php-psr-${PSR_VERSION} \
       ${PWD}/v${PHALCON_VERSION}.tar.gz \
       ${PWD}/cphalcon-${PHALCON_VERSION} \
   && \
   php -m

Next, create ini, the php settings file that you linked to the "volume" entry. You must create timezone.ini and file.ini in the "php/asset" folder, respectively.

; timezone.ini

; file.ini

I changed the timezone on the php to "Asia/Seoul" in Korean time and set the maximum upload file capacity to 10MB.

Lastly, set the "nginx" container.

   container_name: nginx
   image: nginx:1.17.8
   command: ["nginx", "-g", "daemon off;"]
   working_dir: /var/www/html
       - php
       - mysql
       - ./nginx/asset/:/etc/nginx/conf.d/
       - ./nginx/log:/var/log/nginx/:rw
       - ./phalcon:/var/www/html:rw
       - "80:80"
       - php
   restart: always
           max-size: "1m"
           max-file: "3"

Use "depends_on" to set the "nginx" container to run after the "php" container and the "mysql" container have been run.
Link to the "php" container via "links".
Use the folder "./nginx/log:/var/log/:rw" for "volume" to logging.
Files running the actual app use the folder "./palcon:/var/www/html:rw" and files setting nginx use the folder "./nginx/asset/:/etc/nginx/conf.d/".

Now create the file default.conf in the folder "nginx/asset" that you set up nginx.

server {
   listen 80;
   root /var/www/html/public;
   index index.html index.htm index.php;

   server_name localhost;
   client_max_body_size 10M;

   error_log /var/log/nginx/error.log;
   access_log /var/log/nginx/access.log;

   location / {
       try_files $uri $uri/ /index.php?_url=$uri&$args;

   location ~ \.php$ {
       try_files $uri =404;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;
       fastcgi_pass php:9000;
       fastcgi_index /index.php;
       fastcgi_connect_timeout 60s;
       fastcgi_read_timeout 60s;
       fastcgi_buffers 256 4k;
       include fastcgi_params;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_param PATH_INFO $fastcgi_path_info;

docker-compose connected the external port from 80 to the internal port 80, so port is 80.
The reason why root is "/var/www/html/public" is because of the folder structure in Phalcon.
Write down each path to logging and create a location.
The most important part of this is "fastcgi_pass". You must write down the name and port of the container containing php. Write "Container name:port" to locate the address of the container name within the docker and connect it to the port of that address. PHP uses 9000 port basically, so please connect it to 9000 port.

We're all set now. Try the first run with the command 'docker-compose up-d'.If you don't give me the "-d" option, it won't run as a daemon and the maintain server.(CAUTION: If there is insufficient RAM when installing xdebug or phalcon, an error can occur. A minimum of 4gb RAM is required)


Once the command is functioning normally, you can see the screen above.
Now use docker-compose ps to check the status of the containers.


If the state is up and ports are connected normally, it is a success.
The basic procedure is over, and the setting after the docker-compose up command is explained in the next article.




Web Front-End developer

하고싶은게 많고, 나만의 서비스를 만들고 싶은 변태스러운 개발자입니다.


디코에 오신 것을 환영해요!
전문가들의 수많은 아티클 창고 🤓