Initial commit

This commit is contained in:
2025-10-28 01:39:22 +03:00
commit 8d1473935a
23 changed files with 870 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
# Ignore local environment files
.env*
# Ignore logs
logs/
# Common OS/editor junk
.DS_Store
Thumbs.db
*.swp

108
README.md Normal file
View File

@@ -0,0 +1,108 @@
# Nginx + PHP-FPM (API v1/v2) + PostgreSQL + Memcached
Проект разворачивает два API (v1 и v2) на отдельных контейнерах PHP-FPM, фронтирует их через Nginx и подключает PostgreSQL и Memcached. Конфигурация рассчитана на локальную разработку и может быть адаптирована для staging/production.
## Возможности
- Два независимых API: `/api/v1/` и `/api/v2/`.
- Nginx проксирует запросы к соответствующим пулам PHP-FPM.
- Проверки соединений с PostgreSQL и Memcached в каждом API.
- Разделённые логи для Nginx и каждого PHP-FPM.
- Переменные окружения вынесены в `.env` файлы (безопаснее, чем хранить пароли в compose).
## Требования
- Установленный Docker Desktop (Windows/macOS) или Docker Engine (Linux).
- Docker Compose v2 (входит в Docker Desktop).
## Быстрый запуск (локально)
1. Открой папку проекта: `c:\docker\nginxphp\server\project`.
2. Убедись, что созданы и заполнены файлы:
- `.env.v1` — переменные для API v1
- `.env.v2` — переменные для API v2
- `.env.db` — переменные для PostgreSQL
Пример значений уже положен в репозиторий (локальные пароли можно заменить).
3. Запусти:
```powershell
docker compose up -d --build
```
4. Проверь эндпоинты:
- `http://localhost/api/v1/`
- `http://localhost/api/v2/`
Оба вернут JSON со статусами PostgreSQL и Memcached, версией API и PHP.
## Структура
- `docker-compose.yml` — оркестрация контейнеров.
- `nginx/nginx.conf` — маршрутизация `/api/v1` и `/api/v2` к нужным upstream (PHP-FPM v1/v2).
- `api-v1/` — Dockerfile, конфиги PHP-FPM (`config`), код (`index.php`).
- `api-v2/` — Dockerfile, конфиги PHP-FPM (`config`), код (`index.php`).
- `database/init/01_init.sql` — создаёт БД `api_v1` и `api_v2`, выдаёт права `api_user`.
- `logs/nginx`, `logs/php-v1`, `logs/php-v2` — каталоги для логов.
- `.env.v1`, `.env.v2`, `.env.db` — переменные окружения для сервисов.
- `.gitignore` — исключает `.env*` и `logs/` из VCS.
## Развёртывание: подробная инструкция
### Локальная среда
- Заполни `.env.v1`, `.env.v2`, `.env.db` корректными значениями (БД, пользователи, пароли).
- Запусти: `docker compose up -d --build`.
- Просмотри логи при необходимости:
- `docker compose logs -f nginx`
- `docker compose logs -f php-fpm-v1`
- `docker compose logs -f php-fpm-v2`
- `docker compose logs -f postgres`
- Остановить и очистить:
```powershell
docker compose down -v
```
Команда удалит контейнеры и именованный том `postgres_data`.
### Staging/Production рекомендации
- Секреты: не хранить пароли в `.env` на диске. Используй Docker Swarm/Kubernetes secrets, HashiCorp Vault или инъекцию env через CI/CD.
- SSL/HTTP2: поставь обратный прокси с TLS (например, Nginx/Traefik) и включи HSTS/CSP/безопасные заголовки.
- Бэкапы: настроить регулярные бэкапы `postgres_data`.
- Доступы БД: разнести пользователей по API (отдельные `DB_USER`/пароли и права на свои базы).
- Обновления: регулярно обновлять базовые образы и пакеты в Dockerfile.
- Мониторинг: добавить healthchecks, метрики и алёрты.
## Что было исправлено и почему
- Nginx: убраны вложенные `location` и добавлены независимые блоки для `/api/v1` и `/api/v2`.
- `SCRIPT_FILENAME`: передаётся абсолютный путь `/var/www/html/index.php` (код не монтируется в Nginx).
- PHP-FPM: `clear_env = no`, чтобы PHP видел переменные из `.env`/compose.
- Dockerfile: удалены лишние пакеты; оставлены PHP 8.2 и нужные расширения. Исправлено отсутствие `php8.2-json` (встроено в ядро).
- Права: вместо `777` используются более строгие `755/775` и корректный владелец `www`.
- БД: добавлен скрипт инициализации, создающий `api_v1` и `api_v2`.
## Безопасность
- Секреты вынесены в `.env` файлы и исключены из VCS (`.gitignore`).
- Для продакшна — использовать secrets-менеджер вместо `.env`.
- Выключен `display_errors` в FPM; включать только на dev.
- Разграничение прав БД и ротация паролей.
## Диагностика проблем
- Ошибка FPM "failed to open error_log": убедись, что логи монтируются в `/var/log/php-fpm` (уже настроено в compose).
- Ошибка пакета `php8.2-json`: не устанавливается отдельно (часть ядра). Удалено из Dockerfile.
- Полный сброс окружения:
```powershell
docker compose down -v
docker compose up -d --build
```
## 📚 Документация
Подробная документация находится в каталоге `docs/`:
- Навигация и быстрый старт: `docs/README.md`
- Обзор и требования: `docs/overview.md`
- Запуск и деплой: `docs/deployment.md`
- Мониторинг (метрики и алёрты): `docs/monitoring.md`
- Примеры `.env`: `docs/env-examples.md`
- Публикация в Gitea: `docs/gitea.md`
- Диагностика: `docs/troubleshooting.md`
## 📚 Раздел: Secrets Management
Секреты вынесены из `docker-compose.yml` в отдельные env-файлы, игнорируемые системой контроля версий.
- Файлы: `.env.v1`, `.env.v2`, `.env.db` (локальные секреты).
- Пример содержимого и рекомендации см. в `docs/env-examples.md`.
### Почему так безопаснее
- Нет паролей в `docker-compose.yml` — меньше риск утечки в VCS.
- Разделение по сервисам — проще ротация и изоляция.
- В продакшене рекомендуем использовать Swarm/K8s Secrets, Vault, SSM Parameter Store.

