feat(boot): параметризация инстанса через .env для параллельного запуска

Все mono-ai-N теперь могут работать одновременно на изолированной
инфраструктуре. Имена контейнеров автогенерируются compose-проектом
(префикс из .env), хост-порты и URL берутся из .env.

- docker-compose.yaml: убраны статические container_name, host-порты
  через ${VAR:-default} для обратной совместимости
- boot scripts (reboot/clean_reboot/extra_reboot/clear): source корневого
  .env и docker exec → docker compose exec -T (через service name)
- networks.sh, preactivate.sh: cleos/curl используют ${CHAIN_URL:-...}
- boot health.ts, configs/index.ts, configs/networks.ts: читают
  process.env.CHAIN_URL вместо hardcoded localhost:8888
- configs/contracts.ts: добавлен ledger2
- init/infra.ts: addUser получил недостающий registration_hash

В каждой папке mono-ai-N нужен локальный .env (в .gitignore) с
INSTANCE_INDEX, COMPOSE_PROJECT_NAME, host-портами и
CHAIN_URL/API_URL/MONGODB_URL. Без .env compose поднимется на дефолтных
портах (как у mono-ai-1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
coopops
2026-04-22 08:24:30 +00:00
parent ff44889c10
commit 8d037a9dbb
12 changed files with 104 additions and 39 deletions
+11 -2
View File
@@ -1,5 +1,14 @@
#!/bin/bash
# Загружаем per-instance конфиг из корня репо.
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
if [ -f "$ROOT_DIR/.env" ]; then
set -a
# shellcheck disable=SC1091
source "$ROOT_DIR/.env"
set +a
fi
# Останавливаем и удаляем контейнеры вместе с volumes
echo "Останавливаем и удаляем контейнеры с volumes..."
docker compose down -v mongo postgres cooparser || true
@@ -19,7 +28,7 @@ docker compose up -d mongo postgres
# Ждем готовности MongoDB
echo "Ждем готовности MongoDB..."
until docker exec mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
until docker compose exec -T mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
echo "MongoDB еще не готов, ждем..."
sleep 2
done
@@ -27,7 +36,7 @@ echo "MongoDB готов!"
# Ждем готовности PostgreSQL
echo "Ждем готовности PostgreSQL..."
until docker exec postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
until docker compose exec -T postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
echo "PostgreSQL еще не готов, ждем..."
sleep 2
done
+11 -2
View File
@@ -1,5 +1,14 @@
#!/bin/bash
# Загружаем per-instance конфиг из корня репо.
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
if [ -f "$ROOT_DIR/.env" ]; then
set -a
# shellcheck disable=SC1091
source "$ROOT_DIR/.env"
set +a
fi
# Останавливаем и удаляем контейнеры вместе с volumes
echo "Останавливаем и удаляем контейнеры с volumes..."
docker compose down -v mongo postgres cooparser || true
@@ -19,7 +28,7 @@ docker compose up -d mongo postgres
# Ждем готовности MongoDB
echo "Ждем готовности MongoDB..."
until docker exec mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
until docker compose exec -T mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
echo "MongoDB еще не готов, ждем..."
sleep 2
done
@@ -27,7 +36,7 @@ echo "MongoDB готов!"
# Ждем готовности PostgreSQL
echo "Ждем готовности PostgreSQL..."
until docker exec postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
until docker compose exec -T postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
echo "PostgreSQL еще не готов, ждем..."
sleep 2
done
+11 -2
View File
@@ -1,5 +1,14 @@
#!/bin/bash
# Загружаем per-instance конфиг из корня репо.
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
if [ -f "$ROOT_DIR/.env" ]; then
set -a
# shellcheck disable=SC1091
source "$ROOT_DIR/.env"
set +a
fi
# Останавливаем контроллер перед очисткой данных
echo "Останавливаем контроллер..."
docker compose down coopback || true
@@ -23,7 +32,7 @@ docker compose up -d mongo postgres
# Ждем готовности MongoDB
echo "Ждем готовности MongoDB..."
until docker exec mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
until docker compose exec -T mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
echo "MongoDB еще не готов, ждем..."
sleep 2
done
@@ -31,7 +40,7 @@ echo "MongoDB готов!"
# Ждем готовности PostgreSQL
echo "Ждем готовности PostgreSQL..."
until docker exec postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
until docker compose exec -T postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
echo "PostgreSQL еще не готов, ждем..."
sleep 2
done
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash
local="-u http://localhost:8888"
local="-u ${CHAIN_URL:-http://localhost:8888}"
test="-u https://testnet.coopenomics.world/api"
prod="-u https://voskhod.coopenomics.world/api"
+1 -1
View File
@@ -6,7 +6,7 @@
# Activate PREACTIVATE_FEATURE before installing eosio.boot
#./cleos.sh push action eosio activate '["0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"]' -p eosio@active
curl --noproxy -X POST "http://localhost:8888/v1/producer/schedule_protocol_feature_activations" -d '{"protocol_features_to_activate": ["0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"]}'
curl --noproxy -X POST "${CHAIN_URL:-http://localhost:8888}/v1/producer/schedule_protocol_feature_activations" -d '{"protocol_features_to_activate": ["0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"]}'
# Install eosio.boot which supports the native actions and activate
# action that allows activating desired protocol features prior to
+12 -2
View File
@@ -1,5 +1,15 @@
#!/bin/bash
# Загружаем per-instance конфиг из корня репо (для CHAIN_URL/MONGODB_URL/API_URL,
# которые читают TS-код boot и шелл-скрипты networks.sh/preactivate.sh).
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
if [ -f "$ROOT_DIR/.env" ]; then
set -a
# shellcheck disable=SC1091
source "$ROOT_DIR/.env"
set +a
fi
# Останавливаем и удаляем контейнеры вместе с volumes
echo "Останавливаем и удаляем контейнеры с volumes..."
docker compose down -v mongo postgres opensearch cooparser || true
@@ -19,7 +29,7 @@ docker compose up -d mongo postgres opensearch
# Ждем готовности MongoDB
echo "Ждем готовности MongoDB..."
until docker exec mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
until docker compose exec -T mongo mongosh --eval "db.adminCommand('ping')" --quiet > /dev/null 2>&1; do
echo "MongoDB еще не готов, ждем..."
sleep 2
done
@@ -27,7 +37,7 @@ echo "MongoDB готов!"
# Ждем готовности PostgreSQL
echo "Ждем готовности PostgreSQL..."
until docker exec postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
until docker compose exec -T postgres pg_isready -U postgres -d voskhod > /dev/null 2>&1; do
echo "PostgreSQL еще не готов, ждем..."
sleep 2
done
+5
View File
@@ -70,6 +70,11 @@ export default [
path: path.resolve(process.cwd(), '../contracts/build/contracts/ledger'),
target: 'ledger',
},
{
name: 'ledger2',
path: path.resolve(process.cwd(), '../contracts/build/contracts/ledger2'),
target: 'ledger2',
},
{
name: 'test',
path: path.resolve(process.cwd(), '../contracts/build/contracts/test'),
+18 -3
View File
@@ -5,11 +5,22 @@ import contracts from './contracts'
config()
function parseChainUrl(url: string) {
const m = url.match(/^(https?):\/\/([^:/]+)(?::(\d+))?(?:\/.*)?$/)
if (!m) {
return { protocol: 'http', host: 'localhost', port: ':8888' }
}
const [, protocol, host, port] = m
return { protocol, host, port: port ? `:${port}` : '' }
}
const { protocol, host, port } = parseChainUrl(process.env.CHAIN_URL || 'http://localhost:8888')
const network = {
name: 'local',
protocol: 'http',
host: 'localhost',
port: ':8888',
protocol,
host,
port,
}
// const network = {
@@ -95,6 +106,10 @@ export default {
name: 'ledger',
code_permissions_to: ['ledger'],
},
{
name: 'ledger2',
code_permissions_to: ['ledger2'],
},
{
name: 'test',
code_permissions_to: ['test'],
+15 -3
View File
@@ -1,10 +1,22 @@
/* eslint-disable node/prefer-global/process */
import type { Network } from '../types'
function parseChainUrl(url: string) {
const m = url.match(/^(https?):\/\/([^:/]+)(?::(\d+))?(?:\/.*)?$/)
if (!m) {
return { protocol: 'http' as const, host: '127.0.0.1', port: ':8888' }
}
const [, protocol, host, port] = m
return { protocol, host, port: port ? `:${port}` : '' }
}
const { protocol, host, port } = parseChainUrl(process.env.CHAIN_URL || 'http://127.0.0.1:8888')
export const networks: Network[] = [
{
name: 'local',
protocol: 'http',
host: '127.0.0.1',
port: ':8888',
protocol,
host,
port,
},
]
+2 -1
View File
@@ -7,7 +7,8 @@ async function sleep(ms: number): Promise<void> {
export async function checkHealth() {
const check = async (): Promise<void> => {
try {
const response = await axios.post('http://127.0.0.1:8888/v1/chain/get_info')
const chainUrl = process.env.CHAIN_URL || 'http://127.0.0.1:8888'
const response = await axios.post(`${chainUrl}/v1/chain/get_info`)
const result = response.data
await sleep(1000)
+3
View File
@@ -10,6 +10,7 @@ import Blockchain from '../blockchain'
import { sleep } from '../utils'
import { initUsersInPostgres, initVaultInPostgres } from '../postgres-init'
import { CooperativeClass } from './cooperative'
import { generateRandomSHA256 } from '../utils/randomHash'
export async function startInfra() {
// инициализируем инстанс с ключами
@@ -390,6 +391,7 @@ export async function installInitialData(blockchain: Blockchain, isExtended = fa
minimum: '200.0000 RUB',
spread_initial: true,
meta: 'Основатель кооператива ВОСХОД',
registration_hash: generateRandomSHA256(),
})
console.log('Устанавливаем дефолтный публичный ключ для ant')
@@ -481,6 +483,7 @@ export async function installInitialData(blockchain: Blockchain, isExtended = fa
minimum: '300.0000 RUB',
spread_initial: true,
meta: `Член совета кооператива ВОСХОД - ${user.first_name} ${user.middle_name} ${user.last_name}`,
registration_hash: generateRandomSHA256(),
})
console.log(`Устанавливаем дефолтный публичный ключ для ${user.username}`)
+14 -22
View File
@@ -1,14 +1,14 @@
version: '3'
# Имена контейнеров не задаём явно — docker генерит их с префиксом
# COMPOSE_PROJECT_NAME (см. .env). Это позволяет параллельный запуск нескольких
# инстансов mono-ai-N. Внутри сети контейнеры стучатся друг к другу по service name.
services:
node:
image: dicoop/blockchain_v5.1.1:dev
container_name: node
ports:
- "8888:8888"
- "9876:9876"
- "8070:8070"
- "${NODE_HTTP_PORT:-8888}:8888"
- "${NODE_P2P_PORT:-9876}:9876"
- "${NODE_HISTORY_PORT:-8070}:8070"
volumes:
- ./components/boot/blockchain-data:/mnt/dev/data
- ./components/boot/wallet-data:/root/eosio-wallet
@@ -17,18 +17,17 @@ services:
command: >
/bin/bash -c "/usr/local/bin/nodeos -d /mnt/dev/data --config-dir /mnt/dev/config --genesis-json /mnt/dev/config/genesis.json"
restart: unless-stopped
mongo:
image: mongo:latest
container_name: mongo
restart: always
volumes:
- mongo_data:/data/db
ports:
- 127.0.0.1:27017:27017
- "127.0.0.1:${MONGO_HOST_PORT:-27017}:27017"
entrypoint: >
/bin/bash -c "
mongod --replSet rs0 --bind_ip_all &
mongod --replSet rs0 --bind_ip_all &
sleep 5;
mongosh --eval '
try {
@@ -44,14 +43,12 @@ services:
monoredis:
image: redis:latest
container_name: monoredis
restart: always
ports:
- 127.0.0.1:6379:6379
- "127.0.0.1:${REDIS_HOST_PORT:-6379}:6379"
postgres:
image: postgres:18
container_name: postgres
restart: always
environment:
POSTGRES_USER: postgres
@@ -60,10 +57,9 @@ services:
volumes:
- postgres_data:/var/lib/postgresql
ports:
- 127.0.0.1:5532:5432
- "127.0.0.1:${PG_HOST_PORT:-5532}:5432"
coopback:
container_name: coopback
build:
context: ./
dockerfile: components/controller/Dockerfile
@@ -74,13 +70,11 @@ services:
volumes:
- ./:/app
ports:
- 0.0.0.0:2998:2998
- "0.0.0.0:${COOPBACK_HOST_PORT:-2998}:2998"
working_dir: /app
command: pnpm --filter @coopenomics/controller run dev
cooparser:
container_name: cooparser
build:
context: ./
dockerfile: components/parser/Dockerfile
@@ -94,7 +88,6 @@ services:
command: pnpm --filter @coopenomics/parser run dev
desktop:
container_name: desktop
build:
context: ./
dockerfile: components/desktop/Dockerfile
@@ -103,7 +96,7 @@ services:
- ./components/desktop/.env
restart: unless-stopped
ports:
- 127.0.0.1:2999:2999
- "127.0.0.1:${DESKTOP_HOST_PORT:-2999}:2999"
volumes:
- ./:/app
working_dir: /app
@@ -111,7 +104,6 @@ services:
opensearch:
image: opensearchproject/opensearch:2.18.0
container_name: opensearch
environment:
- discovery.type=single-node
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=CoopSearch_2024!Secure
@@ -119,7 +111,7 @@ services:
volumes:
- opensearch_data:/usr/share/opensearch/data
ports:
- 127.0.0.1:9200:9200
- "127.0.0.1:${OPENSEARCH_HOST_PORT:-9200}:9200"
restart: unless-stopped
volumes: