feat(bundle): add agent image to build.sh bundle + enterprise-clean compose

- build.sh bundle_release() now builds ss-tools-agent:{tag} from
  docker/Dockerfile.agent alongside backend and frontend
- Generated docker-compose.enterprise-clean.yml includes agent service
  (image: + pull_policy: never, port 7860, depends_on: backend)
- Manifest .txt and .json include agent image fields
- sha256sums and load instructions updated for three images
- Static docker-compose.enterprise-clean.yml adds agent service (build
  from source) for local 'up enterprise-clean' profile
This commit is contained in:
2026-06-11 16:13:02 +03:00
parent ff9f8bb54f
commit b3bc9e53b9
2 changed files with 68 additions and 9 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# #region build [C:2] [TYPE Module]
# @PURPOSE: Unified build script — local docker compose + release bundles + lightweight bundle
# @PURPOSE: Unified build script — local docker compose + release bundles (backend + frontend + agent) + lightweight bundle
# @COMPLEXITY: 2
#
# Usage: ./build.sh <command> [options]
@@ -214,6 +214,7 @@ bundle_release() {
local tag="$1"
local backend_tag="ss-tools-backend:${tag}"
local frontend_tag="ss-tools-frontend:${tag}"
local agent_tag="ss-tools-agent:${tag}"
mkdir -p "$DIST_ROOT"
@@ -223,24 +224,31 @@ bundle_release() {
echo "[bundle] Building frontend image ${frontend_tag}..."
docker build -f docker/frontend.Dockerfile -t "${frontend_tag}" .
echo "[bundle] Building agent image ${agent_tag}..."
docker build -f docker/Dockerfile.agent -t "${agent_tag}" .
echo "[bundle] Exporting .tar.xz archives..."
echo "[bundle] Compressing backend image..."
docker save "${backend_tag}" | xz -T0 -6 > "${DIST_ROOT}/ss-tools-backend.${tag}.tar.xz"
echo "[bundle] Compressing frontend image..."
docker save "${frontend_tag}" | xz -T0 -6 > "${DIST_ROOT}/ss-tools-frontend.${tag}.tar.xz"
echo "[bundle] Compressing agent image..."
docker save "${agent_tag}" | xz -T0 -6 > "${DIST_ROOT}/ss-tools-agent.${tag}.tar.xz"
echo "[bundle] Calculating checksums..."
(
cd "${DIST_ROOT}"
sha256sum "ss-tools-backend.${tag}.tar.xz" "ss-tools-frontend.${tag}.tar.xz" > "sha256sums.${tag}.txt"
sha256sum "ss-tools-backend.${tag}.tar.xz" "ss-tools-frontend.${tag}.tar.xz" "ss-tools-agent.${tag}.tar.xz" > "sha256sums.${tag}.txt"
)
local backend_id frontend_id
local backend_digest frontend_digest
local backend_id frontend_id agent_id
local backend_digest frontend_digest agent_digest
backend_id="$(get_image_id "${backend_tag}")"
frontend_id="$(get_image_id "${frontend_tag}")"
agent_id="$(get_image_id "${agent_tag}")"
backend_digest="$(get_repo_digest "${backend_tag}")"
frontend_digest="$(get_repo_digest "${frontend_tag}")"
agent_digest="$(get_repo_digest "${agent_tag}")"
# Генерируем deploy-compose для загрузки pre-built образов (image: + pull_policy: never)
# Без postgres — используется внешний корпоративный PostgreSQL.
@@ -283,6 +291,24 @@ services:
- "\${FRONTEND_SSL_PORT:-443}:443"
volumes:
- \${CERTS_PATH:-./certs}:/opt/certs:ro
agent:
image: ${agent_tag}
pull_policy: never
restart: unless-stopped
depends_on:
- backend
environment:
LLM_API_KEY: \${LLM_API_KEY:-}
LLM_BASE_URL: \${LLM_BASE_URL:-https://api.openai.com/v1}
LLM_MODEL: \${LLM_MODEL:-gpt-4o}
FASTAPI_URL: http://backend:8000
JWT_SECRET: \${JWT_SECRET:-super-secret-key}
SERVICE_TOKEN_SECRET: \${SERVICE_TOKEN_SECRET:-agent-service-secret}
DATABASE_URL: postgresql+psycopg2://\${POSTGRES_USER:-postgres}:\${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}@\${POSTGRES_HOST:?Set POSTGRES_HOST}:\${POSTGRES_PORT:-5432}/\${POSTGRES_DB:-ss_tools}
GRADIO_SERVER_PORT: 7860
ports:
- "\${AGENT_HOST_PORT:-7860}:7860"
DEPLOY
cat > "${DIST_ROOT}/manifest.${tag}.txt" <<EOF
@@ -295,6 +321,10 @@ frontend_image=${frontend_tag}
frontend_image_id=${frontend_id}
frontend_repo_digest=${frontend_digest}
frontend_archive=ss-tools-frontend.${tag}.tar.xz
agent_image=${agent_tag}
agent_image_id=${agent_id}
agent_repo_digest=${agent_digest}
agent_archive=ss-tools-agent.${tag}.tar.xz
compose_file=docker-compose.enterprise-clean.yml
env_template=.env.enterprise-clean.example
env_bootstrap_fields=INITIAL_ADMIN_CREATE,INITIAL_ADMIN_USERNAME,INITIAL_ADMIN_PASSWORD,INITIAL_ADMIN_EMAIL
@@ -320,6 +350,13 @@ EOF
"image_id": "${frontend_id}",
"repo_digest": "${frontend_digest}",
"archive": "ss-tools-frontend.${tag}.tar.xz"
},
{
"role": "agent",
"image": "${agent_tag}",
"image_id": "${agent_id}",
"repo_digest": "${agent_digest}",
"archive": "ss-tools-agent.${tag}.tar.xz"
}
],
"compose_file": "docker-compose.enterprise-clean.yml",
@@ -340,6 +377,7 @@ EOF
echo " # Load images (decompress stream):"
echo " xz -dc ${DIST_ROOT}/ss-tools-backend.${tag}.tar.xz | docker load"
echo " xz -dc ${DIST_ROOT}/ss-tools-frontend.${tag}.tar.xz | docker load"
echo " xz -dc ${DIST_ROOT}/ss-tools-agent.${tag}.tar.xz | docker load"
echo " # Edit .env.enterprise-clean.example -> .env.enterprise-clean, then:"
echo " docker compose -f ${DIST_ROOT}/docker-compose.enterprise-clean.yml up"
echo ""
@@ -476,9 +514,9 @@ Commands for local docker:
status Show running containers for all profiles
Commands for release bundles:
bundle <tag> Build release images (backend + frontend .tar.xz's).
NOTE: external PostgreSQL only — no bundled postgres image.
Example: ./build.sh bundle v1.0.0
bundle <tag> Build release images (backend + frontend + agent .tar.xz's).
NOTE: external PostgreSQL only — no bundled postgres image.
Example: ./build.sh bundle v1.0.0
bundle:light <tag> Lightweight all-in-one image (.tar.xz, <200 MB, no Playwright)
Example: ./build.sh bundle:light v1.0.0

View File

@@ -1,14 +1,16 @@
# #region docker.compose.enterprise-clean [C:4] [TYPE Module] [SEMANTICS docker,compose,enterprise]
# @BRIEF Enterprise docker compose — сборка backend + frontend из исходников, внешний Postgres, корп. сертификаты.
# @BRIEF Enterprise docker compose — сборка backend + frontend + agent из исходников, внешний Postgres, корп. сертификаты.
# @PRE Docker и docker compose установлены. Файлы .env.enterprise-clean настроены.
# Postgres: внешний, доступный по POSTGRES_HOST:POSTGRES_PORT.
# Сертификаты: опциональные .crt файлы в CERTS_PATH монтируются в /opt/certs.
# @POST Сервисы backend и frontend запущены. SSL терминация в nginx опциональна.
# @POST Сервисы backend, frontend и agent запущены. SSL терминация в nginx опциональна.
# @SIDE_EFFECT backend использует ENTRYPOINT для установки сертификатов и bootstrap admin.
# frontend автоопределяет наличие SSL сертификатов и переключает nginx конфиг.
# agent запускает Gradio-сервер с LangGraph на порту 7860.
# @LAYER Infrastructure
# @RELATION DEPENDS_ON -> [docker/backend.Dockerfile]
# @RELATION DEPENDS_ON -> [docker/frontend.Dockerfile]
# @RELATION DEPENDS_ON -> [docker/Dockerfile.agent]
# @RELATION DEPENDS_ON -> [docker/nginx.conf]
# @RELATION DEPENDS_ON -> [docker/nginx.ssl.conf]
# @RELATION DEPENDS_ON -> [docker/frontend.entrypoint.sh]
@@ -82,4 +84,23 @@ services:
# автоматически установит CA-сертификаты в Alpine и переключит SSL конфиг.
- ${CERTS_PATH:-./certs}:/opt/certs:ro
agent:
build:
context: .
dockerfile: docker/Dockerfile.agent
restart: unless-stopped
depends_on:
- backend
environment:
LLM_API_KEY: ${LLM_API_KEY:-}
LLM_BASE_URL: ${LLM_BASE_URL:-https://api.openai.com/v1}
LLM_MODEL: ${LLM_MODEL:-gpt-4o}
FASTAPI_URL: http://backend:8000
JWT_SECRET: ${JWT_SECRET:-super-secret-key}
SERVICE_TOKEN_SECRET: ${SERVICE_TOKEN_SECRET:-agent-service-secret}
DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env.enterprise-clean}@${POSTGRES_HOST:?Set POSTGRES_HOST in .env.enterprise-clean}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-ss_tools}
GRADIO_SERVER_PORT: 7860
ports:
- "${AGENT_HOST_PORT:-7860}:7860"
# #endregion docker.compose.enterprise-clean