62
api-v1/Dockerfile Normal file
View File

@@ -0,0 +1,62 @@
# Используем официальный образ Debian
FROM debian:bookworm-slim
LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="PHP-FPM container for API v1 with PostgreSQL and Memcached"
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
# Базовые утилиты и репозиторий PHP
RUN apt-get update && apt-get install -y \
curl \
wget \
gnupg \
lsb-release \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg \
&& echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
# PHP, расширения, клиент PostgreSQL
RUN apt-get update && apt-get install -y --no-install-recommends \
php8.2-fpm \
php8.2-cli \
php8.2-pgsql \
php8.2-memcached \
php8.2-curl \
php8.2-mbstring \
php8.2-xml \
php8.2-zip \
php8.2-gd \
php8.2-intl \
php8.2-bcmath \
php8.2-opcache \
postgresql-client \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Логи и рантайм
RUN mkdir -p /var/log/php-fpm \
&& mkdir -p /var/run/php
# Конфиги PHP-FPM
COPY config/php-fpm.conf /etc/php/8.2/fpm/php-fpm.conf
COPY config/www.conf /etc/php/8.2/fpm/pool.d/www.conf
# Пользователь
RUN groupadd -g 1000 www \
&& useradd -u 1000 -ms /bin/bash -g www www
WORKDIR /var/www/html
COPY . /var/www/html/
# Права доступа (без 777)
RUN chown -R www:www /var/www/html /var/log \
&& chmod -R 755 /var/www/html \
&& chmod -R 775 /var/log
EXPOSE 9000
CMD ["php-fpm8.2", "-F"]

