You are here

Пакуем PHP приложение в Dockerfile со всеми пояснениями

Пакуем PHP приложение в Dockerfile со всеми пояснениями

Если вы уже читали как запустить "Nginx + PHP-FPM" + "MySQL", то после этого на должности DevOps инженера вы скорее всего столкнетесь с вопросом, а как запаковать PHP приложение в Dockerfile? На этот вопрос и многое другое, ответим в данной статье!

1. Ставим "Nginx + PHP-FPM" + "MySQL

У нас Debian 10, все примеры ниже на данной версии Linux. В других сборках - суть та же. Начнем с установки в Debian, потом перенесем в Docker. Простейшие моменты будем пропускать. Статья будет длинная, чтобы понять все от и до. Приступим:

Ставим Nginx:

  1. sudo apt update
  2. apt install nginx
  3. systemctl start nginx
  4. systemctl status nginx
  5. ● nginx.service - nginx - high performance web server
  6. Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
  7. Active: active (running) since Wed 2019-11-06 21:49:47 +05; 1s ago
  8. Docs: http://nginx.org/en/docs/
  9. Process: 4143 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
  10. Main PID: 4144 (nginx)
  11. Tasks: 2 (limit: 4915)
  12. Memory: 2.1M
  13. CGroup: /system.slice/nginx.service
  14. ├─4144 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
  15. └─4145 nginx: worker process

Проверяем:

  1. curl -I 127.0.0.1
  2. HTTP/1.1 200 OK
  3. Server: nginx/1.17.5
  4. Date: Wed, 06 Nov 2019 16:51:48 GMT
  5. Content-Type: text/html
  6. Content-Length: 612
  7. Last-Modified: Tue, 22 Oct 2019 14:30:00 GMT
  8. Connection: keep-alive
  9. ETag: "5daf1268-264"
  10. Accept-Ranges: bytes

Полезные файлы и директории:

  1. /etc/nginx
  2. /etc/nginx/nginx.conf
  3. /etc/nginx/sites-enabled/
  4. /etc/nginx/sites-available/
  5. /var/log/nginx/

* Можете воспользоваться статьей, для установки через Ansible: Playbook: Блоки, условия и циклы. Lesson 7

Ставим PHP-FPM

  1. apt install php-fpm
  2. apt install php-mysql php-bcmath php-json php-mbstring php-tokenizer php-xml php-curl
  3. # для работы с графикой можно поставить доп модули:
  4. apt-get install php7.3-gd php7.3-imagick

Проверяем:

  1. systemctl status php7.3-fpm
  2. ● php7.3-fpm.service - The PHP 7.3 FastCGI Process Manager
  3. Loaded: loaded (/lib/systemd/system/php7.3-fpm.service; enabled; vendor preset: enabled)
  4. Active: active (running) since Wed 2019-11-06 22:30:53 +05; 1min 9s ago
  5. Docs: man:php-fpm7.3(8)
  6. Main PID: 13586 (php-fpm7.3)
  7. Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
  8. Tasks: 3 (limit: 4915)
  9. Memory: 14.9M
  10. CGroup: /system.slice/php7.3-fpm.service
  11. ├─13586 php-fpm: master process (/etc/php/7.3/fpm/php-fpm.conf)
  12. ├─13587 php-fpm: pool www
  13. └─13588 php-fpm: pool www

Ставим MariaDB

По установке MariaDB есть хорошая статья на нашем сайте:
Настройка Master-Slave Replication на MariaDB (MySQL). Начало.

PHP приложение

