From 1cb2b5355eae3e49b671f4659820cff0c6f2a0c4 Mon Sep 17 00:00:00 2001 From: busya Date: Wed, 11 Mar 2026 12:35:01 +0300 Subject: [PATCH] feat: add offline docker bundle for enterprise clean releases --- .env.enterprise-clean.example | 21 ++++++++++ README.md | 27 ++++++------ docker-compose.enterprise-clean.yml | 57 +++++++++++++++++++++++++ docs/installation.md | 54 ++++++++++++++++++++++++ scripts/build_offline_docker_bundle.sh | 58 ++++++++++++++++++++++++++ 5 files changed, 203 insertions(+), 14 deletions(-) create mode 100644 .env.enterprise-clean.example create mode 100644 docker-compose.enterprise-clean.yml create mode 100755 scripts/build_offline_docker_bundle.sh diff --git a/.env.enterprise-clean.example b/.env.enterprise-clean.example new file mode 100644 index 00000000..706f21de --- /dev/null +++ b/.env.enterprise-clean.example @@ -0,0 +1,21 @@ +# Offline / air-gapped compose profile for enterprise clean release. + +BACKEND_IMAGE=ss-tools-backend:v1.0.0-rc2 +FRONTEND_IMAGE=ss-tools-frontend:v1.0.0-rc2 +POSTGRES_IMAGE=postgres:16-alpine + +POSTGRES_DB=ss_tools +POSTGRES_USER=postgres +POSTGRES_PASSWORD=change-me + +BACKEND_HOST_PORT=8001 +FRONTEND_HOST_PORT=8000 +POSTGRES_HOST_PORT=5432 + +ENABLE_BELIEF_STATE_LOGGING=true +TASK_LOG_LEVEL=INFO + +STORAGE_ROOT=./storage + +OPENAI_API_KEY= +ANTHROPIC_API_KEY= diff --git a/README.md b/README.md index 7f9e4d62..356c25da 100755 --- a/README.md +++ b/README.md @@ -250,19 +250,19 @@ cd /home/busya/dev/ss-tools ```bash # 1. Собрать образы в подключённом контуре -docker compose -f docker-compose.yml build +./scripts/build_offline_docker_bundle.sh v1.0.0-rc2 -# 2. Экспортировать их в tar-архивы -docker save ss-tools-backend:TAG -o dist/docker/backend.TAG.tar -docker save ss-tools-frontend:TAG -o dist/docker/frontend.TAG.tar +# 2. Передать dist/docker/* в изолированный контур +# 3. Импортировать образы локально +docker load -i dist/docker/backend.v1.0.0-rc2.tar +docker load -i dist/docker/frontend.v1.0.0-rc2.tar +docker load -i dist/docker/postgres.v1.0.0-rc2.tar -# 3. Передать bundle в изолированный контур -# 4. Импортировать образы локально -docker load -i dist/docker/backend.TAG.tar -docker load -i dist/docker/frontend.TAG.tar +# 4. Подготовить env из шаблона +cp dist/docker/.env.enterprise-clean.example .env.enterprise-clean # 5. Запустить только локальные образы -docker compose -f docker-compose.enterprise-clean.yml up -d +docker compose --env-file .env.enterprise-clean -f dist/docker/docker-compose.enterprise-clean.yml up -d ``` Ограничения для production-grade offline release: @@ -272,10 +272,10 @@ docker compose -f docker-compose.enterprise-clean.yml up -d - clean/compliance manifest должен включать docker image digests как часть evidence package. Практический план внедрения: -- добавить pinned Docker image tags и отдельный `enterprise-clean` compose profile; -- подготовить `make release-docker-bundle` или shell script для `build -> save -> checksum`; -- включить docker image digests в clean-release manifest; -- добавить smoke-check, что compose-файлы не содержат внешних registry references вне allowlist. +- pinned Docker image tags и отдельный `enterprise-clean` compose profile добавлены; +- shell script `scripts/build_offline_docker_bundle.sh` добавлен для `build -> save -> checksum`; +- следующим шагом стоит включить docker image digests в clean-release manifest; +- следующим шагом стоит добавить smoke-check, что compose-файлы не содержат внешних registry references вне allowlist. ## 📖 Документация @@ -371,4 +371,3 @@ pip install -r requirements.txt --upgrade cd frontend npm install ``` - diff --git a/docker-compose.enterprise-clean.yml b/docker-compose.enterprise-clean.yml new file mode 100644 index 00000000..343fda7a --- /dev/null +++ b/docker-compose.enterprise-clean.yml @@ -0,0 +1,57 @@ +services: + db: + image: ${POSTGRES_IMAGE:?Set POSTGRES_IMAGE in .env.enterprise-clean} + pull_policy: never + container_name: ss_tools_db + restart: unless-stopped + environment: + POSTGRES_DB: ${POSTGRES_DB:-ss_tools} + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env.enterprise-clean} + ports: + - "${POSTGRES_HOST_PORT:-5432}:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-ss_tools}"] + interval: 10s + timeout: 5s + retries: 10 + + backend: + image: ${BACKEND_IMAGE:?Set BACKEND_IMAGE in .env.enterprise-clean} + pull_policy: never + container_name: ss_tools_backend + restart: unless-stopped + depends_on: + db: + condition: service_healthy + environment: + DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-ss_tools} + TASKS_DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-ss_tools} + AUTH_DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-ss_tools} + BACKEND_PORT: 8000 + ENABLE_BELIEF_STATE_LOGGING: ${ENABLE_BELIEF_STATE_LOGGING:-true} + TASK_LOG_LEVEL: ${TASK_LOG_LEVEL:-INFO} + OPENAI_API_KEY: ${OPENAI_API_KEY:-} + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} + ports: + - "${BACKEND_HOST_PORT:-8001}:8000" + volumes: + - ./config.json:/app/config.json:ro + - ./backups:/app/backups + - ./backend/git_repos:/app/backend/git_repos + - ${STORAGE_ROOT:-./storage}:/app/storage + + frontend: + image: ${FRONTEND_IMAGE:?Set FRONTEND_IMAGE in .env.enterprise-clean} + pull_policy: never + container_name: ss_tools_frontend + restart: unless-stopped + depends_on: + - backend + ports: + - "${FRONTEND_HOST_PORT:-8000}:80" + +volumes: + postgres_data: diff --git a/docs/installation.md b/docs/installation.md index 7b7e87b3..69609c00 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -6,6 +6,7 @@ - [Требования](#требования) - [Установка через Docker](#установка-через-docker) +- [Offline Docker Bundle](#offline-docker-bundle) - [Локальная установка](#локальная-установка) - [Первая настройка](#первая-настройка) - [Конфигурация окружений](#конфигурация-окружений) @@ -143,6 +144,59 @@ createdb ss_tools psql -U postgres -d ss_tools ``` +## Offline Docker Bundle + +Этот режим предназначен для enterprise clean-развёртывания в контуре без доступа к внешнему интернету. + +### 1. Сборка bundle в подключённом контуре + +```bash +cd /home/busya/dev/ss-tools +./scripts/build_offline_docker_bundle.sh v1.0.0-rc2 +``` + +Результат появится в `dist/docker/`: +- `backend.v1.0.0-rc2.tar` +- `frontend.v1.0.0-rc2.tar` +- `postgres.v1.0.0-rc2.tar` +- `sha256sums.v1.0.0-rc2.txt` +- `manifest.v1.0.0-rc2.txt` +- `docker-compose.enterprise-clean.yml` +- `.env.enterprise-clean.example` + +### 2. Перенос bundle в изолированный контур + +Передайте каталог `dist/docker/` во внутреннюю сеть любым утверждённым способом. + +### 3. Импорт образов + +```bash +docker load -i backend.v1.0.0-rc2.tar +docker load -i frontend.v1.0.0-rc2.tar +docker load -i postgres.v1.0.0-rc2.tar +``` + +### 4. Подготовка конфигурации + +```bash +cp .env.enterprise-clean.example .env.enterprise-clean +``` + +Минимально проверьте: +- `BACKEND_IMAGE` +- `FRONTEND_IMAGE` +- `POSTGRES_IMAGE` +- `POSTGRES_PASSWORD` +- `STORAGE_ROOT` + +### 5. Запуск в offline-контуре + +```bash +docker compose --env-file .env.enterprise-clean -f docker-compose.enterprise-clean.yml up -d +``` + +Compose-файл использует `pull_policy: never`, поэтому runtime не должен обращаться к внешним registry. + ## Первая настройка ### 1. Инициализация базы данных diff --git a/scripts/build_offline_docker_bundle.sh b/scripts/build_offline_docker_bundle.sh new file mode 100755 index 00000000..8187df95 --- /dev/null +++ b/scripts/build_offline_docker_bundle.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +# [DEF:scripts.build_offline_docker_bundle:Module] +# @PURPOSE: Build and export an offline Docker bundle for enterprise-clean releases. +# [/DEF:scripts.build_offline_docker_bundle:Module] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +DIST_ROOT="${PROJECT_ROOT}/dist/docker" + +TAG="${1:-v1.0.0-rc2}" +POSTGRES_IMAGE="${POSTGRES_IMAGE:-postgres:16-alpine}" +BACKEND_IMAGE="ss-tools-backend:${TAG}" +FRONTEND_IMAGE="ss-tools-frontend:${TAG}" + +mkdir -p "${DIST_ROOT}" + +cd "${PROJECT_ROOT}" + +echo "[offline-bundle] building backend image ${BACKEND_IMAGE}" +docker build -f docker/backend.Dockerfile -t "${BACKEND_IMAGE}" . + +echo "[offline-bundle] building frontend image ${FRONTEND_IMAGE}" +docker build -f docker/frontend.Dockerfile -t "${FRONTEND_IMAGE}" . + +echo "[offline-bundle] pulling postgres image ${POSTGRES_IMAGE}" +docker pull "${POSTGRES_IMAGE}" + +echo "[offline-bundle] exporting tar archives" +docker save -o "${DIST_ROOT}/backend.${TAG}.tar" "${BACKEND_IMAGE}" +docker save -o "${DIST_ROOT}/frontend.${TAG}.tar" "${FRONTEND_IMAGE}" +docker save -o "${DIST_ROOT}/postgres.${TAG}.tar" "${POSTGRES_IMAGE}" + +echo "[offline-bundle] calculating checksums" +( + cd "${DIST_ROOT}" + sha256sum "backend.${TAG}.tar" "frontend.${TAG}.tar" "postgres.${TAG}.tar" > "sha256sums.${TAG}.txt" +) + +cat > "${DIST_ROOT}/manifest.${TAG}.txt" <