View File

@@ -0,0 +1,4 @@
[global]
error_log = /var/log/php-fpm/v1-error.log
daemonize = no
include=/etc/php/8.2/fpm/pool.d/*.conf

28
api-v1/config/www.conf Normal file
View File

@@ -0,0 +1,28 @@
; Пул процессов для API v1
[www]
user = www
group = www
listen = 0.0.0.0:9000
listen.mode = 0660
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 5
; Важно для доступа к env переменным из PHP
clear_env = no
catch_workers_output = yes
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php-fpm/v1-error.log
php_admin_flag[log_errors] = on
; Метрики и пинг
pm.status_path = /status
ping.path = /ping
ping.response = pong
security.limit_extensions = .php .php3 .php4 .php5 .php7 .php8

44
api-v1/src/index.php Normal file
View File

@@ -0,0 +1,44 @@
<?php
/**
* API v1 Entry Point
* Docker Container: php-fpm-v1
* Endpoint: /api/v1/
*/
header('Content-Type: application/json');
// Проверяем подключение к PostgreSQL
try {
$pdo = new PDO(
"pgsql:host=" . getenv('DB_HOST') . ";dbname=" . getenv('DB_NAME'),
getenv('DB_USER'),
getenv('DB_PASS')
);
$db_status = "connected";
} catch (PDOException $e) {
$db_status = "error: " . $e->getMessage();
}
// Проверяем подключение к Memcached
try {
$memcached = new Memcached();
$memcached->addServer(getenv('MEMCACHED_HOST'), 11211);
$memcached_status = $memcached->set('test_key', 'test_value', 10) ? "connected" : "error";
} catch (Exception $e) {
$memcached_status = "error: " . $e->getMessage();
}
// Формируем ответ
$response = [
'api_version' => 'v1',
'status' => 'success',
'timestamp' => time(),
'services' => [
'postgresql' => $db_status,
'memcached' => $memcached_status,
],
'container' => gethostname(),
'php_version' => PHP_VERSION,
];
echo json_encode($response, JSON_PRETTY_PRINT);

56
api-v2/Dockerfile Normal file
View File

@@ -0,0 +1,56 @@
# Аналогично API v1, кастомизация под v2 при необходимости
FROM debian:bookworm-slim
LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="PHP-FPM container for API v2 with PostgreSQL and Memcached"
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
RUN apt-get update && apt-get install -y \
curl \
wget \
gnupg \
lsb-release \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg \
&& echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
RUN apt-get update && apt-get install -y --no-install-recommends \
php8.2-fpm \
php8.2-cli \
php8.2-pgsql \
php8.2-memcached \
php8.2-curl \
php8.2-mbstring \
php8.2-xml \
php8.2-zip \
php8.2-gd \
php8.2-intl \
php8.2-bcmath \
php8.2-opcache \
postgresql-client \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /var/log/php-fpm \
&& mkdir -p /var/run/php
COPY config/php-fpm.conf /etc/php/8.2/fpm/php-fpm.conf
COPY config/www.conf /etc/php/8.2/fpm/pool.d/www.conf
RUN groupadd -g 1001 www \
&& useradd -u 1001 -ms /bin/bash -g www www
WORKDIR /var/www/html
COPY . /var/www/html/
RUN chown -R www:www /var/www/html /var/log \
&& chmod -R 755 /var/www/html \
&& chmod -R 775 /var/log
EXPOSE 9000
CMD ["php-fpm8.2", "-F"]

View File

