Docker-compose настройка для сайта NGINX + MYSQL + PHP-FPM

Материал из Wiki МИАЦ ВО
Перейти к навигации Перейти к поиску

Основа статьи взята тут.
У нас есть сайт, который мы хотим быстро перенести на другой сервер. Для этого мы будем использовать docker + docker-compose

Что будет уметь наша сборка?

Простейшая среда разработки на php включает в себя следующие компоненты:

  1. Собственно сам PHP, последний стабильный релиз 7.4;
  2. Composer
  3. Mysql, последняя стабильная версия 8;
  4. Nginx

Также наша конфигурация будет поддерживать сколько угодно хостов nginx (см. проектов). Добавление новых компонентов в стек обычно не составляет труда.

Файловая структура

Переходим к организации папок и файлов нашей сборки. Создадим на диске какую-нибудь директорию, которая будет корневой для нашей сборки и в ней по порядку создаем следующие директории:

  1. www - в этой папке будут лежать файлы наших проектов, по директории на каждый проект;
  2. mysql и mysql-files - в этой папке будут храниться файлы наших баз данных;
  3. logs - здесь будет собриать логи из разных образов. В ней расположены 2 папки mysql и nginx;
  4. hosts - здесь будут храниться файлы конфигурации nginx для наших проектов;
  5. etc/mysql - здесь будут хранится настройки mysql;
  6. images - папка с нашими образами - компонентами нашей системы.

Еще не помешает создать дефолтный проект, чтобы проверить работоспособность нашей сборки когда все запустится. В директории www создадим директорию тестового проекта - hello.dev с одим единственным файлом index.php. Содердимое файла index.php классическое:

<?php phpinfo();

Также в корне будет лежать наш docker-compose.yml - сердце любой docker-конфигурации :)

Настройки mysql

По умолчанию, подключиться к mysql серверу можно только локально и к докеру. А если мы хотим, что бы можно было подключиться к mesql, например, с помощью HeidiSQL, нам нужно в файл конфигурации my.cnf добавить строки. Создаем в папке etc/mysql/ файл my.cnf и заносим туда следующие данные.

[mysqld]
#
# * Basic Settings
#
#bind-address		= 127.0.0.1
bind-address		= 0.0.0.0
# Error log - should be very few entries.
log_error = /var/log/mysql/error.log
slow_query_log		= 1
slow_query_log_file	= /var/log/mysql/mysql-slow.log

Можно добавить все нужные для mysql настройки.

Собираем образ PHP

Стандартный официальный образ PHP не включает в себя никаких модулей, поэтому чтобы включить их нужно собрать свой образ на основе официального. Звучит немного страшновато, но на деле все просто. Создаем директорию для нашего образа images/php и в ней создаем файл Dockerfile следующего содержания:

# Для начала указываем исходный образ, он будет использован как основа
FROM php:7.4-fpm
# Необязательная строка с указанием автора образа
MAINTAINER PHPtoday.ru <info@phptoday.ru>

# RUN выполняет идущую за ней команду в контексте нашего образа.
# В данном случае мы установим некоторые зависимости и модули PHP.
# Для установки модулей используем команду docker-php-ext-install.
# На каждый RUN создается новый слой в образе, поэтому рекомендуется объединять команды.
RUN apt-get update && apt-get install -y \
        curl \
        wget \
        git \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
	libpng-dev \
	libonig-dev \
	libzip-dev \
	libmcrypt-dev \
        && pecl install mcrypt-1.0.3 \
	&& docker-php-ext-enable mcrypt \
        && docker-php-ext-install -j$(nproc) iconv mbstring mysqli pdo_mysql zip \
	&& docker-php-ext-configure gd --with-freetype --with-jpeg \
        && docker-php-ext-install -j$(nproc) gd 

# Куда же без composer'а.
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Добавим свой php.ini, можем в нем определять свои значения конфига
ADD php.ini /usr/local/etc/php/conf.d/40-custom.ini

# Указываем рабочую директорию для PHP
WORKDIR /var/www

# Запускаем контейнер
# Из документации: The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, 
# or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.
CMD ["php-fpm"]

Также в этой папке создадим пока пустой php.ini, чтобы не было ошибки при сборке образа. Можете добавить в него нужные вам настройки.
Вот мой файл php.ini

;было error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT
;было display_errors = of
display_errors = on
;Разрешить сокращенные теги
;было short_open_tag = of
short_open_tag = on
;было post_max_size = 8M
post_max_size = 200M
;было upload_max_filesize = 2M
upload_max_filesize = 200M
;Если не указать тайм зону, то будут сыпаться ошибки.
;было ;date.timezone = 
date.timezone = Europe/Moscow
;заремарить следующую строку, иначе письма будут терять поле FROM
mail.add_x_header = of

Docker Compose

Docker compose сильно упрощает жизнь если у вас больше одного контейнера. С помощью одного (иногда нескольких) конфигурационных файлов формата yml вы описываете какие у вас будут запускаться контейнеры, их настройки, то как они будут между собой взаимодействовать и так далее. Начиная со второй версии docker compose поддерживает наследование и можно с его помощью описывать разные конфигурации для разных окружений. Мы сейчас не будем заострять на этом внимание, у нас одно окружение и один файл. Создадим в корне docker-compose.yml.

