Если вы уже читали как запустить "Nginx + PHP-FPM" + "MySQL", то после этого на должности DevOps инженера вы скорее всего столкнетесь с вопросом, а как запаковать PHP приложение в Dockerfile? На этот вопрос и многое другое, ответим в данной статье!
1. Ставим "Nginx + PHP-FPM" + "MySQL
У нас Debian 10, все примеры ниже на данной версии Linux. В других сборках - суть та же. Начнем с установки в Debian, потом перенесем в Docker. Простейшие моменты будем пропускать. Статья будет длинная, чтобы понять все от и до. Приступим:
Ставим Nginx:
sudo apt update apt install nginx systemctl start nginx systemctl status nginx ● nginx.service - nginx - high performance web server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2019-11-06 21:49:47 +05; 1s ago Docs: http://nginx.org/en/docs/ Process: 4143 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS) Main PID: 4144 (nginx) Tasks: 2 (limit: 4915) Memory: 2.1M CGroup: /system.slice/nginx.service ├─4144 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf └─4145 nginx: worker process
Проверяем:
curl -I 127.0.0.1 HTTP/1.1 200 OK Server: nginx/1.17.5 Date: Wed, 06 Nov 2019 16:51:48 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 22 Oct 2019 14:30:00 GMT Connection: keep-alive ETag: "5daf1268-264" Accept-Ranges: bytes
Полезные файлы и директории:
/etc/nginx /etc/nginx/nginx.conf /etc/nginx/sites-enabled/ /etc/nginx/sites-available/ /var/log/nginx/
* Можете воспользоваться статьей, для установки через Ansible: Playbook: Блоки, условия и циклы. Lesson 7
Ставим PHP-FPM
apt install php-fpm apt install php-mysql php-bcmath php-json php-mbstring php-tokenizer php-xml php-curl # для работы с графикой можно поставить доп модули: apt-get install php7.3-gd php7.3-imagick
Проверяем:
systemctl status php7.3-fpm ● php7.3-fpm.service - The PHP 7.3 FastCGI Process Manager Loaded: loaded (/lib/systemd/system/php7.3-fpm.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2019-11-06 22:30:53 +05; 1min 9s ago Docs: man:php-fpm7.3(8) Main PID: 13586 (php-fpm7.3) Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec" Tasks: 3 (limit: 4915) Memory: 14.9M CGroup: /system.slice/php7.3-fpm.service ├─13586 php-fpm: master process (/etc/php/7.3/fpm/php-fpm.conf) ├─13587 php-fpm: pool www └─13588 php-fpm: pool www
Ставим MariaDB
По установке MariaDB есть хорошая статья на нашем сайте:
Настройка Master-Slave Replication на MariaDB (MySQL). Начало.
PHP приложение
Чтобы не придумывать велосипед, используем в качестве PHP приложения дистрибутив "wordpress". Ставим:
cd /var/www/ wget https://ru.wordpress.org/latest-ru_RU.tar.gz tar xvzf latest-ru_RU.tar.gz # если у вас каталог html, то надо перенести проект, у нас оставляем по умолчанию /var/www/wordpress cp -R /var/www/wordpress/* /var/www/html/ # сразу исправим права на каталог wordpress chmod ug+rwx wordpress chown -R www-data:www-data wordpress
2. Настройка конфигурационных файлов
/etc/nginx/nginx.conf
Узнаем количество процессоров в системе:
cat /proc/cpuinfo | grep processor | wc -l 2
Прежде всего надо настроить Nginx, для этого заходим в файл конфига "/etc/nginx/nginx.conf":
nano /etc/nginx/nginx.conf
Немного модифицируем файл (пояснения в коде):
# в Debian/Ubuntu веб-сервер работает от пользователя www-data и кол. рабочих процессов user www-data; worker_processes 2; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; # Первая опция задает количество соединений на рабочий процесс, вторая задает метод обработки соединений, явно укажем наиболее эффективный для Linux. events { worker_connections 1024; use epoll; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; # дополним: Они задают таймаут (в секундах) на чтение клиентом тела и заголовка запроса, последняя опция разрешает сброс соединений по таймауту. client_header_timeout 30; client_body_timeout 30; reset_timedout_connection on; # дополним: ограничивают максимальный размер тела запроса клиента и задают буфер для чтения заголовка запроса. client_max_body_size 32m; client_body_buffer_size 128k; # разрешим передачу файлов и оптимизируем этот процесс. sendfile on; tcp_nopush on; # было 65: keepalive_timeout 30; # зададим параметры gzip-сжатия: gzip on; gzip_disable "msie6"; gzip_proxied any; gzip_min_length 1024; gzip_comp_level 4; gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/atom+xml application/rdf+xml; include /etc/nginx/conf.d/*.conf; # добавим: include /etc/nginx/sites-enabled/*; }
Проверяем и перезагружаем:
nginx -t systemctl reload nginx
Создаем 2 папки. В первой будут хранится настройки сайтов, а во второй мы будем создавать символьные ссылки для того, чтобы подключить настройки сайта к конфигурационному файлу nginx:
mkdir /etc/nginx/sites-available mkdir /etc/nginx/sites-enabled
/etc/nginx/sites-available/wordpress.conf
Создадим конфигурационный файл для сайта:
nano /etc/nginx/sites-available/wordpress.conf
Заполняем:
server { # порт, прослушивающий nginx, default - по умолчанию. listen 80 default; # доменное имя, относящиеся к текущему виртуальному хосту, поддомен server_name 127.0.0.1; # кодировка по умолчанию charset utf-8; # каталог в котором лежит проект, путь к точке входа root /var/www/wordpress # root /var/www/html; # возможные имена индексных файлов index index.php; # расположение логов access_log /var/log/nginx/example.org_access.log; error_log /var/log/nginx/example.org_error.log; # файл конфигурации php-fpm, его заполним ниже по тексту статьи include /etc/nginx/templates/php-fpm.conf; } # для перенаправления сайта с www на без www можно прописать(мы не используем): #server { # listen 80; # server_name www.example.org; # rewrite ^(.*) http://example.org$1 permanent; #}
Сохраняем конфигурацию и подключаем ее к nginx:
ln -s /etc/nginx/sites-available/wordpress.conf /etc/nginx/sites-enabled/
/etc/php/7.3/fpm/php.ini
Настройки PHP-FPM по умолчанию достаточно оптимальны. Подправить некоторые опции PHP:
nano /etc/php/7.3/fpm/php.ini
Поправляем при необходимости следующие строки:
# задает максимальный размер данных загружаемых методом POST post_max_size = 8M # если кодировка CMS отлична от UTF-8, меняем этот параметр default_charset = "UTF-8" # закроет возможную уязвимость в PHP, если выставить 0, по умолчанию выключен с 1 cgi.fix_pathinfo=0 # размер максимально загружаемого файла upload_max_filesize = 8M
Можно перезагрузить PHP-FPM.
Теперь надо подружить "Nginx + PHP-FPM": для этого в файл конфигурации виртуального хоста нужно добавить настройки, которые будут перенаправлять (проксировать) все запросы к динамическому содержимому на FastCGI-шлюз.
/etc/nginx/templates/php-fpm.conf
Создадим директорию для хранения шаблонов, и создадим шаблон:
mkdir /etc/nginx/templates nano /etc/nginx/templates/php-fpm.conf
Заполним:
# блок location будет обрабатывать все запросы к php-файлам location ~ \.php$ { # проверка запрошенного файла, в противном случае выдаст ошибку 404 try_files $uri =404; # подключаем сокет php-fpm, параметр соединения с FastCGI-шлюзом fastcgi_pass unix:/var/run/php/php7.3-fpm.sock; # индексный файл fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } # в целях безопасности запрет к файлам htaccess location ~ /\.ht { deny all; } # кэширование статического содержимого location ~* \.(gif|jpeg|jpg|txt|png|tif|tiff|ico|jng|bmp|doc|pdf|rtf|xls|ppt|rar|rpm|swf|zip|bin|exe|dll|deb|cur)$ { expires 168h; } # кэширование для скриптов и стилей location ~* \.(css|js)$ { expires 180m; }
Перезагружаем PHP-FPM и Nginx.
3. Проверяем работу PHP
Для быстрой проверки создадим PHP файл:
cd /var/www/wordpress/ nano test.php
Содержимое:
<?php phpinfo(); ?>
Перезагружаем PHP-FPM и Nginx:
systemctl reload nginx php7.3-fpm
Проверяем, заходим на адрес:
127.0.0.1/test.php
На основном адресе 127.0.0.1 у нас висит wordpress:
В базе данных создадим саму базу и пользователя, далее внесем в wordpress:
mysql
> CREATE DATABASE wordpress;
> CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress';
> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'127.0.0.1';
Вводим данные в wordpress:
Дальше указываем название, пользователя, пароль, почту. Проверяем результат:
4. Пишем Dockerfile для нашего проекта PHP
Проект на PHP надо поместить в Docker файл с чем-то, в нашем случае это будет PHP-FPM. Тем самым по сути мы создаем Dockerfile с конфигурацией PHP-FPM под наш проект, а файлы самого проекта переносим внутрь. Это очень удобно, для запуска на других машинах, просто надо перенести Docker Images.
Выбираем директорию для проекта:
cd 100docker # скопируем PHP проект в текущую директорию cp /var/www/wordpress /{ваш путь}/100docker/ nano Dockerfile
Заполняем:
#------------------------------------------ # PHP-FPM Dockerfile and WWW wordpress #------------------------------------------ FROM php:7.3-fpm-alpine3.10 RUN apk update && apk add --no-cache php-bcmath \ mc \ nano \ php-json \ php-mbstring \ php-tokenizer \ php-xml \ php-curl \ php7-dev \ php7-dev \ libmemcached-dev \ libpng-dev \ zlib-dev \ && docker-php-ext-install gd mysqli WORKDIR /var/www/wordpress COPY wordpress/ . CMD ["php-fpm"]
Пояснения:
Собираем :
docker build -t wpfpm:n1 .
Проверяем:
docker images REPOSITORY TAG IMAGE ID CREATED SIZE wpfpm n1 174ad540bf87 17 minutes ago 212MB php 7.3-fpm-alpine3.10 7b9000ea0aaa 2 weeks ago 76.7MB
Оформим все в "docker-compose.yml":
ersion: '3.6' services: wordpress: image: wpfpm:n1 container_name: wordpress restart: always # PHP-FPM будет светить на 9000 порт по умолчанию # Данный пункт позволит объединиться с текущей сетью, а не создавать отдельную подсеть Docker network_mode: host
5. Настройка конфигов перед запуском из Docker:
Список действий:
Меняем конфиг "wordpress.conf", старый закомментировали для сравнения:
server { listen 80 default; server_name 127.0.0.1; root /var/www/wordpress; index index.php; # Обработка запросов # $uri - существует ли конкретный файл # $uri/ - существует ли директория # /index.php?$args - если это не запрос на существующий файл или директорию, то перебрасываем на роутер WordPress location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { root /var/www/wordpress; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_read_timeout 500; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } #server { # listen 80 default; # server_name 127.0.0.1; # charset utf-8; # root /var/www/wordpress; # index index.php; # access_log /var/log/nginx/example.org_access.log; # error_log /var/log/nginx/example.org_error.log; # include /etc/nginx/templates/php-fpm.conf; #}
6. Запускаем docker-compose
Можно приступить к проверке работы wordpress из Docker Images через docker-compose:
docker-compose up -d
Проверяем запущенные порты:
netstat -lptun Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 733/mysqld tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 16617/nginx: master tcp6 0 0 :::9000 :::* LISTEN 16575/php-fpm: mast ...
Как видим PHP-FPM запустился по умолчанию на 9000 порту. Проверяем отражения тестовой станицы и wordpress:
Как видно, тестовая страница работает без проблем. Страница с wordpress работает, но имеет некоторые недочеты в виде структуры. Напоминаем, данный wordpress запущен в среде Linux Alpine, который минимален. Правильно проверить PHP логи, и выловить недостающие модули. Включить их в Dockerfile. На этом останавливаться не будем, а перенесем Nginx в docker-compose:
version: '3.6' services: nginx: image: nginx container_name: nginx # ports: # - 80:80 # - 443:443 volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./default.conf:/etc/nginx/conf.d/default.conf:ro restart: always network_mode: host # links: # - app:app wordpress: image: wpfpm:n1 container_name: wordpress # ports: # - 9001:9000 volumes: - ./www.conf:/usr/local/etc/php-fpm.d/www.conf restart: always network_mode: host
Тормозим старый процесс:
# сначала тормозим wordpress docker stop wordpress && docker rm wordpress # потом убиваем systemctl stop nginx
Дальше делаем как и выше. Запускаем docker-compose и проверяем. Все работает так же.
Файлы включенные в docker-compose:
default.conf
server { listen 80; server_name 127.0.0.1; root /var/www/public; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { root /var/www/wordpress; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_read_timeout 500; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
nginx.conf
Тот же, что и в начале статьи.
www.conf
# Обратить внимание на эти строчки: listen = 127.0.0.1:9000 chdir = /var/www/wordpress/
7. Немного о Dockerfile, PECL, модулях, docker-php-ext-install
Зачем нужны расширения PHP на PECL?
PECL - это репозиторий нативных расширений, написанных на C. Обычно их используют, когда что-то нельзя реализовать на голом PHP, например перегрузку функций или операторов. К примеру: можно поставить API для memcache через него, а можно и через пакет в Ubuntu/Debian.
packagist - репозиторий PHP зависимостей, работают с ним через composer. Это must have для любого проекта.
PEAR - умер, вместо него используют composer/packagist.
Разбираем: "docker-php-ext-install" и "pecl"
"docker-php-ext-install" - этот скрипт используется для сборки "расширений" из кода в основном используется для установки основных расширений.
"pecl" - идентичный скрипт, но используется, если расширение уже опубликовано на pecl. В случае установки расширения через pecl необходимо установить путь к php.ini для pecl, выполнив:
pecl config-set php_ini " $ {PHP_INI_DIR} /php.ini "
Только после этого необходимо устанавливать через:
pecl install [extension]
Необходимо обратить внимание на следующий момент:
Команда "pecl install", в отличии от команды "docker-php-ext-install", не будет включать ваше расширение после установки. Поэтому необходимо использовать связку:
pecl install [extension] docker-php-ext-enable [extension]
Если вы не можете установить расширение через pecl, используйте docker-php-ext-install. Так же отметим, что скрипт docker-php-ext-configure выполняется автоматически в docker-php-ext-install , поэтому нет необходимости запускать его напрямую, если вы не хотите проходить через определенные флаги для ./configure .
Примерный список PHP Modules:
bcmath
bz2
calendar
Core
ctype
curl
date
dom
exif
fileinfo
filter
ftp
gd
gettext
hash
iconv
imagick
imap
intl
json
ldap
libxml
mbstring
memcached
mongodb
mysqli
mysqlnd
openssl
pcre
PDO
pdo_mysql
pdo_pgsql
pdo_sqlite
pgsql
Phar
posix
readline
redis
Reflection
session
SimpleXML
soap
sockets
sodium
SPL
sqlite3
standard
tokenizer
xdebug
xml
xmlreader
xmlrpc
xmlwriter
xsl
Zend OPcache
zip
zlib
Пример готового Dockerfile (к сборке не относится):
FROM php:7.3-fpm-alpine3.10 RUN apk update && apk add --no-cache php-bcmath \ mc \ ... libpng-dev \ zlib-dev \ && pecl config-set php_ini /etc/php7/php.ini \ && pecl install memcached redis uuid \ && pecl install http://pecl.php.net/get/geoip-1.1.1.tgz \ && docker-php-ext-install gd mysqli \ && docker-php-ext-enable memcached redis uuid geoip WORKDIR /var/www/wordpress COPY wordpress/ . CMD ["php-fpm"]
Всем спасибо кто читал, если есть дополнения, пишите комментарии.
Источник: http://linuxsql.ru