@@ -0,0 +1,4 @@
[global]
error_log = /var/log/php-fpm/v2-error.log
daemonize = no
include=/etc/php/8.2/fpm/pool.d/*.conf

27
api-v2/config/www.conf Normal file
View File

@@ -0,0 +1,27 @@
; Пул процессов для API v2
[www]
user = www
group = www
listen = 0.0.0.0:9000
listen.mode = 0660
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 5
clear_env = no
catch_workers_output = yes
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php-fpm/v2-error.log
php_admin_flag[log_errors] = on
; Метрики и пинг
pm.status_path = /status
ping.path = /ping
ping.response = pong
security.limit_extensions = .php .php3 .php4 .php5 .php7 .php8

45
api-v2/src/index.php Normal file
View File

@@ -0,0 +1,45 @@
<?php
/**
* API v2 Entry Point
* Docker Container: php-fpm-v2
* Endpoint: /api/v2/
*/
header('Content-Type: application/json');
try {
$pdo = new PDO(
"pgsql:host=" . getenv('DB_HOST') . ";dbname=api_v2",
getenv('DB_USER'),
getenv('DB_PASS')
);
$db_status = "connected";
} catch (PDOException $e) {
$db_status = "error: " . $e->getMessage();
}
try {
$memcached = new Memcached();
$memcached->addServer(getenv('MEMCACHED_HOST'), 11211);
$memcached_status = $memcached->set('test_key_v2', 'test_value', 10) ? "connected" : "error";
} catch (Exception $e) {
$memcached_status = "error: " . $e->getMessage();
}
$response = [
'api_version' => 'v2',
'status' => 'success',
'timestamp' => time(),
'services' => [
'postgresql' => $db_status,
'memcached' => $memcached_status,
],
'container' => gethostname(),
'php_version' => PHP_VERSION,
'features' => [
'advanced_caching',
'extended_metrics'
]
];
echo json_encode($response, JSON_PRETTY_PRINT);

View File

@@ -0,0 +1,6 @@
-- Инициализация дополнительных баз данных для API v1 и API v2
CREATE DATABASE api_v1;
CREATE DATABASE api_v2;
GRANT ALL PRIVILEGES ON DATABASE api_v1 TO api_user;
GRANT ALL PRIVILEGES ON DATABASE api_v2 TO api_user;

185
docker-compose.yml Normal file
View File

@@ -0,0 +1,185 @@
services:
nginx:
image: nginx:1.24-alpine
container_name: nginx_proxy
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs/nginx:/var/log/nginx
depends_on:
- php-fpm-v1
- php-fpm-v2
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost/"]
interval: 10s
timeout: 3s
retries: 5
networks:
- app_network
restart: unless-stopped
php-fpm-v1:
build:
context: ./api-v1
dockerfile: Dockerfile
container_name: php_fpm_v1
volumes:
- ./api-v1:/var/www/html
- ./logs/php-v1:/var/log/php-fpm
env_file:
- .env.v1
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://nginx/api/v1/ > /dev/null"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app_network
restart: unless-stopped
php-fpm-v2:
build:
context: ./api-v2
dockerfile: Dockerfile
container_name: php_fpm_v2
volumes:
- ./api-v2:/var/www/html
- ./logs/php-v2:/var/log/php-fpm
env_file:
- .env.v2
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://nginx/api/v2/ > /dev/null"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app_network
restart: unless-stopped
postgres:
image: postgres:15-alpine
container_name: postgres_db
env_file:
- .env.db
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
volumes:
- postgres_data:/var/lib/postgresql/data
- ./database/init:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
networks:
- app_network
restart: unless-stopped
memcached:
image: memcached:1.6-alpine
container_name: memcached_server
healthcheck:
test: ["CMD-SHELL", "pidof memcached"]
interval: 10s
timeout: 3s
retries: 5
ports:
- "11211:11211"
networks:
- app_network
restart: unless-stopped
nginx_exporter:
image: nginx/nginx-prometheus-exporter:0.11.0
container_name: nginx_exporter
command: ["-nginx.scrape-uri", "http://nginx/status"]
ports:
- "9113:9113"
depends_on:
- nginx
networks:
- app_network
restart: unless-stopped
php_fpm_exporter:
image: hipages/php-fpm_exporter:latest
container_name: php_fpm_exporter
command:
- "server"
- "--phpfpm.scrape-uri=tcp://php-fpm-v1:9000/status"
- "--phpfpm.scrape-uri=tcp://php-fpm-v2:9000/status"
- "--web.listen-address=0.0.0.0:9253"
ports:
- "9253:9253"
depends_on:
- php-fpm-v1
- php-fpm-v2
networks:
- app_network
restart: unless-stopped
postgres_exporter:
image: prometheuscommunity/postgres-exporter:latest
container_name: postgres_exporter
env_file:
- .env.db
environment:
DATA_SOURCE_NAME: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable"
ports:
- "9187:9187"
depends_on:
- postgres
networks:
- app_network
restart: unless-stopped
memcached_exporter:
image: prom/memcached-exporter:latest
container_name: memcached_exporter
command: ["--memcached.address=memcached:11211"]
ports:
- "9150:9150"
depends_on:
- memcached
networks:
- app_network
restart: unless-stopped
prometheus:
image: prom/prometheus:latest
container_name: prometheus
command: ["--config.file=/etc/prometheus/prometheus.yml","--storage.tsdb.path=/prometheus","--web.enable-lifecycle"]
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./monitoring/alert.rules.yml:/etc/prometheus/alert.rules.yml:ro
- prometheus_data:/prometheus
ports:
- "9090:9090"
depends_on:
- nginx_exporter
- php_fpm_exporter
- postgres_exporter
- memcached_exporter
networks:
- app_network
restart: unless-stopped
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
volumes:
- ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
ports:
- "9093:9093"
networks:
- app_network
restart: unless-stopped
volumes:
postgres_data:
prometheus_data:
networks:
app_network:
driver: bridge

