» » Докеризация nginx и php на сокетах с ротацией логов

 

Докеризация nginx и php на сокетах с ротацией логов

Автор: admin от 29-01-2018, 15:05, посмотрело: 180

В статье на Хабре обсуждался «docker way»(TM), который гласит: один контейнер — один процесс.Следование этому принципу при докеризации nginx чревато двумя последствиями. Настроить взаимодействие nginx и php-fpm в разных процессах через unix сокет немного сложнее, чем может показаться. И ротация логов, которая при обычной установке идет «из коробки», не может осуществляться в принципе, т.к. требует отправки сигнала USR1 nginx, для чего нужен ещё один процесс.

защиты от DDoS-атак вместо сервера nginx будет запускаться openresty (сборка nginx от Taobao со скриптовым движком Lua). Этот сервер имеет другое по сравнению с nginx расположение каталогов с файлами. Но все остальное абсолютно идентично.



Для начала создадим файл docker-compose.yml в корневом каталоге проекта:



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


Мы предполагаем что сценарии создания контейнеров будут храниться в файлах docker/php/Dockerfile и docker/nginx/Dockerfile. Имя Dockerfile является именем по умолчанию, следовательно нет необходимости его явно задавать в конфигурации.



Создадим файл docker/php/Dockerfile:



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


Загружается образ php:7-fpm и создается пользователь с идентификатором заданным параметром UID (в docker-compose.yml UID: 3000) с именем app в группе app. Это нужно чтобы задать права на чтение сокета из контйнера, где будет запущен openresty.



Для того чтобы получить ротацию логов в nginx или openresty, необходимо чтобы контейнер не завершал работу при рестарте веб-сервера, а так же чтобы в этом же контейнере был запущен cron. То есть это не будет однопроцессный контейнер, но иначе ничего не получится. Запускать несколько процессов рекомендуется через supervisor.



Создадим файл docker/nginx/Dockerfile:



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"]


Сначала интсаллируются все необходмые программы. Затем копируются конфигурационные файлы из каталога ./docker/nginx/ во внутреннюю файловую систему контейнера. Далее некоторым из этих файлов присваиваются права 644 (в противном случае система не будет выполнять ротацию логов). И также создается пользователь и группа app с тем же самым идентификатором (UID: 3000).



Так же необходмио создать несколько конфигурационных файлов.



Файл docker/php/zz-docker.conf (имя zz-docker.conf присутсвует в конфигурации образа php:7-fpm. Это нигде не описано и может меняться. К сожалению в настоящий момент подробных описаний образов нет, и приходися их исследовать после загрузки из репозитария):



[global]
daemonize = no

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


Параметр listen = /sock/docker.sock будет тот же что и в конфигурации nginx.



Основной конфигурационный файл nginx придется переписать т.к. в openresty он не содержит необходимых параметров, а это расположение логов, иднтификатор процесса, пользователь (app), и каталог с конфигурациями виртуалных серверов (/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/*;
}


Создадим виртуальный сервер с конфигурацией server.conf:



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;
    }
}


К прокси обращаемся не через порт, а через сокет unix:/sock/docker.sock.



Теперь создадим файл logrotate.conf:



/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
}




И задание для cron:



SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""

# m h dom mon dow user  command
*  *  *  *  *  root  logrotate -v /etc/logrotate.conf
#




Размер файла size=1k и зспуск ротации каждую минуту (* * * * *) не для рабочего сервера, а тоько для того чтобы можно было при имнимальных временных заратах наблюдать ротацию логов. Команда logrotate копирует логи в архивные файлы. Но пока не будет перезапущен nginx — не произойдет реального создания нового пустого файла логов. Для того чтобы nginx открыл логи заново служит устрашающая команда kill -USR1 `cat /var/run/nginx.pid`.



И наконец конфигурация supervisor:



[supervisord]
nodaemon=true
logfile=/dev/null

[program:nginx]
command=/usr/local/openresty/bin/openresty -g 'daemon off;'

[program:cron]
command=cron -f


Совершенно не имеет значения где все эти конфигурационные фйлы находятся, т.к. все пути задаются в операторах COPY из Dockerfile, и в значениях volumes из docker-compose.yml. Теперь нужно набраться терпения и записать все необходимые пути в 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


Теперь можно добавить скрипты Lua (см. статью на Хабре).



apapacy@gmail.com

27 января 2018 года

Источник: Хабрахабр

Категория: Программирование, Веб-разработка

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *