refactor: deploy model — all files under /opt/pulse-lets-go

Single prefix deployment: /opt/pulse-lets-go/ contains
bin/, data/, web/, log/ — no more split across
/usr/local/bin, /etc, /usr/local/share, /var/log.

* Makefile: install → deploy target with PREFIX=/opt/pulse-lets-go
* deploy/pulse-lets-go.service: all paths under /opt/pulse-lets-go,
  removed stale nats.service dependency
* main.go: default dataDir = parent of exeDir (PREFIX/bin → PREFIX/data)
* README: updated all paths, step 1 uses make deploy
This commit is contained in:
Maksim Totmin 2026-06-25 19:35:54 +07:00
parent 2917f4de44
commit 64f9f20500
4 changed files with 46 additions and 46 deletions

View File

@ -4,9 +4,9 @@
APP := pulse-lets-go APP := pulse-lets-go
BINDIR := bin BINDIR := bin
WEB_DIR := web WEB_DIR := web
DATA_DIR := data PREFIX := /opt/pulse-lets-go
.PHONY: all build build-go build-web clean run test install \ .PHONY: all build build-go build-web clean run test deploy \
emulate emulate-normal emulate-overload emulate-cpu-low emulate-fail-high \ emulate emulate-normal emulate-overload emulate-cpu-low emulate-fail-high \
emulate-node-down emulate-stale emulate-chaos build-emulator \ emulate-node-down emulate-stale emulate-chaos build-emulator \
build-siptest siptest-uas siptest-uac siptest-full build-siptest siptest-uas siptest-uac siptest-full
@ -50,21 +50,23 @@ build-prod:
rm -rf $(BINDIR)/web && cp -r $(WEB_DIR)/build $(BINDIR)/web rm -rf $(BINDIR)/web && cp -r $(WEB_DIR)/build $(BINDIR)/web
CGO_ENABLED=0 go build -ldflags="-s -w" -o $(BINDIR)/$(APP) ./cmd/$(APP) CGO_ENABLED=0 go build -ldflags="-s -w" -o $(BINDIR)/$(APP) ./cmd/$(APP)
# Установка: копирует бинарник и статику в /usr/local # Деплой в PREFIX: бинарник + статика + data + log
install: build deploy: build-prod
@echo "→ Установка в /usr/local" @echo "→ Деплой в $(PREFIX)"
mkdir -p /usr/local/share/$(APP)/web install -d $(PREFIX)/bin $(PREFIX)/data $(PREFIX)/web $(PREFIX)/log
cp -r $(WEB_DIR)/build /usr/local/share/$(APP)/web/ install -m 755 $(BINDIR)/$(APP) $(PREFIX)/bin/
cp $(BINDIR)/$(APP) /usr/local/bin/$(APP) cp -r $(WEB_DIR)/build/. $(PREFIX)/web/
chmod +x /usr/local/bin/$(APP) @echo "✓ Готово: $(PREFIX)"
@echo "✓ Установлен в /usr/local/bin/$(APP)" @echo " $(PREFIX)/bin/$(APP)"
@echo " $(PREFIX)/web/ (SvelteKit статика)"
@echo " $(PREFIX)/data/ (config.json, trunks.json, users.json)"
@echo " $(PREFIX)/log/ (ASCII-лог метрик)"
# Установка systemd unit # Установка systemd unit
install-systemd: install-systemd:
@echo "→ Установка systemd unit" install -m 644 deploy/$(APP).service /etc/systemd/system/
cp deploy/$(APP).service /etc/systemd/system/
systemctl daemon-reload systemctl daemon-reload
@echo "✓ systemd unit установлен. Запуск: systemctl start $(APP)" @echo "✓ systemd unit установлен. Запуск: sudo systemctl start $(APP)"
# ============================================================ # ============================================================
# Эмулятор метрик # Эмулятор метрик

View File

