понедельник, 1 апреля 2024 г.

Установка web-сервера nginx с отдельными модулями php и mariadb с помощью docker

Создаем главную директорию проекта, где будут сложены все необходимые файлы и базы
# mkdir web-server
# cd web-server/

Создаем директории для проекта.
Под каждый контейнер своя директория для конфигов, и плюс директория data - для файлов и datadb для файлов базы данных.
# mkdir nginx
# mkdir php-fpm
# mkdir mariadb
# mkdir data
# mkdir datadb


Скачиваем образ nginx и php-fpm
# docker pull nginx
# docker pull bitnami/php-fpm
# docker pull mariadb


В директорию data кладем тестовые файлы index.html (любая страничка) и info.php (с функцией phpinfo();)
Пример файла index.html
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Заголовок</title>
  <link rel="stylesheet" href="./styles/style.css">
</head>
<body>
  <header>
    <h1>Сайт-тест HTTP NGINX-1</h1>
    <p>Просто какая-то информация</p>
  </header>
  <main>
     12345 АБВГДЕ, Основной блок информации
   </main>
   <footer>
       <p>footer (подвал), нижняя часть сайта</p>
   </footer>
    <!--подключение скриптов <script src="app.js"></script> -->
</body>
</html>


Содержимое файла info.php
<?php
    phpinfo();
?>


Нам необходимо выстроить конструкцию контейнеров, показанную на рисунке ниже

Основная папка с файлами проекта – это папка data, куда будем складывать файлы html и php.

В директорию nginx кладем типовой файл nginx.conf конфига nginx.

Главное, что нужно указать, это параметры директивы fastcgi_pass в блоке location ~ \.php$:
fastcgi_pass php-fpm:9000;
Директива fastcgi_pass задаёт адрес FastCGI-сервера, которому сервер nginx будет передавать php файлы для обработки. Тут указывается доменное имя и порт. 9000 – это стандартный порт, на котором работает сервер php-fpm. А доменное имя «php-fpm» - это доменное имя сервера php-fpm. В системе doker при старте контейнеров в каждом контейнере автоматически пропишутся все имена запущенных сервисов. И если будет запущен контейнер сервиса «php-fpm», то nginx будет знать его внутренний адрес по имени «php-fpm».
Второй важный момент – это директива
fastcgi_param SCRIPT_FILENAME /app$fastcgi_script_name;
Тут необходимо указать правильный путь до местонахождения файлов php. В контейнере, созданном на основе образа bitnami/php-fpm, это будет папка /app. Поэтому переменная SCRIPT_FILENAME должна начинаться с «/app».
В конфигурационном файле важные изменяемые значения выделены красным.
worker_processes 1;
pid /run/nginx.pid;
events {
  worker_connections 1024;
}
http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 4096;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        error_log /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
        location / {
             index index.php index.html index.htm;
        }
        location ~ \.php$ {
            fastcgi_pass php-fpm:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /app$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }
}

Директива «error_log /var/log/nginx/error.log;» определяет, куда сервер nginx будет складывать логи ошибок. Контейнер bitnami/php-fpm по умолчанию настроен так, что логи для записи передает для записи web-серверу, в данном случае nginx. И искать логи ошибок php нужно тоже в этом же файле /var/log/nginx/error.log.

Создаем файл docker-compose.yml, который описывает контейнеры nginx и php-fpm.
# touch web-server/docker-compose.yml
version: '3'
services:
    nginx:
        image: nginx
        container_name: nginx1
        ports:
            - 8080:80
        volumes:
            - ./data:/usr/share/nginx/html
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf
            - ./nginx/logs:/var/log/nginx/
        depends_on:
            - php-fpm
        networks:
            - internal
    
    php-fpm:
        image: bitnami/php-fpm
        container_name: php1
        volumes:
            - ./data:/app
         networks:
             - internal
    
networks:
    internal:
        driver: bridge
Из директории web-server запускаем контейнеры
# docker compose up --build
Параметр --build означает, что перед запуском контейнеров произойдет их сборка.

Теперь можно обратиться к web-серверу и прочитать тестовые файлы:
http://<IPадрес>:8080/
http://10.10.49.166:8080/info.php

Останавливаем контейнеры, нажав CTRL+C в командной строке, где запускали контейнеры (docker compose up --build)

Теперь запускаем контейнеры вместе с контейнером Mariadb. Для этого в docker-compose.yml добавляем новый сервис, работающий в новом контейнере:
    mariadb:
        image: mariadb
        container_name: mariadb1
        environment:
            MYSQL_ROOT_PASSWORD: rootpasswd
            MYSQL_DATABASE: mydb
            MYSQL_USER: user1
            MYSQL_PASSWORD: secret1
        command: mariadbd --log_error="/var/log/mysql/error.log"
        ports:
            - 3309:3306
        volumes:
            - ./datadb:/var/lib/mysql
            - ./mariadb/error.log:/var/log/mysql/error.log
        networks:
            - internal