# Версия docker-compose
version: '3'
# Список наших сервисов (контейнеров)
services:
    nginx:
        # используем последний стабильный образ nginx
        image: nginx:latest
        # маршрутизируем порты
        ports:
            - "80:80"
            - "443:443"
        # монтируем директории, слева директории на основной машине, справа - куда они монтируются в контейнере
        volumes:
            - ./hosts:/etc/nginx/conf.d
            - ./www:/var/www
            - ./logs/nginx:/var/log/nginx
        # nginx должен общаться с php контейнером
        links:
            - php
    php:
        # у нас свой образ для PHP, указываем путь к нему и говорим что его надо собрать
        build: ./images/php
        # этот образ будет общаться с mysql
        links:
            - mysql
        # монтируем директорию с проектами
        volumes:
            - ./www:/var/www
    mysql:
        image: mysql
        ports:
            - "3306:3306"
        volumes:
         - /etc/mysql:/etc/mysql
         - ./logs/mysql:/var/log/mysql
         - ./mysql:/var/lib/mysql
         - ./mysql-files:/var/lib/mysql-files
         - ./data:/docker-entrypoint-initdb.d
        # задаем пароль для root пользователя
        # заливку дампа сайта и создание пользователя для доступа к базе снаружи будем делать позже 
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_DATABASE: sait
- ./data:/docker-entrypoint-initdb.d

В описании докера написано, что, если в локальую папку, которая мапится на /docker-entrypoint-initdb.d, положить sql или bash файлы, то они будут выполнены после разворачивания mysql. У меня почему то - не получилось. Использовал метод, описанный ниже.

Конфигурация nginx для проектов

Раньше мы уже создали тестовый проект hello.dev, давайте добавим для него конфиг nginx. В папке hosts создадим файл с названием hello-dev.conf:

server {
    index index.php;
    server_name hello.dev;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/hello.dev;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Конфиг nginx для докер-контейнера ничем не отличается от обычного конфига для сайта. Стоит лишь обратить внимание на директиву fastcgi_pass, где мы используем не путь к unix-сокету, а адрес php:9000. Здесь присутствует немного магии docker'а: php - это хост по которому доступен наш php контейнер внутри контейнера nginx, ну а 9000 - порт, по которому можно достучаться до fpm-сокета.

Run the magic!

Мы набросали минимальную конфигурацию для локальной среды разработки и можем ее смело запускать. Для этого из корня нашей сборки, где лежит docker-compose.yml файл нужно выполнить команду

$docker-compose up -d 

и немного подождать. Первый запуск будет дольше, потому что docker'у нужно скачать образы и собрать образ для php.
В конце концов мы увидим заветные строчки:

Starting source_mysql_1 ... 
Starting source_mysql_1 ... done
Starting source_php_1 ... 
Starting source_php_1 ... done
Starting source_nginx_1 ... 
Starting source_nginx_1 ... done

Они говорят нам что наши три контейнера запущены и готовы к работе. Проверимс... Для этого откроем браузер и перейдем по адресу http://hello.dev/, но сперва добавим одну строку в hosts файл.

127.0.0.1 hello.dev

Важно для windows и mac адрес 127.0.0.1 нужно заменить на адрес виртуальной машины, в которой запускается докер, потому что нативной поддержки пока нет или она очень унылая.

Заливка дампа для создания пользователя базы данных и данных для сайта

Долго искал способ быстрой заливки дампа mysql в docker и нашел способ, как снаружи можно залить дамп внутрь докера. И так:
В папке ./data положим два файла
Первый создает пользователя mysql для доступа к база снаружи (user.sql)

CREATE USER 'user'@'%' IDENTIFIED BY 'user_password';
GRANT EXECUTE, PROCESS, SELECT, SHOW DATABASES, SHOW VIEW, ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TABLESPACE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT,INDEX, INSERT, REFERENCES, TRIGGER, UPDATE, CREATE USER, FILE, LOCK TABLES, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHUTDOWN, SUPER  ON *.* TO 'user'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

Где

user - пользователь базы данных
user-password - его пароль

Второй - это дамп сайта (sait.sql)

Добавляем пакет pv, если не был добавлен. Пакет нужен для наглядной заливки дампа, особенно если дамп большой.

$ sudo apt install pv

Сборку докера и заливку базы данных будем делать из следующего скрипта (docker_load.sh) Он создает контейнеры, создает пользователя с доступом из сети и заливает дамп базы данных сайта.

docker-compose up -d
sleep 10
cat data/user.sql | docker exec -i test_mysql_1 mysql -uroot -password
cat data/sait.sql |pv | docker exec -i test_mysql_1 mysql -uroot -password --init-command="SET autocommit=0  sait;"

где

data/user.sql - путь до файла с дампом на сервере
test_mysql_1 - имя докера mysql
sait - база данных сайта
data/sait.sql - дамп базы сайта

Сохраняем файл, делаем исполняемым и запускаем.

Наша среда готова для работы. Можно легко добавлять новые проекты - просто создаем новую папку для проекта в www и добавляем новый конфиг для nginx, перезаускаем контейнеры и вперед!