18
docs/README.md Normal file
View File

@@ -0,0 +1,18 @@
# Документация проекта
Добро пожаловать! Этот раздел содержит полную документацию по проекту, навигацию по подсекциям, примеры конфигураций и инструкции по развёртыванию и публикации в Gitea.
## Навигация
- [Обзор и требования](./overview.md)
- [Запуск и деплой](./deployment.md)
- [Мониторинг: метрики и алёрты](./monitoring.md)
- [Примеры .env файлов](./env-examples.md)
- [Публикация в Gitea](./gitea.md)
- [Диагностика и троблшутинг](./troubleshooting.md)
## Быстрый старт
- Скопируйте и заполните `.env.v1`, `.env.v2`, `.env.db` по образцам из [env-examples.md](./env-examples.md).
- Запустите `docker compose up -d` из корня проекта.
- Проверьте таргеты в Prometheus: `http://localhost:9090/targets`.
- Проверьте метрики экспортеров: Nginx `http://localhost:9113/metrics`, PHP-FPM `http://localhost:9253/metrics`, Postgres `http://localhost:9187/metrics`, Memcached `http://localhost:9150/metrics`.
- Alertmanager UI: `http://localhost:9093` (настройте получателей в `monitoring/alertmanager.yml`).

23
docs/deployment.md Normal file
View File

@@ -0,0 +1,23 @@
# Запуск и деплой
## Локальный запуск (DEV)
1. Заполните `.env.v1`, `.env.v2`, `.env.db` по образцам из [env-examples.md](./env-examples.md).
2. Запустите: `docker compose up -d` в корне проекта.
3. Проверьте:
- API v1: `http://localhost/api/v1/`
- API v2: `http://localhost/api/v2/`
- Nginx статус: `http://localhost/status`
- Prometheus: `http://localhost:9090`
- Alertmanager: `http://localhost:9093`
## Продакшен (общие рекомендации)
- Используйте секреты: Docker Swarm/K8s Secrets, Vault или SSM Parameter Store.
- Ограничьте `/status` (Nginx stub_status) по IP/ACL.
- Разнесите экспортеры и Prometheus на отдельные ноды.
- Настройте резервное копирование для Postgres и ретеншен для Prometheus.
- Добавьте Grafana для визуализации (рекомендуется).
## Обновление стека
- Обновить конфиги: `monitoring/*`, `nginx/nginx.conf`, `.env.*`.
- Перезапуск: `docker compose up -d`.
- Проверка таргетов: `http://localhost:9090/targets`.

