mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-20 15:05:08 +00:00
Add deployment tooling: Makefile, scripts, docs
- Makefile: единые команды build/up/update/migrate/assets/backup/shell - scripts/build.sh: сборка образа с apps.json → base64 - scripts/update-apps.sh: проверка последних коммитов приложений через GitHub API - scripts/new-site.sh: создание нового сайта со всеми приложениями - .env.example: шаблон конфигурации с комментариями - DEPLOY.md: документация по развёртыванию и обновлению Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7f5b0a2c47
commit
c60ecbbabc
6 changed files with 444 additions and 0 deletions
45
.env.example
Normal file
45
.env.example
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# ============================================================
|
||||||
|
# Frappe ERP — пример конфигурации (.env.example)
|
||||||
|
# Скопируй в .env и заполни реальными значениями:
|
||||||
|
# cp .env.example .env
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# Версия ERPNext (используется только при PULL_POLICY=always)
|
||||||
|
ERPNEXT_VERSION=v16.9.1
|
||||||
|
|
||||||
|
# Кастомный образ, собранный из apps.json
|
||||||
|
# Собрать: make build
|
||||||
|
CUSTOM_IMAGE=frappe-custom
|
||||||
|
CUSTOM_TAG=v16
|
||||||
|
PULL_POLICY=missing
|
||||||
|
|
||||||
|
# Пароль MariaDB (сгенерируй: openssl rand -base64 32)
|
||||||
|
DB_PASSWORD=CHANGE_ME_use_strong_password
|
||||||
|
|
||||||
|
# Внешняя БД (оставь пустым для встроенной MariaDB)
|
||||||
|
DB_HOST=
|
||||||
|
DB_PORT=
|
||||||
|
|
||||||
|
# Внешний Redis (оставь пустым для встроенного)
|
||||||
|
REDIS_CACHE=
|
||||||
|
REDIS_QUEUE=
|
||||||
|
|
||||||
|
# Имя сайта (должно совпадать с именем, созданным через bench new-site)
|
||||||
|
FRAPPE_SITE_NAME_HEADER=erp.local
|
||||||
|
|
||||||
|
# HTTP-порт публикации
|
||||||
|
HTTP_PUBLISH_PORT=8090
|
||||||
|
|
||||||
|
# Политика перезапуска контейнеров
|
||||||
|
RESTART_POLICY=unless-stopped
|
||||||
|
|
||||||
|
# Таймаут nginx (секунды)
|
||||||
|
PROXY_READ_TIMEOUT=300
|
||||||
|
|
||||||
|
# Максимальный размер тела запроса
|
||||||
|
CLIENT_MAX_BODY_SIZE=100m
|
||||||
|
|
||||||
|
# Расписание автобэкапа (формат ofelia/cron)
|
||||||
|
# @every 6h — каждые 6 часов
|
||||||
|
# 0 2 * * * — каждый день в 02:00
|
||||||
|
BACKUP_CRONSTRING=@every 6h
|
||||||
148
DEPLOY.md
Normal file
148
DEPLOY.md
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
# Frappe ERP — развёртывание и обновление
|
||||||
|
|
||||||
|
## Структура репозитория
|
||||||
|
|
||||||
|
```
|
||||||
|
frappe_docker/
|
||||||
|
├── apps.json ← список приложений для образа
|
||||||
|
├── compose.yaml ← основной docker-compose
|
||||||
|
├── .env ← конфигурация (не в git, создать из .env.example)
|
||||||
|
├── .env.example ← шаблон конфигурации
|
||||||
|
├── Makefile ← все команды управления
|
||||||
|
├── DEPLOY.md ← эта документация
|
||||||
|
│
|
||||||
|
├── images/
|
||||||
|
│ ├── layered/Containerfile ← сборка на базе frappe/build (быстро)
|
||||||
|
│ └── custom/Containerfile ← сборка с нуля (полный контроль)
|
||||||
|
│
|
||||||
|
├── overrides/
|
||||||
|
│ ├── compose.assets-volume.yaml ← общий том assets (обязателен)
|
||||||
|
│ ├── compose.mariadb.yaml ← встроенная MariaDB
|
||||||
|
│ └── ... ← другие оверрайды (proxy, ssl, etc.)
|
||||||
|
│
|
||||||
|
└── scripts/
|
||||||
|
├── build.sh ← сборка образа
|
||||||
|
├── update-apps.sh ← проверка обновлений приложений
|
||||||
|
└── new-site.sh ← создание нового сайта
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Первый запуск
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Создать конфигурацию
|
||||||
|
cp .env.example .env
|
||||||
|
# Отредактировать .env: задать DB_PASSWORD, FRAPPE_SITE_NAME_HEADER и т.д.
|
||||||
|
|
||||||
|
# 2. Собрать образ с приложениями из apps.json
|
||||||
|
make build
|
||||||
|
|
||||||
|
# 3. Запустить стек
|
||||||
|
make up
|
||||||
|
|
||||||
|
# 4. Создать сайт (если ещё не создан)
|
||||||
|
./scripts/new-site.sh erp.local YourAdminPassword
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Обновление приложений
|
||||||
|
|
||||||
|
### Шаг 1 — проверить доступные обновления
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/update-apps.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт покажет последние коммиты каждого приложения из `apps.json`.
|
||||||
|
|
||||||
|
### Шаг 2 — обновить apps.json при необходимости
|
||||||
|
|
||||||
|
Если нужна конкретная ветка или тег:
|
||||||
|
|
||||||
|
```json
|
||||||
|
// apps.json
|
||||||
|
[
|
||||||
|
{ "url": "https://github.com/frappe/erpnext", "branch": "version-16" },
|
||||||
|
{ "url": "https://github.com/frappe/crm", "branch": "main" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Шаг 3 — полный цикл обновления
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make update
|
||||||
|
```
|
||||||
|
|
||||||
|
Это выполнит:
|
||||||
|
1. `make build` — пересборка образа frappe-custom:v16
|
||||||
|
2. `docker compose up -d --no-deps` — замена контейнеров без даунтайма DB/Redis
|
||||||
|
3. `bench migrate` — применение миграций БД
|
||||||
|
4. `bench build` — пересборка JS/CSS assets
|
||||||
|
5. Перезапуск nginx
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Частичные операции
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make migrate # только миграции (после ручного обновления)
|
||||||
|
make assets # только пересборка JS/CSS
|
||||||
|
make restart # перезапуск backend/frontend
|
||||||
|
make backup # резервная копия сайта
|
||||||
|
make logs # логи backend в реальном времени
|
||||||
|
make shell # bash в контейнере backend
|
||||||
|
make ps # статус всех контейнеров
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Смена версии (например, v16 → v17)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Обновить ветки в apps.json
|
||||||
|
# 2. Пересобрать с новым тегом
|
||||||
|
make build TAG=v17
|
||||||
|
|
||||||
|
# 3. Обновить .env
|
||||||
|
# CUSTOM_TAG=v17
|
||||||
|
|
||||||
|
# 4. Пересоздать стек
|
||||||
|
make up
|
||||||
|
make migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Добавление нового приложения
|
||||||
|
|
||||||
|
1. Добавить в `apps.json`:
|
||||||
|
```json
|
||||||
|
{ "url": "https://github.com/frappe/hrms", "branch": "version-16" }
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Пересобрать образ и обновить:
|
||||||
|
```bash
|
||||||
|
make update
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Установить на сайт:
|
||||||
|
```bash
|
||||||
|
make shell
|
||||||
|
bench --site erp.local install-app hrms
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Переменные окружения (.env)
|
||||||
|
|
||||||
|
| Переменная | Описание | Пример |
|
||||||
|
|-------------------------|------------------------------------------|---------------------|
|
||||||
|
| `CUSTOM_IMAGE` | Имя Docker-образа | `frappe-custom` |
|
||||||
|
| `CUSTOM_TAG` | Тег образа | `v16` |
|
||||||
|
| `PULL_POLICY` | `missing` — использовать локальный образ | `missing` |
|
||||||
|
| `DB_PASSWORD` | Пароль MariaDB | (сильный пароль) |
|
||||||
|
| `FRAPPE_SITE_NAME_HEADER` | Имя сайта | `erp.local` |
|
||||||
|
| `HTTP_PUBLISH_PORT` | Внешний порт HTTP | `8090` |
|
||||||
|
| `BACKUP_CRONSTRING` | Расписание бэкапов | `@every 6h` |
|
||||||
109
Makefile
Normal file
109
Makefile
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
# ============================================================
|
||||||
|
# Frappe ERP — управление стеком
|
||||||
|
# Использование: make <target>
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
SHELL := /bin/bash
|
||||||
|
SITE ?= erp.local
|
||||||
|
TAG ?= v16
|
||||||
|
|
||||||
|
COMPOSE_OVERRIDES := \
|
||||||
|
-f compose.yaml \
|
||||||
|
-f overrides/compose.assets-volume.yaml
|
||||||
|
|
||||||
|
APPS_JSON_B64 := $(shell base64 -w 0 apps.json)
|
||||||
|
|
||||||
|
.PHONY: help build up down restart update migrate assets backup logs ps shell
|
||||||
|
|
||||||
|
# ── Справка ─────────────────────────────────────────────────
|
||||||
|
help:
|
||||||
|
@echo ""
|
||||||
|
@echo " Frappe ERP — доступные команды:"
|
||||||
|
@echo ""
|
||||||
|
@echo " Образ:"
|
||||||
|
@echo " make build — собрать frappe-custom:$(TAG) из apps.json"
|
||||||
|
@echo " make build TAG=v17 — собрать с другим тегом"
|
||||||
|
@echo ""
|
||||||
|
@echo " Стек:"
|
||||||
|
@echo " make up — запустить все контейнеры"
|
||||||
|
@echo " make down — остановить и удалить контейнеры"
|
||||||
|
@echo " make restart — перезапустить backend/frontend"
|
||||||
|
@echo " make ps — статус контейнеров"
|
||||||
|
@echo ""
|
||||||
|
@echo " Обновление:"
|
||||||
|
@echo " make update — rebuild образа + up + migrate + assets"
|
||||||
|
@echo " make migrate — bench migrate на сайте $(SITE)"
|
||||||
|
@echo " make assets — пересобрать JS/CSS бандлы"
|
||||||
|
@echo ""
|
||||||
|
@echo " Обслуживание:"
|
||||||
|
@echo " make backup — создать резервную копию сайта"
|
||||||
|
@echo " make logs — логи backend (live)"
|
||||||
|
@echo " make shell — bash в backend контейнере"
|
||||||
|
@echo ""
|
||||||
|
|
||||||
|
# ── Сборка образа ────────────────────────────────────────────
|
||||||
|
build:
|
||||||
|
@echo "→ Сборка frappe-custom:$(TAG) из apps.json..."
|
||||||
|
docker build \
|
||||||
|
--build-arg APPS_JSON_BASE64=$(APPS_JSON_B64) \
|
||||||
|
--build-arg FRAPPE_BRANCH=version-16 \
|
||||||
|
-t frappe-custom:$(TAG) \
|
||||||
|
-f images/layered/Containerfile \
|
||||||
|
.
|
||||||
|
@echo "✓ Образ frappe-custom:$(TAG) готов"
|
||||||
|
|
||||||
|
# ── Запуск стека ─────────────────────────────────────────────
|
||||||
|
up:
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) up -d
|
||||||
|
@echo "✓ Стек запущен. Сайт: http://localhost:$${HTTP_PUBLISH_PORT:-8090}"
|
||||||
|
|
||||||
|
down:
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) down
|
||||||
|
|
||||||
|
restart:
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) restart backend frontend websocket
|
||||||
|
|
||||||
|
ps:
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) ps
|
||||||
|
|
||||||
|
# ── Обновление (полный цикл) ─────────────────────────────────
|
||||||
|
update: build
|
||||||
|
@echo "→ Пересоздаём контейнеры с новым образом..."
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) up -d --no-deps backend websocket queue-short queue-long scheduler
|
||||||
|
@echo "→ Ждём готовности backend..."
|
||||||
|
sleep 10
|
||||||
|
$(MAKE) migrate
|
||||||
|
$(MAKE) assets
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) restart frontend
|
||||||
|
@echo "✓ Обновление завершено"
|
||||||
|
|
||||||
|
# ── Миграции БД ──────────────────────────────────────────────
|
||||||
|
migrate:
|
||||||
|
@echo "→ bench migrate --site $(SITE)..."
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) exec backend \
|
||||||
|
bench --site $(SITE) migrate
|
||||||
|
@echo "✓ Миграция завершена"
|
||||||
|
|
||||||
|
# ── Пересборка JS/CSS ────────────────────────────────────────
|
||||||
|
assets:
|
||||||
|
@echo "→ Пересборка assets..."
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) exec backend \
|
||||||
|
bash -c "cd apps/frappe && node esbuild --production"
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) exec backend \
|
||||||
|
bench build
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) restart frontend
|
||||||
|
@echo "✓ Assets пересобраны"
|
||||||
|
|
||||||
|
# ── Резервная копия ──────────────────────────────────────────
|
||||||
|
backup:
|
||||||
|
@echo "→ Создание резервной копии сайта $(SITE)..."
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) exec backend \
|
||||||
|
bench --site $(SITE) backup --with-files
|
||||||
|
@echo "✓ Бэкап создан (см. sites/$(SITE)/private/backups/)"
|
||||||
|
|
||||||
|
# ── Логи и отладка ───────────────────────────────────────────
|
||||||
|
logs:
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) logs -f backend
|
||||||
|
|
||||||
|
shell:
|
||||||
|
docker compose $(COMPOSE_OVERRIDES) exec backend bash
|
||||||
48
scripts/build.sh
Executable file
48
scripts/build.sh
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# Сборка образа frappe-custom
|
||||||
|
# Использование: ./scripts/build.sh [tag]
|
||||||
|
# По умолчанию: tag = v16
|
||||||
|
# ============================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TAG="${1:-v16}"
|
||||||
|
FRAPPE_BRANCH="${FRAPPE_BRANCH:-version-16}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
|
echo "╔══════════════════════════════════════════════╗"
|
||||||
|
echo " Сборка frappe-custom:${TAG}"
|
||||||
|
echo " Ветка Frappe : ${FRAPPE_BRANCH}"
|
||||||
|
echo " Репозиторий : ${REPO_DIR}"
|
||||||
|
echo "╚══════════════════════════════════════════════╝"
|
||||||
|
|
||||||
|
cd "$REPO_DIR"
|
||||||
|
|
||||||
|
# Проверяем apps.json
|
||||||
|
if [ ! -f apps.json ]; then
|
||||||
|
echo "✗ Файл apps.json не найден"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "→ Приложения из apps.json:"
|
||||||
|
python3 -c "import json; [print(' -', a['url'].split('/')[-1], '@', a['branch']) for a in json.load(open('apps.json'))]"
|
||||||
|
|
||||||
|
# Кодируем apps.json в base64
|
||||||
|
APPS_JSON_B64=$(base64 -w 0 apps.json)
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "→ Запуск docker build..."
|
||||||
|
docker build \
|
||||||
|
--build-arg APPS_JSON_BASE64="$APPS_JSON_B64" \
|
||||||
|
--build-arg FRAPPE_BRANCH="$FRAPPE_BRANCH" \
|
||||||
|
-t "frappe-custom:${TAG}" \
|
||||||
|
-f images/layered/Containerfile \
|
||||||
|
.
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Образ frappe-custom:${TAG} собран"
|
||||||
|
echo ""
|
||||||
|
echo "Следующий шаг:"
|
||||||
|
echo " make update # пересоздать контейнеры, мигрировать БД, пересобрать assets"
|
||||||
|
echo " make up # просто запустить (если контейнеры не существуют)"
|
||||||
48
scripts/new-site.sh
Executable file
48
scripts/new-site.sh
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# Создание нового Frappe-сайта
|
||||||
|
# Использование: ./scripts/new-site.sh <site-name> <admin-password>
|
||||||
|
# Пример: ./scripts/new-site.sh mycompany.local Admin123
|
||||||
|
# ============================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SITE="${1:-}"
|
||||||
|
ADMIN_PASS="${2:-}"
|
||||||
|
|
||||||
|
if [ -z "$SITE" ] || [ -z "$ADMIN_PASS" ]; then
|
||||||
|
echo "Использование: $0 <site-name> <admin-password>"
|
||||||
|
echo "Пример: $0 mycompany.local Admin123"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
|
cd "$REPO_DIR"
|
||||||
|
|
||||||
|
COMPOSE_OVERRIDES="-f compose.yaml -f overrides/compose.assets-volume.yaml"
|
||||||
|
|
||||||
|
echo "→ Создание сайта: $SITE"
|
||||||
|
|
||||||
|
docker compose $COMPOSE_OVERRIDES exec backend \
|
||||||
|
bench new-site "$SITE" \
|
||||||
|
--mariadb-root-password "$(grep DB_PASSWORD .env | cut -d= -f2)" \
|
||||||
|
--admin-password "$ADMIN_PASS" \
|
||||||
|
--install-app erpnext
|
||||||
|
|
||||||
|
echo "→ Устанавливаем дополнительные приложения..."
|
||||||
|
for APP in crm helpdesk payments insights lms; do
|
||||||
|
echo " + $APP"
|
||||||
|
docker compose $COMPOSE_OVERRIDES exec backend \
|
||||||
|
bench --site "$SITE" install-app "$APP" || echo " ! $APP пропущен (возможно не нужен)"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "→ Запуск миграций..."
|
||||||
|
docker compose $COMPOSE_OVERRIDES exec backend \
|
||||||
|
bench --site "$SITE" migrate
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Сайт $SITE создан"
|
||||||
|
echo " URL: http://localhost:${HTTP_PUBLISH_PORT:-8090}"
|
||||||
|
echo " Логин: Administrator"
|
||||||
|
echo " Пароль: $ADMIN_PASS"
|
||||||
46
scripts/update-apps.sh
Executable file
46
scripts/update-apps.sh
Executable file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ============================================================
|
||||||
|
# Обновление версий приложений в apps.json
|
||||||
|
# Проверяет последние коммиты каждого приложения
|
||||||
|
# Использование: ./scripts/update-apps.sh
|
||||||
|
# ============================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
APPS_FILE="$REPO_DIR/apps.json"
|
||||||
|
|
||||||
|
echo "╔══════════════════════════════════════════════╗"
|
||||||
|
echo " Проверка обновлений приложений"
|
||||||
|
echo "╚══════════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
python3 -c "
|
||||||
|
import json, urllib.request, sys
|
||||||
|
|
||||||
|
apps = json.load(open('$APPS_FILE'))
|
||||||
|
|
||||||
|
for app in apps:
|
||||||
|
url = app['url']
|
||||||
|
branch = app['branch']
|
||||||
|
name = url.rstrip('/').split('/')[-1]
|
||||||
|
|
||||||
|
# GitHub API: последний коммит ветки
|
||||||
|
api_url = url.replace('https://github.com/', 'https://api.github.com/repos/') + '/commits/' + branch
|
||||||
|
try:
|
||||||
|
req = urllib.request.Request(api_url, headers={'User-Agent': 'frappe-update-check'})
|
||||||
|
data = json.loads(urllib.request.urlopen(req, timeout=5).read())
|
||||||
|
sha = data['sha'][:8]
|
||||||
|
date = data['commit']['committer']['date'][:10]
|
||||||
|
msg = data['commit']['message'].splitlines()[0][:60]
|
||||||
|
print(f' {name:20s} [{branch}] последний коммит: {sha} ({date})')
|
||||||
|
print(f' {msg}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f' {name:20s} [{branch}] ошибка проверки: {e}')
|
||||||
|
print()
|
||||||
|
"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Чтобы обновить образ после изменения apps.json:"
|
||||||
|
echo " make build — только пересобрать образ"
|
||||||
|
echo " make update — полный цикл (build + migrate + assets)"
|
||||||
Loading…
Reference in a new issue