Чтобы не придумывать велосипед, используем в качестве PHP приложения дистрибутив "wordpress". Ставим:

  1. cd /var/www/
  2. wget https://ru.wordpress.org/latest-ru_RU.tar.gz
  3. tar xvzf latest-ru_RU.tar.gz
  4. # если у вас каталог html, то надо перенести проект, у нас оставляем по умолчанию /var/www/wordpress
  5. cp -R /var/www/wordpress/* /var/www/html/
  6. # сразу исправим права на каталог wordpress
  7. chmod ug+rwx wordpress
  8. chown -R www-data:www-data wordpress

2. Настройка конфигурационных файлов

/etc/nginx/nginx.conf

Узнаем количество процессоров в системе:

  1. cat /proc/cpuinfo | grep processor | wc -l
  2. 2

Прежде всего надо настроить Nginx, для этого заходим в файл конфига "/etc/nginx/nginx.conf":

  1. nano /etc/nginx/nginx.conf

Немного модифицируем файл (пояснения в коде):

  1. # в Debian/Ubuntu веб-сервер работает от пользователя www-data и кол. рабочих процессов
  2. user www-data;
  3. worker_processes 2;
  4.  
  5. error_log /var/log/nginx/error.log warn;
  6. pid /var/run/nginx.pid;
  7.  
  8. # Первая опция задает количество соединений на рабочий процесс, вторая задает метод обработки соединений, явно укажем наиболее эффективный для Linux.
  9. events {
  10. worker_connections 1024;
  11. use epoll;
  12. }
  13.  
  14.  
  15. http {
  16. include /etc/nginx/mime.types;
  17. default_type application/octet-stream;
  18.  
  19. log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  20. '$status $body_bytes_sent "$http_referer" '
  21. '"$http_user_agent" "$http_x_forwarded_for"';
  22.  
  23. access_log /var/log/nginx/access.log main;
  24.  
  25. # дополним: Они задают таймаут (в секундах) на чтение клиентом тела и заголовка запроса, последняя опция разрешает сброс соединений по таймауту.
  26. client_header_timeout 30;
  27. client_body_timeout 30;
  28. reset_timedout_connection on;
  29.  
  30. # дополним: ограничивают максимальный размер тела запроса клиента и задают буфер для чтения заголовка запроса.
  31. client_max_body_size 32m;
  32. client_body_buffer_size 128k;
  33.  
  34. # разрешим передачу файлов и оптимизируем этот процесс.
  35. sendfile on;
  36. tcp_nopush on;
  37.  
  38. # было 65:
  39. keepalive_timeout 30;
  40.  
  41. # зададим параметры gzip-сжатия:
  42. gzip on;
  43. gzip_disable "msie6";
  44. gzip_proxied any;
  45. gzip_min_length 1024;
  46. gzip_comp_level 4;
  47. 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;
  48.  
  49. include /etc/nginx/conf.d/*.conf;
  50.  
  51. # добавим:
  52. include /etc/nginx/sites-enabled/*;
  53.  
  54. }

Проверяем и перезагружаем:

  1. nginx -t
  2. systemctl reload nginx

Создаем 2 папки. В первой будут хранится настройки сайтов, а во второй мы будем создавать символьные ссылки для того, чтобы подключить настройки сайта к конфигурационному файлу nginx:

  1. mkdir /etc/nginx/sites-available
  2. mkdir /etc/nginx/sites-enabled

/etc/nginx/sites-available/wordpress.conf

Создадим конфигурационный файл для сайта:

  1. nano /etc/nginx/sites-available/wordpress.conf

Заполняем:

  1. server {
  2. # порт, прослушивающий nginx, default - по умолчанию.
  3. listen 80 default;
  4.  
  5. # доменное имя, относящиеся к текущему виртуальному хосту, поддомен
  6. server_name 127.0.0.1;
  7. # кодировка по умолчанию
  8. charset utf-8;
  9.  
  10. # каталог в котором лежит проект, путь к точке входа
  11. root /var/www/wordpress
  12. # root /var/www/html;
  13. # возможные имена индексных файлов
  14. index index.php;
  15.  
  16. # расположение логов
  17. access_log /var/log/nginx/example.org_access.log;
  18. error_log /var/log/nginx/example.org_error.log;
  19. # файл конфигурации php-fpm, его заполним ниже по тексту статьи
  20. include /etc/nginx/templates/php-fpm.conf;
  21. }
  22.  
  23. # для перенаправления сайта с www на без www можно прописать(мы не используем):
  24. #server {
  25.  
  26. # listen 80;
  27.  
  28. # server_name www.example.org;
  29. # rewrite ^(.*) http://example.org$1 permanent;
  30. #}

Сохраняем конфигурацию и подключаем ее к nginx:

  1. ln -s /etc/nginx/sites-available/wordpress.conf /etc/nginx/sites-enabled/

/etc/php/7.3/fpm/php.ini

Настройки PHP-FPM по умолчанию достаточно оптимальны. Подправить некоторые опции PHP:

  1. nano /etc/php/7.3/fpm/php.ini

Поправляем при необходимости следующие строки:

  1. # задает максимальный размер данных загружаемых методом POST
  2. post_max_size = 8M
  3. # если кодировка CMS отлична от UTF-8, меняем этот параметр
  4. default_charset = "UTF-8"
  5. # закроет возможную уязвимость в PHP, если выставить 0, по умолчанию выключен с 1
  6. cgi.fix_pathinfo=0
  7. # размер максимально загружаемого файла
  8. upload_max_filesize = 8M

Можно перезагрузить PHP-FPM.

Теперь надо подружить "Nginx + PHP-FPM": для этого в файл конфигурации виртуального хоста нужно добавить настройки, которые будут перенаправлять (проксировать) все запросы к динамическому содержимому на FastCGI-шлюз.

/etc/nginx/templates/php-fpm.conf

Создадим директорию для хранения шаблонов, и создадим шаблон:

  1. mkdir /etc/nginx/templates
  2. nano /etc/nginx/templates/php-fpm.conf

Заполним:

  1. # блок location будет обрабатывать все запросы к php-файлам
  2. location ~ \.php$ {
  3. # проверка запрошенного файла, в противном случае выдаст ошибку 404
  4. try_files $uri =404;
  5. # подключаем сокет php-fpm, параметр соединения с FastCGI-шлюзом
  6. fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
  7. # индексный файл
  8. fastcgi_index index.php;
  9. include fastcgi_params;
  10. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  11. }
  12.  
  13. # в целях безопасности запрет к файлам htaccess
  14. location ~ /\.ht {
  15. deny all;
  16. }
  17.  
  18. # кэширование статического содержимого
  19. 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)$ {
  20. expires 168h;
  21. }
  22.  
  23. # кэширование для скриптов и стилей
  24. location ~* \.(css|js)$ {
  25. expires 180m;
  26. }

Перезагружаем PHP-FPM и Nginx.

3. Проверяем работу PHP

Для быстрой проверки создадим PHP файл:

  1. cd /var/www/wordpress/
  2. nano test.php

Содержимое:

  1. <?php
  2. phpinfo();
  3. ?>

Перезагружаем PHP-FPM и Nginx:

  1. systemctl reload nginx php7.3-fpm

Проверяем, заходим на адрес:
127.0.0.1/test.php

Пакуем PHP приложение в Dockerfile со всеми пояснениями

На основном адресе 127.0.0.1 у нас висит wordpress:

Пакуем PHP приложение в Dockerfile со всеми пояснениями

В базе данных создадим саму базу и пользователя, далее внесем в wordpress:
mysql
> CREATE DATABASE wordpress;
> CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'wordpress';
> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'127.0.0.1';

Вводим данные в wordpress:

  • wordpress
  • wordpress
  • wordpress
  • 127.0.0.1
  • wp_

Дальше указываем название, пользователя, пароль, почту. Проверяем результат:

Пакуем PHP приложение в Dockerfile со всеми пояснениями

4. Пишем Dockerfile для нашего проекта PHP
Проект на PHP надо поместить в Docker файл с чем-то, в нашем случае это будет PHP-FPM. Тем самым по сути мы создаем Dockerfile с конфигурацией PHP-FPM под наш проект, а файлы самого проекта переносим внутрь. Это очень удобно, для запуска на других машинах, просто надо перенести Docker Images.

Выбираем директорию для проекта:

  1. cd 100docker
  2. # скопируем PHP проект в текущую директорию
  3. cp /var/www/wordpress /{ваш путь}/100docker/
  4. nano Dockerfile

Заполняем:

  1. #------------------------------------------
  2. # PHP-FPM Dockerfile and WWW wordpress
  3. #------------------------------------------
  4.  
  5. FROM php:7.3-fpm-alpine3.10
  6.  
  7. RUN apk update && apk add --no-cache php-bcmath \
  8. mc \
  9. nano \
  10. php-json \
  11. php-mbstring \
  12. php-tokenizer \
  13. php-xml \
  14. php-curl \
  15. php7-dev \
  16. php7-dev \
  17. libmemcached-dev \
  18. libpng-dev \
  19. zlib-dev \
  20. && docker-php-ext-install gd mysqli
  21.  
  22. WORKDIR /var/www/wordpress
  23.  
  24. COPY wordpress/ .
  25.  
  26. CMD ["php-fpm"]

Пояснения:

  • FROM - образ на основе которого будем собирать Dockerfile
  • RUN - установка пакетов, в том числе для обеспечения среды внутри контейнера
  • WORKDIR - создать и сделать основной
  • COPY - скопировать из директории в основную
  • CMD - запуск

Собираем :

  1. docker build -t wpfpm:n1 .

Проверяем:

  1. docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. wpfpm n1 174ad540bf87 17 minutes ago 212MB
  4. php 7.3-fpm-alpine3.10 7b9000ea0aaa 2 weeks ago 76.7MB

Оформим все в "docker-compose.yml":

  1. ersion: '3.6'
  2. services:
  3.  
  4. wordpress:
  5. image: wpfpm:n1
  6. container_name: wordpress
  7. restart: always
  8. # PHP-FPM будет светить на 9000 порт по умолчанию
  9. # Данный пункт позволит объединиться с текущей сетью, а не создавать отдельную подсеть Docker
  10. network_mode: host

5. Настройка конфигов перед запуском из Docker:
Список действий:

  • Удаляем каталог /var/www/wordpress, чтобы исключить запуск PHP с текущей машины
  • Останавливаем процесс PHP-FPM: "systemctl stop php7.3-fpm", он на сокет'е, портом не светит
  • Меняем настройки конфига: /etc/nginx/sites-available/wordpress.conf
  • Делаем рестарт "systemctl reload nginx"
  • Проверяем на внешнем и внутреннем IP

Меняем конфиг "wordpress.conf", старый закомментировали для сравнения:

  1. server {
  2. listen 80 default;
  3. server_name 127.0.0.1;
  4. root /var/www/wordpress;
  5. index index.php;
  6.  
  7. # Обработка запросов
  8. # $uri - существует ли конкретный файл
  9. # $uri/ - существует ли директория
  10. # /index.php?$args - если это не запрос на существующий файл или директорию, то перебрасываем на роутер WordPress
  11. location / {
  12. try_files $uri $uri/ /index.php?$args;
  13. }
  14.  
  15. location ~ \.php$ {
  16. root /var/www/wordpress;
  17. fastcgi_pass 127.0.0.1:9000;
  18. fastcgi_index index.php;
  19. fastcgi_read_timeout 500;
  20. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  21. include fastcgi_params;
  22. }
  23. }
  24.  
  25.  
  26. #server {
  27. # listen 80 default;
  28.  
  29. # server_name 127.0.0.1;
  30. # charset utf-8;
  31.  
  32. # root /var/www/wordpress;
  33. # index index.php;
  34.  
  35. # access_log /var/log/nginx/example.org_access.log;
  36. # error_log /var/log/nginx/example.org_error.log;
  37.  
  38. # include /etc/nginx/templates/php-fpm.conf;
  39.  
  40. #}

6. Запускаем docker-compose

Можно приступить к проверке работы wordpress из Docker Images через docker-compose:

  1. docker-compose up -d

Проверяем запущенные порты:

  1. netstat -lptun
  2. Active Internet connections (only servers)
  3. Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
  4. tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 733/mysqld
  5. tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 16617/nginx: master
  6. tcp6 0 0 :::9000 :::* LISTEN 16575/php-fpm: mast
  7. ...

Как видим PHP-FPM запустился по умолчанию на 9000 порту. Проверяем отражения тестовой станицы и wordpress:

Пакуем PHP приложение в Dockerfile со всеми пояснениями

Как видно, тестовая страница работает без проблем. Страница с wordpress работает, но имеет некоторые недочеты в виде структуры. Напоминаем, данный wordpress запущен в среде Linux Alpine, который минимален. Правильно проверить PHP логи, и выловить недостающие модули. Включить их в Dockerfile. На этом останавливаться не будем, а перенесем Nginx в docker-compose:

  1. version: '3.6'
  2. services:
  3. nginx:
  4. image: nginx
  5. container_name: nginx
  6. # ports:
  7. # - 80:80
  8. # - 443:443
  9. volumes:
  10. - ./nginx.conf:/etc/nginx/nginx.conf:ro
  11. - ./default.conf:/etc/nginx/conf.d/default.conf:ro
  12. restart: always
  13. network_mode: host
  14. # links:
  15. # - app:app
  16.  
  17. wordpress:
  18. image: wpfpm:n1
  19. container_name: wordpress
  20. # ports:
  21. # - 9001:9000
  22. volumes:
  23. - ./www.conf:/usr/local/etc/php-fpm.d/www.conf
  24.  
  25. restart: always
  26. network_mode: host

Тормозим старый процесс:

  1. # сначала тормозим wordpress
  2. docker stop wordpress && docker rm wordpress
  3. # потом убиваем
  4. systemctl stop nginx

Дальше делаем как и выше. Запускаем docker-compose и проверяем. Все работает так же.

Файлы включенные в docker-compose:

default.conf

  1. server {
  2. listen 80;
  3. server_name 127.0.0.1;
  4. root /var/www/public;
  5. index index.php;
  6.  
  7. location / {
  8. try_files $uri $uri/ /index.php?$args;
  9. }
  10.  
  11. location ~ \.php$ {
  12. root /var/www/wordpress;
  13. fastcgi_pass 127.0.0.1:9000;
  14. fastcgi_index index.php;
  15. fastcgi_read_timeout 500;
  16. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  17. include fastcgi_params;
  18. }
  19. }

nginx.conf
Тот же, что и в начале статьи.

www.conf

  1. # Обратить внимание на эти строчки:
  2. listen = 127.0.0.1:9000
  3. 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, выполнив:

  1. pecl config-set php_ini " $ {PHP_INI_DIR} /php.ini "

Только после этого необходимо устанавливать через:

  1. pecl install [extension]

Необходимо обратить внимание на следующий момент:
Команда "pecl install", в отличии от команды "docker-php-ext-install", не будет включать ваше расширение после установки. Поэтому необходимо использовать связку:

  1. pecl install [extension]
  2. 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 (к сборке не относится):

  1. FROM php:7.3-fpm-alpine3.10
  2.  
  3. RUN apk update && apk add --no-cache php-bcmath \
  4. mc \
  5. ...
  6. libpng-dev \
  7. zlib-dev \
  8. && pecl config-set php_ini /etc/php7/php.ini \
  9. && pecl install memcached redis uuid \
  10. && pecl install http://pecl.php.net/get/geoip-1.1.1.tgz \
  11. && docker-php-ext-install gd mysqli \
  12. && docker-php-ext-enable memcached redis uuid geoip
  13.  
  14. WORKDIR /var/www/wordpress
  15.  
  16. COPY wordpress/ .
  17.  
  18. CMD ["php-fpm"]

Всем спасибо кто читал, если есть дополнения, пишите комментарии.

Источник: http://linuxsql.ru