30
docs/env-examples.md Normal file
View File

@@ -0,0 +1,30 @@
# Примеры .env файлов
## .env.v1
```
DB_HOST=postgres
DB_NAME=app_db
DB_USER=app_user
DB_PASS=local_password_v1
MEMCACHED_HOST=memcached
```
## .env.v2
```
DB_HOST=postgres
DB_NAME=app_db
DB_USER=app_user
DB_PASS=local_password_v2
MEMCACHED_HOST=memcached
```
## .env.db
```
POSTGRES_DB=app_db
POSTGRES_USER=app_user
POSTGRES_PASSWORD=local_db_password
```
## Примечания
- Эти файлы добавлены в `.gitignore` и не должны коммититься.
- В продакшене используйте секрет-менеджеры или переменные окружения CI/CD.

28
docs/gitea.md Normal file
View File

@@ -0,0 +1,28 @@
# Публикация в Gitea
## Подготовка репозитория
- Убедитесь, что `.env.*` и `logs/` в `.gitignore`.
- Проверьте `README.md` и раздел `docs/` на актуальность.
## Создание репозитория в Gitea
1. Зайдите в Gitea и создайте новый репозиторий (Private/Public по вашему выбору).
2. Скопируйте URL репозитория (SSH/HTTPS).
## Локальная привязка и пуш
```bash
# Инициализация (если не инициализировано)
git init
# Добавление ремоута
git remote add origin <URL-вашего-репозитория>
# Коммиты и пуш
git add .
git commit -m "Initial commit"
git push -u origin main
```
## CI/CD (рекомендации)
- Включите защищённые секреты в Gitea/Runner.
- Запланируйте пайплайн: линтеры, сборка, запуск `docker compose config && docker compose up -d`.
- Храните prod-секреты вне репозитория (Secrets/Variables).

24
docs/monitoring.md Normal file
View File

@@ -0,0 +1,24 @@
# Мониторинг: метрики и алёрты
## Экспортеры и порты
- Nginx Exporter (`nginx_exporter`): `http://localhost:9113/metrics` — читает `http://nginx/status`.
- PHP-FPM Exporter (`php_fpm_exporter`): `http://localhost:9253/metrics` — опрашивает `tcp://php-fpm-v1:9000/status` и `tcp://php-fpm-v2:9000/status`.
- Postgres Exporter (`postgres_exporter`): `http://localhost:9187/metrics`.
- Memcached Exporter (`memcached_exporter`): `http://localhost:9150/metrics`.
## Prometheus
- UI: `http://localhost:9090`
- Конфиг: `monitoring/prometheus.yml`
- Таргеты: `http://localhost:9090/targets`
## Alertmanager
- UI: `http://localhost:9093`
- Конфиг: `monitoring/alertmanager.yml`
- Правила алёртов: `monitoring/alert.rules.yml`
## Правила по умолчанию
- `InstanceDown`: `up == 0` в течение 1 минуты — критический алерт.
## Расширение
- Добавьте свои правила в `monitoring/alert.rules.yml`.
- Настройте получателей в `monitoring/alertmanager.yml` (email/telegram/webhook).

16
docs/overview.md Normal file
View File

@@ -0,0 +1,16 @@
# Обзор и требования
Проект содержит два PHP API (v1 и v2), Nginx для роутинга, Postgres и Memcached. Добавлены healthchecks, метрики через экспортеры и базовые алёрты.
## Компоненты
- Nginx (`nginx`) — прокси и роутинг `/api/v1` и `/api/v2`.
- PHP-FPM v1/v2 (`php-fpm-v1`, `php-fpm-v2`) — обработка PHP.
- Postgres (`postgres`) — база данных.
- Memcached (`memcached`) — кеш.
- Экспортеры: `nginx_exporter`, `php_fpm_exporter`, `postgres_exporter`, `memcached_exporter`.
- Мониторинг: `prometheus`, `alertmanager`.
## Требования
- Docker 24+ и Docker Compose v2.
- Порты, свободные на хосте: `80, 5432, 11211, 9113, 9253, 9187, 9150, 9090, 9093`.
- Windows: запуск из PowerShell, пути проекта в `c:\docker\nginxphp\server\project`.

