feat: Go backend, enhanced search, new widgets, Docker deploy
Major changes: - Add Go backend (backend/) with microservices architecture - Enhanced master-agents-svc: reranker, content-classifier, stealth-crawler, proxy-manager, media-search, fastClassifier, language detection - New web-svc widgets: KnowledgeCard, ProductCard, ProfileCard, VideoCard, UnifiedCard, CardGallery, InlineImageGallery, SourcesPanel, RelatedQuestions - Improved discover-svc with discover-db integration - Docker deployment improvements (Caddyfile, vendor.sh, BUILD.md) - Library-svc: project_id schema migration - Remove deprecated finance-svc and travel-svc - Localization improvements across services Made-with: Cursor
This commit is contained in:
34
deploy/docker/BUILD.md
Normal file
34
deploy/docker/BUILD.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Сборка Docker (GooSeek)
|
||||
|
||||
## Почему в логе «дубли» и много строк подряд
|
||||
|
||||
**Это не дубли.** Собираются **15+ образов параллельно** (cache-worker, chat-svc, api-gateway, web-svc, search-svc, localization-svc, travel-svc, caddy, auth-svc, library-svc, master-agents-svc, projects-svc, llm-svc, discover-svc, geo-device-svc и др.). У каждого свой шаг `RUN npm install`, и вывод в терминале **перемешан** — поэтому кажется, что одна и та же строка повторяется. На самом деле это разные сервисы.
|
||||
|
||||
## Ресурсы: хватает ли?
|
||||
|
||||
- **Ошибка в логе** — `ECONNRESET` при `npm install`: «Client network socket disconnected before secure TLS connection was established». Это **сетевой сбой** (или лимиты при большом числе одновременных запросов к registry), а не нехватка RAM/CPU.
|
||||
- То есть **ресурсов машины обычно хватает**; проблема в том, что при параллельной сборке много образов одновременно качают пакеты с registry.npmjs.org, и часть соединений обрывается.
|
||||
|
||||
## Что сделано для устойчивости
|
||||
|
||||
Во всех сервисных Dockerfile добавлено:
|
||||
|
||||
1. **Кэш npm** — `RUN --mount=type=cache,target=/root/.npm ... npm install`. Повторные сборки меньше ходят в сеть.
|
||||
2. **Повторы при сбоях** — `--fetch-retries=5 --fetch-retry-mintimeout=20000 --fetch-retry-maxtimeout=120000`. При обрыве соединения npm повторяет запрос.
|
||||
|
||||
Так сборка становится устойчивее к нестабильной сети и к параллельной нагрузке на registry.
|
||||
|
||||
## Если сборка всё равно падает по сети
|
||||
|
||||
1. **Повторить** — часто помогает второй запуск `./run.sh`.
|
||||
2. **Собрать по одному сервису** (из каталога `deploy/docker`):
|
||||
```bash
|
||||
docker compose -f docker-compose.yml --env-file ../../.env build localization-svc
|
||||
docker compose -f docker-compose.yml --env-file ../../.env build chat-svc
|
||||
# … и т.д.
|
||||
```
|
||||
3. **Проверить сеть** — VPN, прокси, нестабильный Wi‑Fi могут вызывать ECONNRESET.
|
||||
|
||||
## Долго билдится
|
||||
|
||||
Сборка 15+ Node-образов с полным `npm install` в каждом — тяжёлая операция (сотни секунд). Это нормально. С кэшем npm повторные сборки после небольших изменений будут быстрее.
|
||||
@@ -1,7 +1,38 @@
|
||||
# gooseek.ru — reverse proxy к web-svc
|
||||
# gooseek.ru, bait.su — reverse proxy
|
||||
# Caddy автоматически получает SSL от Let's Encrypt
|
||||
# Защита от DDoS: rate_limit (per-IP), лимит тела запроса
|
||||
#
|
||||
# Healthcheck Docker: запросы с 127.0.0.1 получают 200 без редиректа и без rate_limit,
|
||||
# иначе wget --spider падает на редиректе и autoheal постоянно перезапускает контейнер.
|
||||
http://127.0.0.1 {
|
||||
respond 200
|
||||
}
|
||||
|
||||
gooseek.ru, www.gooseek.ru {
|
||||
request_body {
|
||||
max_size 10MB
|
||||
}
|
||||
rate_limit {
|
||||
zone per_ip {
|
||||
key {http.request.remote.host}
|
||||
events 300
|
||||
window 1m
|
||||
}
|
||||
}
|
||||
header Cache-Control "no-cache, no-store, must-revalidate"
|
||||
reverse_proxy web-svc:3000
|
||||
}
|
||||
|
||||
bait.su, www.bait.su {
|
||||
request_body {
|
||||
max_size 10MB
|
||||
}
|
||||
rate_limit {
|
||||
zone per_ip {
|
||||
key {http.request.remote.host}
|
||||
events 300
|
||||
window 1m
|
||||
}
|
||||
}
|
||||
reverse_proxy ghost:2368
|
||||
}
|
||||
|
||||
7
deploy/docker/Dockerfile.caddy
Normal file
7
deploy/docker/Dockerfile.caddy
Normal file
@@ -0,0 +1,7 @@
|
||||
# Caddy 2 с плагином rate_limit для защиты от DDoS (per-IP лимиты)
|
||||
# Оригинал mholt/caddy-ratelimit (distributed через storage при необходимости)
|
||||
FROM caddy:2-builder AS builder
|
||||
RUN xcaddy build --with github.com/mholt/caddy-ratelimit
|
||||
|
||||
FROM caddy:2-alpine
|
||||
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
|
||||
@@ -1,12 +1,22 @@
|
||||
# GooSeek — запуск в Docker (без Kubernetes)
|
||||
# gooseek.ru → reverse-proxy (80/443) → web-svc:3000
|
||||
#
|
||||
# Защита от DDoS: reverse-proxy — rate_limit (120 req/min на IP), лимит тела 10MB, лимиты памяти/CPU.
|
||||
#
|
||||
# Самовосстановление (аналог Kubernetes):
|
||||
# - restart: unless-stopped — перезапуск при падении процесса
|
||||
# - healthcheck — проверка живости; статус (healthy/unhealthy) виден в docker ps
|
||||
# - autoheal — перезапускает контейнеры с меткой autoheal=true при переходе в unhealthy
|
||||
#
|
||||
# Запуск: ./deploy/docker/run.sh
|
||||
# Порты 80 и 443 должны быть открыты на роутере (проброс на ПК)
|
||||
|
||||
services:
|
||||
reverse-proxy:
|
||||
image: caddy:2-alpine
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.caddy
|
||||
image: gooseek/caddy-ratelimit:latest
|
||||
container_name: gooseek-reverse-proxy
|
||||
ports:
|
||||
- "80:80"
|
||||
@@ -17,12 +27,36 @@ services:
|
||||
- caddy-config:/config
|
||||
depends_on:
|
||||
- web-svc
|
||||
- ghost
|
||||
restart: unless-stopped
|
||||
mem_limit: 512m
|
||||
cpus: 0.5
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: "0.5"
|
||||
reservations:
|
||||
memory: 64M
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 65535
|
||||
hard: 65535
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:80/"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
web-svc:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/web-svc/Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
args:
|
||||
API_GATEWAY_URL: "http://api-gateway:3015"
|
||||
image: gooseek/web-svc:latest
|
||||
@@ -35,11 +69,21 @@ services:
|
||||
depends_on:
|
||||
- api-gateway
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
api-gateway:
|
||||
build:
|
||||
context: ../../services/api-gateway
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/api-gateway:latest
|
||||
container_name: gooseek-api-gateway
|
||||
ports:
|
||||
@@ -68,12 +112,23 @@ services:
|
||||
- auth-svc
|
||||
- llm-svc
|
||||
- chat-svc
|
||||
- library-svc
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3015/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
geo-device-svc:
|
||||
build:
|
||||
context: ../../services/geo-device-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/geo-device-svc:latest
|
||||
container_name: gooseek-geo-device-svc
|
||||
ports:
|
||||
@@ -81,11 +136,21 @@ services:
|
||||
environment:
|
||||
PORT: "4002"
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:4002/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
|
||||
localization-svc:
|
||||
build:
|
||||
context: ../../services/localization-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/localization-svc:latest
|
||||
container_name: gooseek-localization-svc
|
||||
ports:
|
||||
@@ -96,28 +161,58 @@ services:
|
||||
depends_on:
|
||||
- geo-device-svc
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:4003/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
discover-svc:
|
||||
build:
|
||||
context: ../../services/discover-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/discover-svc:latest
|
||||
container_name: gooseek-discover-svc
|
||||
env_file:
|
||||
- ../../.env
|
||||
ports:
|
||||
- "3002:3002"
|
||||
environment:
|
||||
PORT: "3002"
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
GEO_DEVICE_SERVICE_URL: "http://geo-device-svc:4002"
|
||||
SEARXNG_URL: "http://searxng:8080"
|
||||
GHOST_URL: "http://ghost:2368"
|
||||
DISCOVER_DB_PATH: "/data/discover_articles.db"
|
||||
# GHOST_CONTENT_API_KEY — из env_file ../../.env
|
||||
volumes:
|
||||
- discover-db-data:/data
|
||||
depends_on:
|
||||
- redis
|
||||
- geo-device-svc
|
||||
- searxng
|
||||
- ghost
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3002/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
travel-svc:
|
||||
build:
|
||||
context: ../../services/travel-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/travel-svc:latest
|
||||
container_name: gooseek-travel-svc
|
||||
ports:
|
||||
@@ -128,11 +223,21 @@ services:
|
||||
depends_on:
|
||||
- redis
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3004/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
auth-svc:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: services/auth-svc/Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/auth-svc:latest
|
||||
container_name: gooseek-auth-svc
|
||||
ports:
|
||||
@@ -146,11 +251,21 @@ services:
|
||||
volumes:
|
||||
- auth-data:/data
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3014/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
llm-svc:
|
||||
build:
|
||||
context: ../../services/llm-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/llm-svc:latest
|
||||
container_name: gooseek-llm-svc
|
||||
env_file:
|
||||
@@ -165,6 +280,14 @@ services:
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3020/health"]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
@@ -174,6 +297,134 @@ services:
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
|
||||
crawl4ai:
|
||||
image: unclecode/crawl4ai:latest
|
||||
container_name: gooseek-crawl4ai
|
||||
ports:
|
||||
- "11235:11235"
|
||||
shm_size: "1g"
|
||||
environment:
|
||||
- CRAWL4AI_API_TOKEN=${CRAWL4AI_API_TOKEN:-}
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
cpus: "2.0"
|
||||
reservations:
|
||||
memory: 1G
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:11235/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
cache-worker-tech:
|
||||
build:
|
||||
context: ../../services/cache-worker
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/cache-worker:latest
|
||||
container_name: gooseek-cache-worker-tech
|
||||
environment:
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
FINANCE_SVC_URL: "http://finance-svc:3003"
|
||||
TRAVEL_SVC_URL: "http://travel-svc:3004"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
CRAWL4AI_URL: "http://crawl4ai:11235"
|
||||
command: ["sh", "-c", "node dist/run.js --task=discover --topic=tech; while true; do sleep 900; node dist/run.js --task=discover --topic=tech; done"]
|
||||
depends_on:
|
||||
- redis
|
||||
- discover-svc
|
||||
- llm-svc
|
||||
- crawl4ai
|
||||
restart: unless-stopped
|
||||
|
||||
cache-worker-finance:
|
||||
image: gooseek/cache-worker:latest
|
||||
container_name: gooseek-cache-worker-finance
|
||||
environment:
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
FINANCE_SVC_URL: "http://finance-svc:3003"
|
||||
TRAVEL_SVC_URL: "http://travel-svc:3004"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
CRAWL4AI_URL: "http://crawl4ai:11235"
|
||||
command: ["sh", "-c", "node dist/run.js --task=discover --topic=finance; while true; do sleep 900; node dist/run.js --task=discover --topic=finance; done"]
|
||||
depends_on:
|
||||
- redis
|
||||
- discover-svc
|
||||
- llm-svc
|
||||
- crawl4ai
|
||||
restart: unless-stopped
|
||||
|
||||
cache-worker-art:
|
||||
image: gooseek/cache-worker:latest
|
||||
container_name: gooseek-cache-worker-art
|
||||
environment:
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
FINANCE_SVC_URL: "http://finance-svc:3003"
|
||||
TRAVEL_SVC_URL: "http://travel-svc:3004"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
CRAWL4AI_URL: "http://crawl4ai:11235"
|
||||
command: ["sh", "-c", "node dist/run.js --task=discover --topic=art; while true; do sleep 900; node dist/run.js --task=discover --topic=art; done"]
|
||||
depends_on:
|
||||
- redis
|
||||
- discover-svc
|
||||
- llm-svc
|
||||
- crawl4ai
|
||||
restart: unless-stopped
|
||||
|
||||
cache-worker-sports:
|
||||
image: gooseek/cache-worker:latest
|
||||
container_name: gooseek-cache-worker-sports
|
||||
environment:
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
FINANCE_SVC_URL: "http://finance-svc:3003"
|
||||
TRAVEL_SVC_URL: "http://travel-svc:3004"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
CRAWL4AI_URL: "http://crawl4ai:11235"
|
||||
command: ["sh", "-c", "node dist/run.js --task=discover --topic=sports; while true; do sleep 900; node dist/run.js --task=discover --topic=sports; done"]
|
||||
depends_on:
|
||||
- redis
|
||||
- discover-svc
|
||||
- llm-svc
|
||||
- crawl4ai
|
||||
restart: unless-stopped
|
||||
|
||||
cache-worker-entertainment:
|
||||
image: gooseek/cache-worker:latest
|
||||
container_name: gooseek-cache-worker-entertainment
|
||||
environment:
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
FINANCE_SVC_URL: "http://finance-svc:3003"
|
||||
TRAVEL_SVC_URL: "http://travel-svc:3004"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
CRAWL4AI_URL: "http://crawl4ai:11235"
|
||||
command: ["sh", "-c", "node dist/run.js --task=discover --topic=entertainment; while true; do sleep 900; node dist/run.js --task=discover --topic=entertainment; done"]
|
||||
depends_on:
|
||||
- redis
|
||||
- discover-svc
|
||||
- llm-svc
|
||||
- crawl4ai
|
||||
restart: unless-stopped
|
||||
|
||||
searxng:
|
||||
image: searxng/searxng:latest
|
||||
@@ -187,11 +438,80 @@ services:
|
||||
environment:
|
||||
SEARXNG_BASE_URL: "http://localhost:8080/"
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/"]
|
||||
interval: 20s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
ghost-db:
|
||||
image: mysql:8
|
||||
container_name: gooseek-ghost-db
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${GHOST_DB_ROOT_PASSWORD:-ghost_root}
|
||||
MYSQL_DATABASE: ghost
|
||||
MYSQL_USER: ghost
|
||||
MYSQL_PASSWORD: ${GHOST_DB_PASSWORD:-ghost}
|
||||
volumes:
|
||||
- ghost-db-data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p\"$$MYSQL_ROOT_PASSWORD\" || exit 1"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
|
||||
ghost:
|
||||
image: ghost:6-alpine
|
||||
container_name: gooseek-ghost
|
||||
ports:
|
||||
- "2368:2368"
|
||||
env_file:
|
||||
- ../../.env
|
||||
environment:
|
||||
url: "https://bait.su"
|
||||
database__client: mysql
|
||||
database__connection__host: ghost-db
|
||||
database__connection__user: ghost
|
||||
database__connection__password: ${GHOST_DB_PASSWORD:-ghost}
|
||||
database__connection__database: ghost
|
||||
# SMTP для рассылки (2FA, сброс пароля, приглашения) — bait.su
|
||||
# from должен совпадать с auth user, иначе Timeweb отклоняет (Sender address rejected)
|
||||
mail__transport: SMTP
|
||||
mail__options__host: smtp.timeweb.ru
|
||||
mail__options__port: ${GHOST_MAIL_PORT:-465}
|
||||
mail__options__secure: "true"
|
||||
mail__options__auth__user: ${GHOST_MAIL_USER:-2factor@bait.su}
|
||||
mail__options__auth__pass: ${GHOST_MAIL_PASSWORD}
|
||||
mail__from: "${GHOST_MAIL_FROM:-bait.su <2factor@bait.su>}"
|
||||
# Временно отключить проверку устройства (2FA по почте), чтобы войти без кода; включите после настройки SMTP
|
||||
security__staffDeviceVerification: "false"
|
||||
volumes:
|
||||
- ghost-content:/var/lib/ghost/content
|
||||
depends_on:
|
||||
ghost-db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:2368/ghost/api/content/settings/?key=dummy 2>&1 | grep -q '401\\|200' || wget -q --spider http://127.0.0.1:2368/favicon.ico"]
|
||||
interval: 30s
|
||||
timeout: 15s
|
||||
retries: 5
|
||||
start_period: 90s
|
||||
|
||||
search-svc:
|
||||
build:
|
||||
context: ../../services/search-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/search-svc:latest
|
||||
container_name: gooseek-search-svc
|
||||
ports:
|
||||
@@ -204,11 +524,21 @@ services:
|
||||
- redis
|
||||
- searxng
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3001/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
master-agents-svc:
|
||||
build:
|
||||
context: ../../services/master-agents-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/master-agents-svc:latest
|
||||
container_name: gooseek-master-agents-svc
|
||||
ports:
|
||||
@@ -217,15 +547,28 @@ services:
|
||||
PORT: "3018"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
SEARCH_SVC_URL: "http://search-svc:3001"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
CRAWL4AI_URL: "http://crawl4ai:11235"
|
||||
depends_on:
|
||||
- llm-svc
|
||||
- search-svc
|
||||
- discover-svc
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3018/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
chat-svc:
|
||||
build:
|
||||
context: ../../services/chat-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/chat-svc:latest
|
||||
container_name: gooseek-chat-svc
|
||||
ports:
|
||||
@@ -234,18 +577,148 @@ services:
|
||||
PORT: "3005"
|
||||
MASTER_AGENTS_SVC_URL: "http://master-agents-svc:3018"
|
||||
LLM_SVC_URL: "http://llm-svc:3020"
|
||||
DISCOVER_SVC_URL: "http://discover-svc:3002"
|
||||
volumes:
|
||||
- chat-data:/app/data
|
||||
depends_on:
|
||||
- master-agents-svc
|
||||
- llm-svc
|
||||
- discover-svc
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3005/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
|
||||
projects-svc:
|
||||
build:
|
||||
context: ../../services/projects-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/projects-svc:latest
|
||||
container_name: gooseek-projects-svc
|
||||
ports:
|
||||
- "3006:3006"
|
||||
environment:
|
||||
PORT: "3006"
|
||||
AUTH_SERVICE_URL: "http://auth-svc:3014"
|
||||
depends_on:
|
||||
- auth-svc
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3006/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: gooseek-postgres
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_USER: gooseek
|
||||
POSTGRES_PASSWORD: gooseek
|
||||
POSTGRES_DB: gooseek
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U gooseek -d gooseek"]
|
||||
interval: 2s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
|
||||
library-svc:
|
||||
build:
|
||||
context: ../../services/library-svc
|
||||
dockerfile: Dockerfile
|
||||
additional_contexts:
|
||||
npm-cache: ../../vendor/npm-cache
|
||||
image: gooseek/library-svc:latest
|
||||
container_name: gooseek-library-svc
|
||||
ports:
|
||||
- "3009:3009"
|
||||
environment:
|
||||
PORT: "3009"
|
||||
POSTGRES_URL: "postgresql://gooseek:gooseek@postgres:5432/gooseek"
|
||||
AUTH_SERVICE_URL: "http://auth-svc:3014"
|
||||
command: sh -c "node dist/db/push.js 2>/dev/null || true && node dist/index.js"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3009/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 25s
|
||||
|
||||
# Перезапускает контейнеры с меткой autoheal=true при переходе в unhealthy (аналог K8s liveness)
|
||||
autoheal:
|
||||
image: willfarrell/autoheal:latest
|
||||
container_name: gooseek-autoheal
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
AUTOHEAL_CONTAINER_LABEL: "autoheal"
|
||||
AUTOHEAL_INTERVAL: "10"
|
||||
AUTOHEAL_START_PERIOD: "30"
|
||||
restart: always
|
||||
|
||||
# Tor proxy для обхода блокировок (бесплатный, опенсорс)
|
||||
# SOCKS5: tor-proxy:9050, Control: tor-proxy:9051
|
||||
# Множественные circuits для ротации IP
|
||||
tor-proxy:
|
||||
image: dperson/torproxy:latest
|
||||
container_name: gooseek-tor-proxy
|
||||
environment:
|
||||
- TOR_NewCircuitPeriod=30
|
||||
- TOR_MaxCircuitDirtiness=600
|
||||
- TOR_CircuitBuildTimeout=10
|
||||
- TOR_NumEntryGuards=8
|
||||
- PASSWORD=gooseek_tor_control
|
||||
ports:
|
||||
- "127.0.0.1:9050:9050"
|
||||
- "127.0.0.1:9051:9051"
|
||||
- "127.0.0.1:8118:8118"
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: "0.5"
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "autoheal=true"
|
||||
healthcheck:
|
||||
test: ["CMD", "nc", "-z", "127.0.0.1", "9050"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
volumes:
|
||||
auth-data:
|
||||
llm-data:
|
||||
redis-data:
|
||||
discover-db-data:
|
||||
chat-data:
|
||||
postgres-data:
|
||||
caddy-data:
|
||||
caddy-config:
|
||||
searxng-cache:
|
||||
ghost-db-data:
|
||||
ghost-content:
|
||||
|
||||
@@ -3,12 +3,17 @@
|
||||
# Сервисы из deploy/k3s/deploy.config.yaml (true)
|
||||
#
|
||||
# Использование:
|
||||
# ./deploy/docker/run.sh # полный build + up
|
||||
# ./deploy/docker/run.sh --web # только web-svc (кнопки, UI) — быстро
|
||||
# ./deploy/docker/run.sh --up # только up (без build)
|
||||
# ./deploy/docker/run.sh --down # остановить
|
||||
# ./deploy/docker/run.sh # build + up (vendor если есть)
|
||||
# ./deploy/docker/run.sh --no-cache # build без кэша + up
|
||||
# ./deploy/docker/run.sh --web # только web-svc — быстро
|
||||
# ./deploy/docker/run.sh --up # только up (без build)
|
||||
# ./deploy/docker/run.sh --down # остановить
|
||||
# ./deploy/docker/run.sh --vendor # скачать npm + docker images в vendor/
|
||||
# ./deploy/docker/run.sh --offline # строгий оффлайн-билд (vendor обязателен)
|
||||
# ./deploy/docker/run.sh --load-images # загрузить Docker images из vendor/
|
||||
#
|
||||
# BuildKit + --no-cache: при деплое старый кэш не используется, сборка всегда свежая
|
||||
# Оффлайн-билд: vendor/npm-cache/ монтируется в Dockerfile через additional_contexts.
|
||||
# Docker images: vendor/docker-images.tar загружается через docker load.
|
||||
|
||||
set -e
|
||||
export DOCKER_BUILDKIT=1
|
||||
@@ -16,46 +21,151 @@ export DOCKER_BUILDKIT=1
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
|
||||
ENV_FILE="$REPO_ROOT/.env"
|
||||
VENDOR_DIR="$REPO_ROOT/vendor"
|
||||
VENDOR_CACHE="$VENDOR_DIR/npm-cache"
|
||||
VENDOR_ARCHIVE="$VENDOR_DIR/npm-cache.tar.gz"
|
||||
VENDOR_IMAGES="$VENDOR_DIR/docker-images.tar"
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
COMPOSE_ENV="docker compose -f $COMPOSE_FILE --env-file $ENV_FILE"
|
||||
|
||||
BUILD_SERVICES=(
|
||||
reverse-proxy
|
||||
llm-svc
|
||||
auth-svc
|
||||
api-gateway
|
||||
geo-device-svc
|
||||
localization-svc
|
||||
discover-svc
|
||||
travel-svc
|
||||
cache-worker-tech
|
||||
search-svc
|
||||
master-agents-svc
|
||||
chat-svc
|
||||
projects-svc
|
||||
library-svc
|
||||
web-svc
|
||||
)
|
||||
|
||||
build_sequential() {
|
||||
local extra_flags="${1:-}"
|
||||
for svc in "${BUILD_SERVICES[@]}"; do
|
||||
echo "=== Build: $svc ==="
|
||||
$COMPOSE_ENV build $extra_flags "$svc"
|
||||
done
|
||||
}
|
||||
|
||||
# -------------------------------------------------------
|
||||
# ensure_vendor — распаковать npm-cache.tar.gz если нужно
|
||||
# -------------------------------------------------------
|
||||
ensure_vendor() {
|
||||
if [ -d "$VENDOR_CACHE" ] && [ "$(ls -A "$VENDOR_CACHE" 2>/dev/null)" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -f "$VENDOR_ARCHIVE" ]; then
|
||||
echo "Распаковка $VENDOR_ARCHIVE ..."
|
||||
mkdir -p "$VENDOR_DIR"
|
||||
tar -xzf "$VENDOR_ARCHIVE" -C "$VENDOR_DIR"
|
||||
echo "npm-cache распакован."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# additional_contexts в docker-compose.yml требует существующую директорию
|
||||
mkdir -p "$VENDOR_CACHE"
|
||||
return 1
|
||||
}
|
||||
|
||||
# -------------------------------------------------------
|
||||
# load_docker_images — загрузить base images из архива
|
||||
# -------------------------------------------------------
|
||||
load_docker_images() {
|
||||
if [ -f "$VENDOR_IMAGES" ]; then
|
||||
echo "Загрузка Docker images из $VENDOR_IMAGES ..."
|
||||
docker load -i "$VENDOR_IMAGES"
|
||||
echo "Docker images загружены."
|
||||
else
|
||||
echo "WARN: $VENDOR_IMAGES не найден, пропускаю загрузку images."
|
||||
fi
|
||||
}
|
||||
|
||||
# -------------------------------------------------------
|
||||
# print_status — вывод адресов сервисов
|
||||
# -------------------------------------------------------
|
||||
print_status() {
|
||||
echo ""
|
||||
echo "Сервисы запущены:"
|
||||
echo " web-svc: http://localhost:3000"
|
||||
echo " api-gateway: http://localhost:3015"
|
||||
echo " auth-svc: http://localhost:3014"
|
||||
echo " llm-svc: http://localhost:3020"
|
||||
echo " chat-svc: http://localhost:3005"
|
||||
echo " master-agents: http://localhost:3018"
|
||||
echo " search-svc: http://localhost:3001"
|
||||
echo " redis: localhost:6379"
|
||||
echo " ghost: http://localhost:2368 (Admin: /ghost)"
|
||||
echo ""
|
||||
echo "Самовосстановление: healthcheck + autoheal (перезапуск unhealthy контейнеров)."
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
--vendor)
|
||||
echo "=== Скачивание vendor (npm + Docker images) ==="
|
||||
bash "$SCRIPT_DIR/vendor.sh"
|
||||
;;
|
||||
|
||||
--load-images)
|
||||
load_docker_images
|
||||
;;
|
||||
|
||||
--offline)
|
||||
if ! ensure_vendor; then
|
||||
echo "ОШИБКА: vendor/npm-cache не найден и vendor/npm-cache.tar.gz отсутствует."
|
||||
echo "Сначала выполните: ./deploy/docker/run.sh --vendor"
|
||||
exit 1
|
||||
fi
|
||||
load_docker_images
|
||||
echo ""
|
||||
echo "=== Оффлайн-билд ==="
|
||||
build_sequential
|
||||
$COMPOSE_ENV up -d --force-recreate
|
||||
print_status
|
||||
;;
|
||||
|
||||
--no-cache)
|
||||
ensure_vendor || echo "WARN: vendor не найден, билд будет скачивать из интернета."
|
||||
build_sequential "--no-cache"
|
||||
$COMPOSE_ENV up -d --force-recreate
|
||||
echo ""
|
||||
echo "Сервисы пересобраны без кэша и запущены."
|
||||
print_status
|
||||
;;
|
||||
|
||||
--web)
|
||||
docker compose -f "$COMPOSE_FILE" build --no-cache web-svc
|
||||
docker compose -f "$COMPOSE_FILE" up -d --force-recreate web-svc reverse-proxy
|
||||
ensure_vendor || echo "WARN: vendor не найден, билд будет скачивать из интернета."
|
||||
$COMPOSE_ENV build --no-cache web-svc
|
||||
$COMPOSE_ENV up -d --force-recreate web-svc reverse-proxy
|
||||
echo ""
|
||||
echo "web-svc пересобран и перезапущен. Обнови страницу (Ctrl+Shift+R)."
|
||||
;;
|
||||
|
||||
--down)
|
||||
docker compose -f "$COMPOSE_FILE" down
|
||||
$COMPOSE_ENV down
|
||||
echo "Остановлено."
|
||||
;;
|
||||
|
||||
--up)
|
||||
docker compose -f "$COMPOSE_FILE" up -d
|
||||
echo ""
|
||||
echo "Сервисы запущены:"
|
||||
echo " web-svc: http://localhost:3000"
|
||||
echo " api-gateway: http://localhost:3015"
|
||||
echo " auth-svc: http://localhost:3014"
|
||||
echo " llm-svc: http://localhost:3020"
|
||||
echo " chat-svc: http://localhost:3005"
|
||||
echo " master-agents: http://localhost:3018"
|
||||
echo " search-svc: http://localhost:3001"
|
||||
$COMPOSE_ENV up -d
|
||||
print_status
|
||||
;;
|
||||
|
||||
*)
|
||||
docker compose -f "$COMPOSE_FILE" build --no-cache
|
||||
docker compose -f "$COMPOSE_FILE" up -d --force-recreate
|
||||
echo ""
|
||||
echo "Сервисы запущены:"
|
||||
echo " web-svc: http://localhost:3000"
|
||||
echo " api-gateway: http://localhost:3015"
|
||||
echo " auth-svc: http://localhost:3014"
|
||||
echo " llm-svc: http://localhost:3020"
|
||||
echo " chat-svc: http://localhost:3005"
|
||||
echo " master-agents: http://localhost:3018"
|
||||
echo " search-svc: http://localhost:3001"
|
||||
echo " redis: localhost:6379"
|
||||
echo ""
|
||||
ensure_vendor || echo "WARN: vendor не найден, билд будет скачивать из интернета."
|
||||
build_sequential
|
||||
$COMPOSE_ENV up -d --force-recreate
|
||||
print_status
|
||||
echo "LLM: настройте .env (LLM_PROVIDER=timeweb или ollama)."
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -1,9 +1,107 @@
|
||||
# GooSeek — SearXNG для внутреннего использования (search-svc)
|
||||
# GooSeek — SearXNG оптимизированный для скорости
|
||||
# https://docs.searxng.org/admin/settings/
|
||||
use_default_settings: true
|
||||
|
||||
search:
|
||||
formats: [html, json, csv, rss]
|
||||
safe_search: 0
|
||||
max_page: 2
|
||||
|
||||
server:
|
||||
secret_key: "gooseek-searxng-internal"
|
||||
limiter: false
|
||||
image_proxy: true
|
||||
image_proxy: false
|
||||
|
||||
outgoing:
|
||||
request_timeout: 3.0
|
||||
max_request_timeout: 8.0
|
||||
retries: 1
|
||||
pool_connections: 100
|
||||
pool_maxsize: 50
|
||||
|
||||
engines:
|
||||
# ОТКЛЮЧЕНЫ медленные/сломанные движки
|
||||
- name: qwant
|
||||
disabled: true
|
||||
- name: startpage
|
||||
disabled: true
|
||||
- name: mojeek
|
||||
disabled: true
|
||||
- name: wiby
|
||||
disabled: true
|
||||
- name: yacy
|
||||
disabled: true
|
||||
- name: ask
|
||||
disabled: true
|
||||
- name: crowdview
|
||||
disabled: true
|
||||
- name: encyclosearch
|
||||
disabled: true
|
||||
- name: stract
|
||||
disabled: true
|
||||
- name: mwmbl
|
||||
disabled: true
|
||||
|
||||
# ============================================
|
||||
# РОССИЙСКИЕ ДВИЖКИ (RU)
|
||||
# ============================================
|
||||
|
||||
# Яндекс - веб поиск (переопределяем дефолтный)
|
||||
- name: yandex
|
||||
disabled: false
|
||||
weight: 1.4
|
||||
|
||||
# Яндекс - изображения (переопределяем дефолтный)
|
||||
- name: yandex images
|
||||
disabled: false
|
||||
|
||||
# ============================================
|
||||
# МЕЖДУНАРОДНЫЕ ДВИЖКИ
|
||||
# ============================================
|
||||
|
||||
# Быстрые и надёжные движки
|
||||
- name: google
|
||||
disabled: false
|
||||
weight: 1.5
|
||||
- name: bing
|
||||
disabled: false
|
||||
weight: 1.3
|
||||
- name: duckduckgo
|
||||
disabled: false
|
||||
weight: 1.2
|
||||
- name: brave
|
||||
disabled: false
|
||||
weight: 1.2
|
||||
- name: yahoo
|
||||
disabled: false
|
||||
- name: wikipedia
|
||||
weight: 1.5
|
||||
- name: wikidata
|
||||
weight: 1.0
|
||||
|
||||
# YouTube
|
||||
- name: youtube
|
||||
disabled: false
|
||||
categories: [videos]
|
||||
weight: 1.3
|
||||
|
||||
# IT / Q&A
|
||||
- name: stackoverflow
|
||||
categories: [general, it]
|
||||
- name: github
|
||||
categories: [general, it]
|
||||
- name: mdn
|
||||
categories: [general, it]
|
||||
|
||||
# Научные
|
||||
- name: arxiv
|
||||
categories: [general, science]
|
||||
- name: semantic scholar
|
||||
disabled: false
|
||||
categories: [general, science]
|
||||
|
||||
# Social media
|
||||
- name: reddit
|
||||
disabled: false
|
||||
categories: [social_media]
|
||||
|
||||
|
||||
99
deploy/docker/vendor.sh
Executable file
99
deploy/docker/vendor.sh
Executable file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# vendor.sh — скачивает ВСЕ npm-зависимости + Docker-образы
|
||||
# в vendor/ для оффлайн-билда в изолированной среде.
|
||||
#
|
||||
# Запускать на машине С ИНТЕРНЕТОМ. Результат:
|
||||
# vendor/npm-cache/ — npm cache (все tarballs)
|
||||
# vendor/npm-cache.tar.gz — архив npm cache
|
||||
# vendor/docker-images.tar — base Docker images
|
||||
#
|
||||
# Перенести vendor/ на изолированную машину.
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
VENDOR_DIR="$REPO_ROOT/vendor"
|
||||
CACHE_DIR="$VENDOR_DIR/npm-cache"
|
||||
|
||||
echo "=== GooSeek vendor: скачивание зависимостей ==="
|
||||
echo "Репозиторий: $REPO_ROOT"
|
||||
echo "Vendor: $VENDOR_DIR"
|
||||
echo ""
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 1. npm cache — все сервисы
|
||||
# ----------------------------------------------------------
|
||||
rm -rf "$CACHE_DIR"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
|
||||
for pkg in "$REPO_ROOT"/services/*/package.json; do
|
||||
svc_dir="$(dirname "$pkg")"
|
||||
svc_name="$(basename "$svc_dir")"
|
||||
|
||||
if [ ! -f "$svc_dir/package-lock.json" ] && [ ! -f "$REPO_ROOT/package-lock.json" ]; then
|
||||
echo "--- Пропускаю $svc_name (нет package-lock.json) ---"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "=== npm cache: $svc_name ==="
|
||||
(cd "$svc_dir" && npm install --cache "$CACHE_DIR" --prefer-offline --ignore-scripts 2>&1) || {
|
||||
echo " WARN: npm install для $svc_name завершился с ошибкой, продолжаем..."
|
||||
}
|
||||
rm -rf "$svc_dir/node_modules"
|
||||
done
|
||||
|
||||
echo "=== npm cache: workspace root (web-svc, auth-svc) ==="
|
||||
(cd "$REPO_ROOT" && npm install --cache "$CACHE_DIR" --prefer-offline --ignore-scripts 2>&1) || {
|
||||
echo " WARN: npm install для workspace root завершился с ошибкой, продолжаем..."
|
||||
}
|
||||
rm -rf "$REPO_ROOT/node_modules"
|
||||
for svc_dir in "$REPO_ROOT"/services/*/; do
|
||||
rm -rf "$svc_dir/node_modules"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Упаковка npm cache ==="
|
||||
tar -czf "$VENDOR_DIR/npm-cache.tar.gz" -C "$VENDOR_DIR" npm-cache
|
||||
NPM_SIZE=$(du -sh "$VENDOR_DIR/npm-cache.tar.gz" | cut -f1)
|
||||
echo " npm-cache.tar.gz: $NPM_SIZE"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 2. Docker base images
|
||||
# ----------------------------------------------------------
|
||||
IMAGES=(
|
||||
"node:22-alpine"
|
||||
"node:20-alpine"
|
||||
"redis:7-alpine"
|
||||
"searxng/searxng:latest"
|
||||
"ghost:6-alpine"
|
||||
"mysql:8"
|
||||
"postgres:16-alpine"
|
||||
"willfarrell/autoheal:latest"
|
||||
"unclecode/crawl4ai:latest"
|
||||
)
|
||||
|
||||
echo ""
|
||||
echo "=== Docker images: pull ==="
|
||||
for img in "${IMAGES[@]}"; do
|
||||
echo " pull $img"
|
||||
docker pull "$img" 2>&1 | tail -1
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Docker images: save ==="
|
||||
docker save -o "$VENDOR_DIR/docker-images.tar" "${IMAGES[@]}"
|
||||
DOCKER_SIZE=$(du -sh "$VENDOR_DIR/docker-images.tar" | cut -f1)
|
||||
echo " docker-images.tar: $DOCKER_SIZE"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Итого
|
||||
# ----------------------------------------------------------
|
||||
echo ""
|
||||
echo "=== Готово ==="
|
||||
echo " $VENDOR_DIR/npm-cache.tar.gz ($NPM_SIZE)"
|
||||
echo " $VENDOR_DIR/docker-images.tar ($DOCKER_SIZE)"
|
||||
echo ""
|
||||
echo "Перенесите vendor/ на изолированную машину:"
|
||||
echo " scp -r vendor/ user@server:~/GooSeek/vendor/"
|
||||
Reference in New Issue
Block a user