📜 ⬆️ ⬇️

Dostering nginx and php on sockets with log rotation

The article on Habré discussed the “docker way” (TM), which says: one container is one process.
one process per container
Each container should have only one concern

It makes it easier to scale horizontally and reuse containers. For instance, there are three containers for each instance.

You may have heard that there should be “one process per container”. It is not necessarily true. In addition to the process of spraying, there could be some processes of their own accord. For instance, Celery can spawn multiple processes, or Apache might create a process per request. It is not a hard and fast rule. Keep it clean and modular as possible.
')
If you can use container lines, you can use.
Following this principle when completing nginx is fraught with two consequences. Configuring the interaction of nginx and php-fpm in different processes through a unix socket is a bit more complicated than it might seem. And the rotation of the logs , which in a normal installation is “out of the box”, cannot be carried out in principle, because requires sending a USR1 nginx signal, for which another process is needed.

As a result of the discussion, it became clear that instead of sending the USR1 nginx signal, add the copytruncate option to the logrotate configuration. So in the container there is no need to run multiple processes. However, all actions on the startup setup of log rotation on cron will still need to be performed not inside the container, but on the host where the container works. When running both a web server and log rotation in a single container, a separate configuration of the rotation on the host is no longer required.


The above links provide solutions. But the first time it did not work, and I had to look for reasons. Therefore, besides the links, I present the results of my experiments. In order to be able to get acquainted with the method of protection against DDoS-attacks, openresty will be launched instead of the nginx server (build of nginx from Taobao with the Lua scripting engine). This server has a different location to the file directories compared to nginx. But everything else is absolutely identical.

First, create a docker-compose.yml file in the project root directory:

version: "3" services: app: build: context: ./docker/php # dockerfile: docker/php/Dockerfile args: UID: "3000" working_dir: /app nginx: build: context: ./docker/nginx # dockerfile: docker/nginx/Dockerfile args: UID: "3000" ports: - 8000:80 

We assume that container creation scripts will be stored in docker / php / Dockerfile and docker / nginx / Dockerfile files. The name of the Dockerfile is the default name, therefore there is no need to explicitly set it in the configuration.

Create a docker / php / Dockerfile file:

 FROM php:7-fpm ARG UID RUN addgroup --gid $UID --system app \ && adduser --uid $UID --system --disabled-login --disabled-password --gid $UID app 

The php: 7-fpm image is loaded and a user is created with the identifier specified by the UID parameter (in docker-compose.yml UID: 3000) with the name app in the app group. This is needed to set permissions to read the socket from the container where openresty will be launched.

In order to get the log rotation in nginx or openresty, it is necessary that the container does not shut down when restarting the web server, as well as that cron is running in the same container. That is, it will not be a single-process container, but otherwise it will not work. It is recommended to run multiple processes through supervisor.

Create a docker / nginx / Dockerfile file:

 FROM openresty/openresty:xenial RUN apt-get update && apt-get install -y supervisor cron logrotate COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY ./logrotate.conf /etc/logrotate.conf COPY ./cron.d /etc/cron.d/nginx ARG UID RUN mkdir -p /var/log/supervisor \ && chmod 644 /etc/logrotate.conf && chown root:root /etc/logrotate.conf \ && chmod 644 /etc/cron.d/nginx && chown root:root /etc/cron.d/nginx \ && addgroup --gid $UID --system app \ && adduser --uid $UID --system --disabled-login --disabled-password --gid $UID app ENTRYPOINT ["/usr/bin/supervisord"] 

At first, all necessary programs are integrated. Then the configuration files from the ./docker/nginx/ directory are copied to the container's internal file system. Further, some of these files are assigned 644 rights (otherwise the system will not rotate the logs). And it also creates a user and app group with the same ID (UID: 3000).

It is also necessary to create several configuration files.

The docker / php / zz-docker.conf file (the name of zz-docker.conf is present in the configuration of the php image: 7-fpm. This is not described anywhere and can change. Unfortunately, there are no detailed descriptions of images at the moment, and have to investigate them after downloads from repository):

 [global] daemonize = no [www] ;listen = [::]:9000 # Don't need this listen = /sock/docker.sock listen.owner = app listen.group = app listen.mode = 0660 

The parameter listen = /sock/docker.sock will be the same as in the nginx configuration.

The main configuration file nginx will have to be rewritten. in openresty, it does not contain the necessary parameters, and this is the location of the logs, the process identifier, the user (app), and the directory with the virtual server configurations (/conf.d).

 user app; error_log /var/log/nginx/error.log debug; pid /var/run/nginx.pid; http { access_log /var/log/nginx/access.log; include mime.types; default_type application/octet-stream; server { listen 80; server_name localhost; location / { root html; } } include /usr/local/openresty/nginx/conf/conf.d/*; } 

Create a virtual server with the server.conf configuration:

 server { listen 80; server_name local; root /usr/share/nginx/html; disable_symlinks off; client_max_body_size 50M; location ~ (/assets|/favicon.ico) { try_files /build$uri $uri =404; } location / { try_files $uri /app.php$is_args$args; } location ~ \.php$ { fastcgi_pass unix:/sock/docker.sock; try_files $fastcgi_script_name =500; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } 

We unix:/sock/docker.sock proxy not through a port, but through a unix:/sock/docker.sock socket unix:/sock/docker.sock .

Now create the logrotate.conf file:

 /var/log/nginx/*.log { size=1k missingok rotate 8 notifempty sharedscripts postrotate [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid` endscript } 


And the task for cron:

 SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin MAILTO="" # mh dom mon dow user command * * * * * root logrotate -v /etc/logrotate.conf # 


File size size = 1k and rotation rotation every minute (* * * * *) is not for a working server, but only for the rotation of logs to be observed at the minimum time. The logrotate command copies logs to archive files. But until nginx is restarted, the real creation of a new empty log file will not happen. In order for nginx to open the logs again, the awesome command kill -USR1 `cat /var/run/nginx.pid` .

Finally, the supervisor configuration:

 [supervisord] nodaemon=true logfile=/dev/null [program:nginx] command=/usr/local/openresty/bin/openresty -g 'daemon off;' [program:cron] command=cron -f 

It doesn't matter where all these configuration files are located, because all paths are specified in the COPY statements from the Dockerfile, and in the volumes values ​​from the docker-compose.yml. Now you need to be patient and write down all the necessary paths in docker-compose.yml.

 version: "3" services: app: build: context: ./docker/php args: UID: "3000" working_dir: /app volumes: - ./:/app - ./html:/usr/share/nginx/html - ./docker/php/zz-docker.conf:/usr/local/etc/php-fpm.d/zz-docker.conf - ./docker/sock:/sock expose: - 9000 links: - mysql nginx: build: context: ./docker/nginx args: UID: "3000" ports: - 8000:80 volumes: - ./:/app/ - ./html/:/usr/share/nginx/html/ - ./docker/nginx/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf - ./docker/nginx/conf.d/:/usr/local/openresty/nginx/conf/conf.d/ - ./docker/nginx/log/:/var/log/nginx/ - ./lua/:/usr/share/nginx/lua/ - ./docker/sock/:/sock/ links: - app depends_on: - app 

Now you can add Lua scripts (see the article on Habré ).

apapacy@gmail.com
January 27, 2018

Source: https://habr.com/ru/post/347662/


All Articles