17
docs/troubleshooting.md Normal file
View File

@@ -0,0 +1,17 @@
# Диагностика и троблшутинг
## Healthchecks
- `nginx`: проверка `http://localhost/`.
- `php-fpm-v1/v2`: проверка `http://nginx/api/v1/` и `http://nginx/api/v2/`.
- `postgres`: `pg_isready`.
- `memcached`: `pidof memcached`.
## Типичные проблемы
- Порты заняты: проверьте, что нет конфликтующих сервисов.
- Ошибка доступа к `/status`: ограничьте доступ в продакшене, в DEV открыт.
- Postgres exporter: проверьте `DATA_SOURCE_NAME` и учётные данные.
## Логи
- Nginx: `./logs/nginx`.
- PHP-FPM v1/v2: `./logs/php-v1`, `./logs/php-v2`.
- Postgres: внутри контейнера `/var/lib/postgresql/data/log` (при включении логгирования).

View File

@@ -0,0 +1,11 @@
groups:
- name: general
rules:
- alert: InstanceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Endpoint {{ $labels.instance }} недоступен"
description: "Таргет job={{ $labels.job }} на хосте {{ $labels.instance }} не отвечает более 1 минуты."

View File

@@ -0,0 +1,15 @@
global:
resolve_timeout: 5m
route:
receiver: 'default'
group_by: ['alertname', 'job']
group_wait: 10s
group_interval: 5m
repeat_interval: 1h
receivers:
- name: 'default'
webhook_configs:
- url: 'http://host.docker.internal:5001/alerts'
send_resolved: true

28
monitoring/prometheus.yml Normal file
View File

@@ -0,0 +1,28 @@
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['nginx_exporter:9113']
- job_name: 'php-fpm'
static_configs:
- targets: ['php_fpm_exporter:9253']
- job_name: 'postgres'
static_configs:
- targets: ['postgres_exporter:9187']
- job_name: 'memcached'
static_configs:
- targets: ['memcached_exporter:9150']
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
rule_files:
- /etc/prometheus/alert.rules.yml

81
nginx/nginx.conf Normal file
View File

@@ -0,0 +1,81 @@
# Основные настройки Nginx
events {
worker_connections 1024;
}
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"';
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Upstream для PHP-FPM серверов
upstream php_fpm_v1 {
server php-fpm-v1:9000;
}
upstream php_fpm_v2 {
server php-fpm-v2:9000;
}
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# API v1: фронт-контроллер index.php внутри контейнера php-fpm-v1
location ~ ^/api/v1(?:/|$) {
include fastcgi_params;
fastcgi_pass php_fpm_v1;
fastcgi_param SCRIPT_FILENAME /var/www/html/index.php;
fastcgi_param PHP_VALUE "upload_max_filesize=100M \n post_max_size=100M";
fastcgi_read_timeout 300;
}
# API v2: фронт-контроллер index.php внутри контейнера php-fpm-v2
location ~ ^/api/v2(?:/|$) {
include fastcgi_params;
fastcgi_pass php_fpm_v2;
fastcgi_param SCRIPT_FILENAME /var/www/html/index.php;
fastcgi_param PHP_VALUE "upload_max_filesize=100M \n post_max_size=100M";
fastcgi_read_timeout 300;
}
# Обслуживание статических файлов (если появятся)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Безопасность: скрываем служебные файлы
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ /README\.md$ {
deny all;
access_log off;
log_not_found off;
}
# Метрики Nginx: stub_status для экспорта
location /status {
stub_status;
access_log off;
# В DEV среде открыт; в PROD ограничить по IP/ACL
}
}
}