Директива MYSQL_ROOT_PASSWORD: rootpasswd определить пароль для root пользователя базы данных SQL. Директивы MYSQL_DATABASE: mydb создаст базу данных mydb. Создание базы выполняется командой CREATE DATABASE IF NOT EXIST, поэтому если база mydb уже есть, она не будет создана снова.
Директивы MYSQL_USER: user1 и MYSQL_PASSWORD: secret1 создадут пользователя user1 с паролем secrtet1 и сделают его администратором базы, заданной в MYSQL_DATABASE.
Регистрация ошибок контейнера mariadb осуществляется по умолчанию через системный journal. Для того, что бы запись ошибок велась в отдельный файл, нужно в контейнере
в файле /etc/mysql/mariadb.conf.d/50-server.cnf раскомментировать строку:
log_error = /var/log/mysql/error.log. Но при пересборке контейнера это изменение потеряется. Поэтому пойдем другим путем. Создадим в основной системе файл для логов и разрешим писать туда пользователю из docker контейнера:
# touch mariadb/error.log
# chmod 777 mariadb/error.log

В секции command: пропишем команду, которая заставит демон mariadb включить запись лого в файл: mariadbd --log_error="/var/log/mysql/error.log"
И затем в секции volumes примонтируем внутренний файл контейнера «/var/log/mysql/error.log» к файлу основной операционной системы «mariadb/error.log»
Теперь логи mariadb будут записываться в файл в основной операционной системе.

После редактирования файла docker-compose.yml запускаем контейнеры:
# docker compose up --build
Из другой консоли пытаемся подключиться к базе:
# /usr/bin/mariadb -h127.0.0.1 --port=3309 -uroot –p
Вводим пароль из директивы MYSQL_ROOT_PASSWORD и мы в консоли mariadb под рутом.
Можно так же подключиться под именем user1 и паролем secret1
# /usr/bin/mariadb -h127.0.0.1 --port=3309 -u user1 -psecret1
Проверяем, создалась ли база mydb?
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb |
+--------------------+
2 rows in set (0.001 sec)
Все в порядке, база есть.
Создадим простую таблицу и внесем туда одну строку для теста
> USE mydb;
> CREATE TABLE table_test (a int, b varchar(10));
> INSERT table_test VALUES(1,'mytext');

Эта информация останется в базе даже после перезагрузки контейнеров, так как файлы базы подключаются при старте контейнера из основной системы

Создадим файл dbtest.php в папке data, который будет подключаться к базе данных и выводить данные из таблицу table_test
<?php
    $mysqli = new mysqli("mariadb", "user1", "secret1", "mydb");
    if (mysqli_connect_errno()) {
        echo "Ошибка: ", mysqli_connect_error();
        exit;
    } else {
        echo "Соединение установлено<br>";
    }
   $query="SELECT a, b FROM table_test ";
   $result = $mysqli->query($query) or die("Ошибка запроса");
   echo "Данные из базы:<br>";
   while($z=$result->fetch_row()) {
       echo "a: ".$z[0].", b: ".$z[1];
   }
?>

В качестве имени сервера, к которому нужно обращаться в php указываем имя сервиса из описания контейнера в файле docker-compose.yml.
$mysqli = new mysqli("mariadb", "user1", "secret1", "mydb");
Теперь обратившись по URL мы увидим информацию из базы данных:
http://10.10.49.166:8080/dbtest.php

Следующие запуски можно выполнять так

# docker compose up
Запуск в режиме демона:
# docker compose up –d

Остановка контейнеров:

# docker stop mariadb1

Запуск контейнера:

# docker start mariadb1

Остановка всех контейнеров:

# docker compose down

Просмотр состояния контейнеров

# docker compose ps

Вход в контейнеры:

# docker exec -it nginx1 /bin/bash
# docker exec -it php1 /bin/bash
# docker exec -it mariadb1 /bin/bash


Просмотр логов контейнеров:
# docker compose logs -f nginx
# docker compose logs -f mariadb
# docker compose logs -f php-fpm


1 комментарий:

  1. Привет, благодарю за статью!
    Именно та сборка, которую Я искал.
    Только Я еще php.ini вынес из php-fpm в volumes
    php-fpm:
    image: bitnami/php-fpm
    container_name: php1
    volumes:
    - ./html:/app
    - ./php-fpm/php.ini:/opt/bitnami/php/etc/php.ini # <<<<<
    networks:
    - internal
    для установки "opcache.enable = Off", для отключения кеширования страниц, чтобы при изменении *.php - файлов изменения сразу отображались в web-browsere.

    ОтветитьУдалить