@ -423,7 +423,7 @@ end
### systemd ### systemd
```bash ```bash
make install # копирует бинарник + web-статику make deploy # полный деплой в /opt/pulse-lets-go
make install-systemd # устанавливает systemd unit make install-systemd # устанавливает systemd unit
``` ```
@ -436,16 +436,15 @@ After=network.target
[Service] [Service]
User=pulse User=pulse
Group=pulse Group=pulse
WorkingDirectory=/usr/local/share/pulse-lets-go ExecStart=/opt/pulse-lets-go/bin/pulse-lets-go
Environment=PULSE_DATA_DIR=/etc/pulse-lets-go WorkingDirectory=/opt/pulse-lets-go
ExecStart=/usr/local/bin/pulse-lets-go
Restart=always Restart=always
RestartSec=5 RestartSec=5
NoNewPrivileges=true NoNewPrivileges=true
PrivateTmp=true PrivateTmp=true
ProtectSystem=strict ProtectSystem=strict
ProtectHome=yes ProtectHome=yes
ReadWritePaths=/etc/pulse-lets-go /var/log/pulse-lets-go ReadWritePaths=/opt/pulse-lets-go/data /opt/pulse-lets-go/log
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
@ -454,13 +453,14 @@ WantedBy=multi-user.target
### Структура директорий ### Структура директорий
``` ```
/usr/local/share/pulse-lets-go/ /opt/pulse-lets-go/
├── web/build/ # SvelteKit статика ├── bin/pulse-lets-go # Бинарник
/etc/pulse-lets-go/ ├── data/
├── config.json # Конфигурация │ ├── config.json # Конфигурация
├── trunks.json # Транки │ ├── trunks.json # Транки
├── users.json # Пользователи │ └── users.json # Пользователи
/var/log/pulse-lets-go/ ├── web/ # SvelteKit статика
└── log/
└── metrics.YYYY-MM-DD.log # ASCII-лог метрик └── metrics.YYYY-MM-DD.log # ASCII-лог метрик
``` ```
@ -497,13 +497,13 @@ fs_cli -x "load mod_curl"
# <load module="mod_curl"/> # <load module="mod_curl"/>
``` ```
### Порядок деплоя (7 шагов) ### Порядок деплоя (8 шагов)
**Шаг 1 — Скопировать бинарник и конфиги** **Шаг 1 — Деплой на сервер**
```bash ```bash
make build-prod make deploy
scp bin/pulse-lets-go admin@balancer.lan:/usr/local/bin/ scp -r /opt/pulse-lets-go admin@balancer.lan:/opt/
scp -r contrib/route.lua admin@balancer.lan:/tmp/ scp contrib/route.lua admin@balancer.lan:/tmp/
``` ```
**Шаг 2 — NATS сервер** (если не установлен) **Шаг 2 — NATS сервер** (если не установлен)
@ -562,11 +562,10 @@ curl -X POST .../api/trunks
**Шаг 7 — Запуск pulse-lets-go** **Шаг 7 — Запуск pulse-lets-go**
```bash ```bash
sudo mkdir -p /etc/pulse-lets-go /var/log/pulse-lets-go # config.json создастся автоматически при первом запуске в /opt/pulse-lets-go/data/
# config.json создастся автоматически при первом запуске
# Добавить esl блок в config.json: # Добавить esl блок в config.json:
# "esl": {"host": "127.0.0.1", "port": 8021, "password": "ClueCon"} # "esl": {"host": "127.0.0.1", "port": 8021, "password": "ClueCon"}
PULSE_DATA_DIR=/etc/pulse-lets-go ./pulse-lets-go /opt/pulse-lets-go/bin/pulse-lets-go
``` ```
**Шаг 8 — Проверка** **Шаг 8 — Проверка**

View File

@ -27,11 +27,12 @@ import (
func main() { func main() {
// Определяем рабочую директорию // Определяем рабочую директорию
// По умолчанию data/ — родительская папка от бинарника.
// Пример: /opt/pulse-lets-go/bin/pulse-lets-go → /opt/pulse-lets-go/data
exe, _ := os.Executable() exe, _ := os.Executable()
exeDir := filepath.Dir(exe) exeDir := filepath.Dir(exe)
dataDir := filepath.Join(exeDir, "data") dataDir := filepath.Join(filepath.Dir(exeDir), "data")
// Разрешаем переопределение через переменную окружения
if envDir := os.Getenv("PULSE_DATA_DIR"); envDir != "" { if envDir := os.Getenv("PULSE_DATA_DIR"); envDir != "" {
dataDir = envDir dataDir = envDir
} }
@ -235,13 +236,13 @@ func main() {
} }
// findWebDir ищет директорию со SvelteKit сборкой (web/build/). // findWebDir ищет директорию со SvelteKit сборкой (web/build/).
// Пробует по порядку: переменная окружения, рядом с бинарником, в корне проекта, CWD. // Пробует по порядку: PULSE_WEB_DIR, CWD, ../web/build, рядом с бинарником.
func findWebDir(exeDir string) string { func findWebDir(exeDir string) string {
candidates := []string{ candidates := []string{
os.Getenv("PULSE_WEB_DIR"), os.Getenv("PULSE_WEB_DIR"),
"web/build", // ./web/build (CWD — dev, systemd working dir) "web/build", // ./web/build (CWD — dev, systemd working dir)
filepath.Join(filepath.Dir(exeDir), "web", "build"), // ../web/build (корень проекта, dev с bin/) filepath.Join(filepath.Dir(exeDir), "web", "build"), // ../web/build (корень проекта, dev с bin/)
filepath.Join(exeDir, "web", "build"), // рядом с бинарником (production install) filepath.Join(exeDir, "web", "build"), // рядом с бинарником (production install, make deploy)
} }
for _, d := range candidates { for _, d := range candidates {
if d == "" { if d == "" {

View File

@ -1,16 +1,14 @@
[Unit] [Unit]
Description=pulse-lets-go — Telephone Load Balancer Description=pulse-lets-go — Telephone Load Balancer
Documentation=https://github.com/pulse-lets-go Documentation=https://github.com/pulse-lets-go
After=network.target nats.service After=network.target
Wants=nats.service
[Service] [Service]
Type=simple Type=simple
User=pulse User=pulse
Group=pulse Group=pulse
ExecStart=/usr/local/bin/pulse-lets-go ExecStart=/opt/pulse-lets-go/bin/pulse-lets-go
WorkingDirectory=/usr/local/share/pulse-lets-go WorkingDirectory=/opt/pulse-lets-go
Environment=PULSE_DATA_DIR=/etc/pulse-lets-go
Restart=always Restart=always
RestartSec=5 RestartSec=5
@ -19,7 +17,7 @@ NoNewPrivileges=yes
PrivateTmp=yes PrivateTmp=yes
ProtectSystem=strict ProtectSystem=strict
ProtectHome=yes ProtectHome=yes
ReadWritePaths=/etc/pulse-lets-go /var/log/pulse-lets-go ReadWritePaths=/opt/pulse-lets-go/data /opt/pulse-lets-go/log
# Логирование # Логирование
StandardOutput=journal StandardOutput=journal