From d6ea4314b019126ae0ab7248e919f720bf6f0e30 Mon Sep 17 00:00:00 2001 From: abakumov-a-a Date: Thu, 11 Dec 2025 21:47:42 +0300 Subject: [PATCH] add docker --- .dockerignore | 21 +++++ DOCKER.md | 158 ++++++++++++++++++++++++++++++++++++ Dockerfile | 54 +++++++++++++ app.js | 27 +++++-- client/.dockerignore | 16 ++++ client/Dockerfile | 50 ++++++++++++ client/nginx.conf | 58 ++++++++++++++ client/nginx.conf.template | 58 ++++++++++++++ docker-compose.build.yml | 159 +++++++++++++++++++++++++++++++++++++ docker-compose.yml | 146 ++++++++++++++++++++++++++++++++++ 10 files changed, 741 insertions(+), 6 deletions(-) create mode 100644 .dockerignore create mode 100644 DOCKER.md create mode 100644 Dockerfile create mode 100644 client/.dockerignore create mode 100644 client/Dockerfile create mode 100644 client/nginx.conf create mode 100644 client/nginx.conf.template create mode 100644 docker-compose.build.yml create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2df9340 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.git +.gitignore +.env +.env.local +.env.*.local +.DS_Store +*.log +coverage +.vscode +.idea +client +tests +*.md +.eslintrc.json +eslint.config.js +logs +*.test.js diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..7267ea9 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,158 @@ +# Docker Setup для Shop Platform + +## Быстрый старт + +### 1. Использование готовых образов из registry (рекомендуется для production) + +```bash +# Копируем пример файла с переменными окружения +cp .env.example .env + +# Редактируем .env файл и укажите образы из registry: +# FRONTEND_IMAGE=your-registry.com/shop-platform-frontend:latest +# BACKEND_IMAGE=your-registry.com/shop-platform-backend:latest +# POSTGRES_IMAGE=postgres:15-alpine +# MINIO_IMAGE=minio/minio:latest + +# Особенно важно изменить JWT_SECRET для продакшена! + +# Если registry требует аутентификацию, выполните: +# docker login your-registry.com + +# Запускаем все сервисы (образы будут скачаны из registry) +docker-compose up -d + +# Просмотр логов +docker-compose logs -f backend +``` + +### 2. Локальная сборка образов + +```bash +# Собираем образы локально +docker-compose -f docker-compose.build.yml build + +# Помечаем образы для registry (опционально) +docker tag shop-platform-frontend:latest your-registry/shop-platform-frontend:latest +docker tag shop-platform-backend:latest your-registry/shop-platform-backend:latest + +# Отправляем в registry (опционально) +docker push your-registry/shop-platform-frontend:latest +docker push your-registry/shop-platform-backend:latest + +# Затем используйте docker-compose.yml с указанием образов в .env +``` + +### 3. Только бэкенд (если PostgreSQL и MinIO уже запущены) + +```bash +# Сборка образа +docker build -t shop-platform-backend . + +# Запуск контейнера +docker run -d \ + --name shop-platform-backend \ + -p 80:80 -p 443:443 \ + -e POSTGRES_HOST=your-postgres-host \ + -e POSTGRES_PASSWORD=your-password \ + -e MINIO_ENDPOINT=your-minio-host \ + -e JWT_SECRET=your-secret-key \ + -v ./tsl:/app/tsl:ro \ + shop-platform-backend +``` + +## Переменные окружения + +Все переменные окружения описаны в файле `.env.example`. Основные: + +### Backend: +- **POSTGRES_*** - настройки подключения к PostgreSQL +- **MINIO_*** - настройки подключения к MinIO +- **WEB_*** - настройки веб-сервера (порты, TLS) +- **TSL_*** - настройки SSL/TLS сертификатов +- **JWT_SECRET** - секретный ключ для JWT (ОБЯЗАТЕЛЬНО измените!) + +### Frontend: +- **FRONTEND_IMAGE** - имя образа фронтенда из registry (по умолчанию: `shop-platform-frontend:latest`) +- **VITE_API_URL** - URL бэкенда для клиентского приложения (по умолчанию: `/api/v1` - относительный путь, проксируется через nginx) +- **BACKEND_URL** - URL бэкенда для nginx proxy (по умолчанию: `http://backend:443`) +- **BACKEND_SSL_VERIFY** - настройка SSL проверки для бэкенда (по умолчанию: `# proxy_ssl_verify off;` - проверка отключена) +- **FRONTEND_PORT** - порт для фронтенда (по умолчанию: `3000`) + +### Образы из registry: +- **FRONTEND_IMAGE** - образ фронтенда (например: `registry.example.com/shop-platform-frontend:v1.0.0`) +- **BACKEND_IMAGE** - образ бэкенда (например: `registry.example.com/shop-platform-backend:v1.0.0`) +- **POSTGRES_IMAGE** - образ PostgreSQL (по умолчанию: `postgres:15-alpine`) +- **MINIO_IMAGE** - образ MinIO (по умолчанию: `minio/minio:latest`) + +## Структура сервисов + +Docker Compose включает: + +1. **frontend** - React приложение (Vite + Nginx) +2. **backend** - основное приложение на Fastify +3. **postgres** - база данных PostgreSQL +4. **minio** - объектное хранилище для изображений + +## Сертификаты TLS + +Если вы используете HTTPS (WEB_TSL=true), поместите сертификаты в папку `tsl/`: +- `tsl/key.pem` - приватный ключ +- `tsl/cert.pem` - сертификат + +Если сертификатов нет, приложение автоматически создаст самоподписанные сертификаты при первом запуске. + +## Healthcheck + +Приложение имеет встроенный healthcheck endpoint: +- HTTP: `http://localhost:80/health` +- HTTPS: `https://localhost:443/health` + +## Логи + +Логи сохраняются в папку `logs/` (если FILE_LOG_LEVEL задан) или выводятся в stdout. + +## Миграции базы данных + +SQL скрипты из папки `sql/` автоматически выполняются при первом запуске PostgreSQL контейнера (благодаря монтированию в `/docker-entrypoint-initdb.d`). + +## Полезные команды + +```bash +# Остановить все сервисы +docker-compose down + +# Остановить и удалить volumes (ОСТОРОЖНО: удалит данные!) +docker-compose down -v + +# Пересобрать образы локально (используя docker-compose.build.yml) +docker-compose -f docker-compose.build.yml build --no-cache + +# Отправить образы в registry (после сборки) +docker tag shop-platform-frontend:latest ${REGISTRY_URL}/shop-platform-frontend:latest +docker tag shop-platform-backend:latest ${REGISTRY_URL}/shop-platform-backend:latest +docker push ${REGISTRY_URL}/shop-platform-frontend:latest +docker push ${REGISTRY_URL}/shop-platform-backend:latest + +# Просмотр логов конкретного сервиса +docker-compose logs -f frontend +docker-compose logs -f backend +docker-compose logs -f postgres +docker-compose logs -f minio + +# Выполнить команду в контейнере +docker-compose exec backend sh + +# Проверить статус +docker-compose ps +``` + +## Production рекомендации + +1. **Измените JWT_SECRET** на сложный случайный ключ +2. **Используйте сильные пароли** для PostgreSQL и MinIO +3. **Настройте правильные TLS сертификаты** (не самоподписанные) +4. **Используйте secrets** для хранения паролей (Docker Secrets или внешний менеджер) +5. **Настройте резервное копирование** для PostgreSQL +6. **Ограничьте доступ** к портам через firewall +7. **Используйте reverse proxy** (nginx) перед приложением diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a401b84 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +# Multi-stage build для бэкенда +# Stage 1: Сборка зависимостей +FROM node:18-alpine AS dependencies + +WORKDIR /app + +# Копируем файлы зависимостей +COPY package*.json ./ + +# Устанавливаем зависимости +RUN npm ci --only=production && npm cache clean --force + +# Stage 2: Production образ +FROM node:18-alpine + +# Устанавливаем wget для healthcheck +RUN apk add --no-cache wget + +WORKDIR /app + +# Создаем пользователя для запуска приложения (безопасность) +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 + +# Копируем зависимости из stage dependencies +COPY --from=dependencies --chown=nodejs:nodejs /app/node_modules ./node_modules + +# Копируем исходный код +COPY --chown=nodejs:nodejs . . + +# Создаем директории для логов и сертификатов +RUN mkdir -p logs tsl && \ + chown -R nodejs:nodejs logs tsl + +# Переключаемся на пользователя nodejs +USER nodejs + +# Открываем порты (HTTP и HTTPS) +# Порты можно настроить через переменные окружения WEB_HTTP_PORT и WEB_HTTPS_PORT +EXPOSE 80 443 + +# Переменные окружения по умолчанию +# Все переменные можно переопределить через docker-compose или docker run +ENV NODE_ENV=production \ + LOG_LEVEL=info \ + STDOUT_LOG_LEVEL=info + +# Healthcheck для проверки работоспособности +# Используем wget или curl (должны быть установлены в alpine) +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:80/health || exit 1 + +# Запускаем приложение +CMD ["node", "app.js"] diff --git a/app.js b/app.js index ec8ad8c..066eafc 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,6 @@ import { YmlParser } from "./src/utils/yml-parser.js"; import daoPlugin from './src/plugins/dao.js'; import pino from "pino"; -import pretty from 'pino-pretty'; import autoload from '@fastify/autoload'; import fastifySwagger from "@fastify/swagger"; import fastifySwaggerUi from "@fastify/swagger-ui"; @@ -22,20 +21,36 @@ import minioPlugin from "./src/plugins/minio.js"; (async () => { let streams; + + // Используем pino-pretty только в development режиме + const isDevelopment = process.env.NODE_ENV !== 'production'; + let prettyStream = process.stdout; + + if (isDevelopment) { + try { + const pretty = (await import('pino-pretty')).default; + prettyStream = pretty({ colorize: true }); + } catch (err) { + // Если pino-pretty не установлен, используем обычный stdout + console.warn('pino-pretty не найден, используется обычный вывод логов'); + } + } + if (process.env.FILE_LOG_LEVEL !== undefined) { - const logFileStream = fs.createWriteStream(`./logs/event-log.log`, { flags: 'a' }); logFileStream.on('error', (err) => { console.error('Ошибка при создании потока для файла логов:', err); }); streams = [ { level: process.env.FILE_LOG_LEVEL || 'debug', stream: logFileStream }, - { level: process.env.STDOUT_LOG_LEVEL || 'trace', stream: pretty({ colorize: true }) } + { level: process.env.STDOUT_LOG_LEVEL || 'trace', stream: prettyStream } + ]; + } + else { + streams = [ + { level: process.env.STDOUT_LOG_LEVEL || 'trace', stream: prettyStream } ]; } - else streams = [ - { level: process.env.STDOUT_LOG_LEVEL || 'trace', stream: pretty({ colorize: true }) } - ]; const logger = pino( { level: process.env.LOG_LEVEL || 'info' }, diff --git a/client/.dockerignore b/client/.dockerignore new file mode 100644 index 0000000..b59f010 --- /dev/null +++ b/client/.dockerignore @@ -0,0 +1,16 @@ +node_modules +dist +.git +.gitignore +.env +.env.local +.env.*.local +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.DS_Store +*.log +coverage +.vscode +.idea +README.md diff --git a/client/Dockerfile b/client/Dockerfile new file mode 100644 index 0000000..7b40093 --- /dev/null +++ b/client/Dockerfile @@ -0,0 +1,50 @@ +# Multi-stage build для фронтенда +# Stage 1: Сборка приложения +FROM node:18-alpine AS builder + +WORKDIR /app + +# Копируем файлы зависимостей +COPY package*.json ./ + +# Устанавливаем зависимости +RUN npm ci && npm cache clean --force + +# Копируем исходный код +COPY . . + +# Переменные окружения для сборки +# VITE_API_URL используется в runtime через import.meta.env +ARG VITE_API_URL +ENV VITE_API_URL=${VITE_API_URL} + +# Собираем приложение +RUN npm run build + +# Stage 2: Production образ с nginx +FROM nginx:alpine + +# Устанавливаем wget и gettext (для envsubst) +RUN apk add --no-cache wget gettext + +# Копируем собранные файлы из builder stage +COPY --from=builder /app/dist /usr/share/nginx/html + +# Копируем шаблон конфигурации nginx +COPY nginx.conf.template /etc/nginx/templates/default.conf.template + +# Переменные окружения для nginx конфигурации (значения по умолчанию) +# Если бэкенд использует HTTPS, используйте https://backend:443 +ENV BACKEND_URL=https://backend:443 +# BACKEND_SSL_VERIFY: "on" = проверка включена, "off" = проверка отключена (по умолчанию отключена для самоподписанных сертификатов) +ENV BACKEND_SSL_VERIFY=off + +# Открываем порт 80 +EXPOSE 80 + +# Healthcheck +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1 + +# Запускаем nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/client/nginx.conf b/client/nginx.conf new file mode 100644 index 0000000..8790c9f --- /dev/null +++ b/client/nginx.conf @@ -0,0 +1,58 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # SPA routing - все запросы направляем на index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Кеширование статических ресурсов + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # API проксирование к бэкенду + # Все запросы к /api проксируются на бэкенд + location /api { + # Проксируем на бэкенд (используется переменная окружения BACKEND_URL) + proxy_pass ${BACKEND_URL}; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # Для HTTPS бэкенда раскомментируйте следующую строку + # proxy_ssl_verify off; + + # Таймауты + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Healthcheck endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +} diff --git a/client/nginx.conf.template b/client/nginx.conf.template new file mode 100644 index 0000000..88dc060 --- /dev/null +++ b/client/nginx.conf.template @@ -0,0 +1,58 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # SPA routing - все запросы направляем на index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Кеширование статических ресурсов + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # API проксирование к бэкенду + # Все запросы к /api проксируются на бэкенд + location /api { + # Проксируем на бэкенд (используется переменная окружения BACKEND_URL) + proxy_pass ${BACKEND_URL}; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # Для HTTPS бэкенда (BACKEND_SSL_VERIFY: "on" = проверка включена, "off" = проверка отключена) + proxy_ssl_verify ${BACKEND_SSL_VERIFY}; + + # Таймауты + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Healthcheck endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +} diff --git a/docker-compose.build.yml b/docker-compose.build.yml new file mode 100644 index 0000000..534b0ea --- /dev/null +++ b/docker-compose.build.yml @@ -0,0 +1,159 @@ +version: '3.8' + +# Docker Compose для локальной сборки образов +# Используйте: docker-compose -f docker-compose.build.yml build +# Затем: docker-compose up -d + +services: + frontend: + build: + context: ./client + dockerfile: Dockerfile + args: + # URL бэкенда для сборки (используется в runtime через import.meta.env.VITE_API_URL) + VITE_API_URL: ${VITE_API_URL:-/api/v1} + image: ${FRONTEND_IMAGE:-shop-platform-frontend:latest} + container_name: shop-platform-frontend + ports: + - "${FRONTEND_PORT:-3000}:80" + environment: + # URL бэкенда для nginx proxy (используется в nginx.conf.template) + # Если бэкенд использует HTTPS (WEB_TSL=true), используйте https://backend:443 + - BACKEND_URL=${BACKEND_URL:-https://backend:443} + # Настройка SSL проверки для бэкенда ("on" = проверка включена, "off" = проверка отключена) + - BACKEND_SSL_VERIFY=${BACKEND_SSL_VERIFY:-off} + # URL бэкенда для клиентского приложения (используется в runtime через import.meta.env.VITE_API_URL) + # Если не задан, используется относительный путь /api/v1 (проксируется через nginx) + - VITE_API_URL=${VITE_API_URL:-/api/v1} + depends_on: + - backend + restart: unless-stopped + networks: + - shop-network + + backend: + build: + context: . + dockerfile: Dockerfile + image: ${BACKEND_IMAGE:-shop-platform-backend:latest} + container_name: shop-platform-backend + ports: + - "${WEB_HTTP_PORT:-80}:80" + - "${WEB_HTTPS_PORT:-443}:443" + environment: + # PostgreSQL настройки + - POSTGRES_HOST=${POSTGRES_HOST:-postgres} + - POSTGRES_PORT=${POSTGRES_PORT:-5432} + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} + - POSTGRES_DB=${POSTGRES_DB:-shop_platform} + + # Web настройки + - WEB_HTTP_PORT=${WEB_HTTP_PORT:-80} + - WEB_HTTPS_PORT=${WEB_HTTPS_PORT:-443} + - WEB_TSL=${WEB_TSL:-true} + - WEB_HOST=${WEB_HOST:-0.0.0.0} + + # TLS/SSL настройки + - TSL_PATH=${TSL_PATH:-./tsl} + - TSL_KEY=${TSL_KEY:-key.pem} + - TSL_CERT=${TSL_CERT:-cert.pem} + - TSL_HOST=${TSL_HOST:-localhost} + - TSL_C=${TSL_C:-RU} + - TSL_ST=${TSL_ST:-Moscow} + - TSL_L=${TSL_L:-Moscow} + - TSL_O=${TSL_O:-Softline} + - TSL_OU=${TSL_OU:-Digital} + + # MinIO настройки + - MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} + - MINIO_PORT=${MINIO_PORT:-9000} + - MINIO_USE_SSL=${MINIO_USE_SSL:-false} + - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-administrator} + - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-123QWEasd} + - MINIO_REGION=${MINIO_REGION:-us-east-1} + - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME:-store-images} + + # Логирование + - LOG_LEVEL=${LOG_LEVEL:-info} + - STDOUT_LOG_LEVEL=${STDOUT_LOG_LEVEL:-info} + - FILE_LOG_LEVEL=${FILE_LOG_LEVEL:-} + + # JWT Secret (важно для безопасности!) + - JWT_SECRET=${JWT_SECRET:-your-secret-key-change-in-production} + volumes: + # Монтируем сертификаты (если они есть на хосте) + - ./tsl:/app/tsl:ro + # Монтируем логи (опционально) + - ./logs:/app/logs + depends_on: + - postgres + - minio + restart: unless-stopped + networks: + - shop-network + + postgres: + image: ${POSTGRES_IMAGE:-postgres:15-alpine} + container_name: shop-platform-postgres + environment: + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} + - POSTGRES_DB=${POSTGRES_DB:-shop_platform} + volumes: + - postgres_data:/var/lib/postgresql/data + # Можно монтировать SQL скрипты для инициализации + - ./sql:/docker-entrypoint-initdb.d:ro + ports: + - "${POSTGRES_PORT:-5432}:5432" + restart: unless-stopped + networks: + - shop-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] + interval: 10s + timeout: 5s + retries: 5 + + minio: + image: ${MINIO_IMAGE:-minio/minio:latest} + container_name: shop-platform-minio + command: server /data --console-address ":9001" + environment: + - MINIO_ROOT_USER=${MINIO_ACCESS_KEY:-administrator} + - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY:-123QWEasd} + volumes: + - minio_data:/data + ports: + - "${MINIO_PORT:-9000}:9000" + - "9001:9001" # MinIO Console + restart: unless-stopped + networks: + - shop-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + cloudbeaver: + image: ${CLOUDBEAVER_IMAGE:-dbeaver/cloudbeaver:latest} + container_name: shop-platform-cloudbeaver + ports: + - "${CLOUDBEAVER_PORT:-8978}:8978" + volumes: + - cloudbeaver_data:/opt/cloudbeaver/workspace + depends_on: + - postgres + restart: unless-stopped + networks: + - shop-network + +volumes: + postgres_data: + minio_data: + cloudbeaver_data: + +networks: + shop-network: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..94956a0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,146 @@ +version: '3.8' + +services: + frontend: + image: ${FRONTEND_IMAGE:-allexd2010/shop-platform-frontend:0.1} + container_name: shop-platform-frontend + ports: + - "${FRONTEND_PORT:-3000}:80" + environment: + # URL бэкенда для nginx proxy (используется в nginx.conf.template) + # Если бэкенд использует HTTPS (WEB_TSL=true), используйте https://backend:443 + - BACKEND_URL=${BACKEND_URL:-https://backend:443} + # Настройка SSL проверки для бэкенда ("on" = проверка включена, "off" = проверка отключена) + - BACKEND_SSL_VERIFY=${BACKEND_SSL_VERIFY:-off} + # URL бэкенда для клиентского приложения (используется в runtime через import.meta.env.VITE_API_URL) + # Если не задан, используется относительный путь /api/v1 (проксируется через nginx) + - VITE_API_URL=${VITE_API_URL:-/api/v1} + depends_on: + - backend + restart: unless-stopped + networks: + - shop-network + + backend: + image: ${BACKEND_IMAGE:-allexd2010/shop-platform-backend:0.1} + container_name: shop-platform-backend + ports: + - "${WEB_HTTP_PORT:-80}:80" + - "${WEB_HTTPS_PORT:-443}:443" + environment: + # PostgreSQL настройки + - POSTGRES_HOST=${POSTGRES_HOST:-postgres} + - POSTGRES_PORT=${POSTGRES_PORT:-5432} + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} + - POSTGRES_DB=${POSTGRES_DB:-shop_platform} + + # Web настройки + - WEB_HTTP_PORT=${WEB_HTTP_PORT:-80} + - WEB_HTTPS_PORT=${WEB_HTTPS_PORT:-443} + - WEB_TSL=${WEB_TSL:-true} + - WEB_HOST=${WEB_HOST:-0.0.0.0} + + # TLS/SSL настройки + - TSL_PATH=${TSL_PATH:-./tsl} + - TSL_KEY=${TSL_KEY:-key.pem} + - TSL_CERT=${TSL_CERT:-cert.pem} + - TSL_HOST=${TSL_HOST:-localhost} + - TSL_C=${TSL_C:-RU} + - TSL_ST=${TSL_ST:-Moscow} + - TSL_L=${TSL_L:-Moscow} + - TSL_O=${TSL_O:-Softline} + - TSL_OU=${TSL_OU:-Digital} + + # MinIO настройки + - MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} + - MINIO_PORT=${MINIO_PORT:-9000} + - MINIO_USE_SSL=${MINIO_USE_SSL:-false} + - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-administrator} + - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-123QWEasd} + - MINIO_REGION=${MINIO_REGION:-us-east-1} + - MINIO_BUCKET_NAME=${MINIO_BUCKET_NAME:-store-images} + + # Логирование + - LOG_LEVEL=${LOG_LEVEL:-info} + - STDOUT_LOG_LEVEL=${STDOUT_LOG_LEVEL:-info} + - FILE_LOG_LEVEL=${FILE_LOG_LEVEL:-} + + # JWT Secret (важно для безопасности!) + - JWT_SECRET=${JWT_SECRET:-your-secret-key-change-in-production} + volumes: + # Монтируем сертификаты (если они есть на хосте) + - ./tsl:/app/tsl:ro + # Монтируем логи (опционально) + - ./logs:/app/logs + depends_on: + - postgres + - minio + restart: unless-stopped + networks: + - shop-network + + postgres: + image: ${POSTGRES_IMAGE:-postgres:15-alpine} + container_name: shop-platform-postgres + environment: + - POSTGRES_USER=${POSTGRES_USER:-postgres} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} + - POSTGRES_DB=${POSTGRES_DB:-shop_platform} + volumes: + - postgres_data:/var/lib/postgresql/data + # Можно монтировать SQL скрипты для инициализации + - ./sql:/docker-entrypoint-initdb.d:ro + ports: + - "${POSTGRES_PORT:-5432}:5432" + restart: unless-stopped + networks: + - shop-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] + interval: 10s + timeout: 5s + retries: 5 + + minio: + image: ${MINIO_IMAGE:-minio/minio:latest} + container_name: shop-platform-minio + command: server /data --console-address ":9001" + environment: + - MINIO_ROOT_USER=${MINIO_ACCESS_KEY:-administrator} + - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY:-123QWEasd} + volumes: + - minio_data:/data + ports: + - "${MINIO_PORT:-9000}:9000" + - "9001:9001" # MinIO Console + restart: unless-stopped + networks: + - shop-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + cloudbeaver: + image: ${CLOUDBEAVER_IMAGE:-dbeaver/cloudbeaver:latest} + container_name: shop-platform-cloudbeaver + ports: + - "${CLOUDBEAVER_PORT:-8978}:8978" + volumes: + - cloudbeaver_data:/opt/cloudbeaver/workspace + depends_on: + - postgres + restart: unless-stopped + networks: + - shop-network + +volumes: + postgres_data: + minio_data: + cloudbeaver_data: + +networks: + shop-network: + driver: bridge