From b0bbe05c5613a558b0d07519efbf1e5232af7769 Mon Sep 17 00:00:00 2001 From: coopops Date: Fri, 1 May 2026 09:02:21 +0000 Subject: [PATCH] =?UTF-8?q?[@ant]=20feat(boot):=20dicoop/bootcoop=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B7=20=D0=B4=D0=BB=D1=8F=20sideboot=20?= =?UTF-8?q?=D0=B2=20=D1=81=D0=BE=D1=81=D0=B5=D0=B4=D0=BD=D0=B8=D1=85=20?= =?UTF-8?q?=D1=80=D0=B5=D0=BF=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Цель: в соседних репозиториях (parser2, blockchain-protocol и т.д.) для тестов и отладки нужно поднимать только цепь + контракты, без mono-инфры (mongo/postgres/desktop). Решение — два контейнера в их compose: dicoop/blockchain (нода) + dicoop/bootcoop (one-shot bootstrap). Что добавлено: - components/boot/Dockerfile — multi-stage от dicoop/contracts: (контракты flat-layout в /contracts) + dicoop/mono-base: (runtime с pnpm/node + workspace). ENTRYPOINT = pnpm run boot:remote. CONTRACTS_DIR=/contracts выставлен по умолчанию. - .github/workflows/build-bootstrap.yaml — push в dev/testnet/main билдит и пушит dicoop/bootcoop: + :latest для main + :- для пинов. Telegram нотификации. - components/boot/README.md — раздел про sideboot с готовым compose snippet'ом, переменными окружения и опциональными INSTALL_*_DATA. Версионирование dicoop/bootcoop: совпадает с dicoop/contracts: (multi-stage из того же тега) — контракты и bootstrap синхронны. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/build-bootstrap.yaml | 102 +++++++++++++++++++++++++ components/boot/Dockerfile | 54 +++++++++++++ components/boot/README.md | 71 +++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 .github/workflows/build-bootstrap.yaml create mode 100644 components/boot/Dockerfile diff --git a/.github/workflows/build-bootstrap.yaml b/.github/workflows/build-bootstrap.yaml new file mode 100644 index 00000000000..5e2658efffa --- /dev/null +++ b/.github/workflows/build-bootstrap.yaml @@ -0,0 +1,102 @@ +name: Build bootstrap container + +# Сборка и публикация docker-образа `dicoop/bootcoop` — bootstrap-артефакта +# для развёртывания контрактов на удалённой ноде. Образ содержит CLI +# (`pnpm run boot:remote`) и `/contracts` от dicoop/contracts (multi-stage). +# Используется как one-shot job в стороннем docker-compose рядом с +# `dicoop/blockchain` — никакой mono-инфры (mongo/postgres/desktop) не нужно. +# +# Триггер — push в dev/testnet/main. Тег `dicoop/bootcoop` совпадает с +# веткой и подтягивает соответствующий тег `dicoop/contracts` (так +# контракты и bootstrap всегда синхронны). +# +# Зависимости в hub: +# dicoop/contracts: — пакет wasm/abi (build-contracts.yaml) +# dicoop/mono-base: — runtime с pnpm/node + workspace (build-containers.yaml) +# +# Секреты: +# DOCKERHUB_USERNAME / DOCKERHUB_TOKEN +# TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID + +on: + push: + branches: [dev, testnet, main] + paths: + - 'components/boot/**' + - '.github/workflows/build-bootstrap.yaml' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Determine docker tags + run: | + case "${{ github.ref_name }}" in + main) + echo "DOCKER_TAG=main" >> $GITHUB_ENV + echo "EXTRA_TAG=latest" >> $GITHUB_ENV + ;; + testnet) + echo "DOCKER_TAG=testnet" >> $GITHUB_ENV + echo "EXTRA_TAG=" >> $GITHUB_ENV + ;; + dev) + echo "DOCKER_TAG=dev" >> $GITHUB_ENV + echo "EXTRA_TAG=" >> $GITHUB_ENV + ;; + *) + echo "Unsupported branch ${{ github.ref_name }}" >&2 + exit 1 + ;; + esac + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Pull source images + run: | + docker pull dicoop/contracts:${{ env.DOCKER_TAG }} + docker pull dicoop/mono-base:${{ env.DOCKER_TAG }} + + - name: Build and push image + run: | + IMAGE="dicoop/bootcoop" + docker build \ + --build-arg CONTRACTS_TAG=${{ env.DOCKER_TAG }} \ + --build-arg MONO_BASE_TAG=${{ env.DOCKER_TAG }} \ + --label "org.opencontainers.image.revision=${{ github.sha }}" \ + --label "org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + -f components/boot/Dockerfile \ + -t "$IMAGE:${{ env.DOCKER_TAG }}" \ + . + docker push "$IMAGE:${{ env.DOCKER_TAG }}" + + if [ -n "${{ env.EXTRA_TAG }}" ]; then + docker tag "$IMAGE:${{ env.DOCKER_TAG }}" "$IMAGE:${{ env.EXTRA_TAG }}" + docker push "$IMAGE:${{ env.EXTRA_TAG }}" + fi + + SHORT_SHA="${GITHUB_SHA::7}" + docker tag "$IMAGE:${{ env.DOCKER_TAG }}" "$IMAGE:${{ env.DOCKER_TAG }}-$SHORT_SHA" + docker push "$IMAGE:${{ env.DOCKER_TAG }}-$SHORT_SHA" + + - name: Telegram notify success + if: ${{ success() }} + run: | + curl -s -X POST https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \ + -d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \ + -d text="✅ [GITHUB MONO] dicoop/bootcoop:${{ env.DOCKER_TAG }} (sha=${GITHUB_SHA::7})" + + - name: Telegram notify failure + if: ${{ failure() }} + run: | + curl -s -X POST https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \ + -d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \ + -d text="❌ [GITHUB MONO] Ошибка сборки dicoop/bootcoop на ${{ github.ref_name }} (sha=${GITHUB_SHA::7})" diff --git a/components/boot/Dockerfile b/components/boot/Dockerfile new file mode 100644 index 00000000000..0007de1adcc --- /dev/null +++ b/components/boot/Dockerfile @@ -0,0 +1,54 @@ +# Образ-bootstrap для удалённой ноды. +# +# Назначение: one-shot job в чужом docker-compose рядом с уже +# запущенным `node`-сервисом (dicoop/blockchain). Bootstrap +# дожидается готовности RPC, после чего вкатывает на ноду все +# системные и кооперативные контракты, активирует протокол-фичи, +# создаёт системный токен и инициализирует system/emission/powerup. +# +# Контракты НЕ собираются здесь — они тянутся multi-stage из +# готового артефакта `dicoop/contracts:` (см. workflow +# build-contracts.yaml) и кладутся в /contracts. CLI находит их +# через CONTRACTS_DIR. +# +# Окружение: +# CHAIN_URL — endpoint удалённой ноды (например http://node:8888) +# CONTRACTS_DIR=/contracts (выставлено по умолчанию) +# RPC_WAIT_TIMEOUT_MS — сколько ждать RPC (default 120000) +# EOSIO_PUB_KEY / EOSIO_PRV_KEY — ключи системного аккаунта eosio +# INSTALL_INITIAL_DATA=1 — опционально доставить mono-данные (нужны MONGO_URI/POSTGRES_*) +# INSTALL_EXTRA_DATA=1 — то же + расширенный совет +# +# Применение в стороннем compose: +# services: +# node: +# image: dicoop/blockchain:latest +# ports: ["8888:8888"] +# bootcoop: +# image: dicoop/bootcoop:dev +# depends_on: [node] +# environment: +# CHAIN_URL: http://node:8888 +# EOSIO_PUB_KEY: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV +# EOSIO_PRV_KEY: 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 +# restart: "no" + +ARG CONTRACTS_TAG=latest +ARG MONO_BASE_TAG=latest + +FROM dicoop/contracts:${CONTRACTS_TAG} AS contracts + +FROM dicoop/mono-base:${MONO_BASE_TAG} AS runtime + +# Контракты из готового артефакта в flat-layout +# (configs/contracts.ts читает из CONTRACTS_DIR). +COPY --from=contracts /contracts /contracts +ENV CONTRACTS_DIR=/contracts + +WORKDIR /app/components/boot + +# По умолчанию sideboot режим — против внешней ноды, без docker-управления. +# Переопределить можно: docker run dicoop/bootcoop:dev pnpm run boot:remote +# или подменив CMD/entrypoint в compose. +ENTRYPOINT ["pnpm", "run"] +CMD ["boot:remote"] diff --git a/components/boot/README.md b/components/boot/README.md index fc98e55209e..ae141e93bdd 100644 --- a/components/boot/README.md +++ b/components/boot/README.md @@ -51,6 +51,77 @@ pnpm install --filter @coopenomics/boot Подробное описание переменных — в файле `.env-example`. +## Запуск bootstrap'а в стороннем проекте (sideboot) + +Для проектов, которым нужна **только цепь + контракты** (без mongo/pg/mono-инфры), +есть готовый docker-образ `dicoop/bootcoop:`. Он one-shot job'ом +накатывает на удалённую ноду все системные и кооперативные контракты, +активирует протокол-фичи, создаёт системный токен. + +Минимальный `docker-compose.yaml` для стороннего репозитория: + +```yaml +services: + node: + image: dicoop/blockchain:latest + ports: + - "8888:8888" + - "9876:9876" + volumes: + - ./blockchain-data:/mnt/dev/data + command: > + /bin/bash -c "/usr/local/bin/nodeos -d /mnt/dev/data + --config-dir /mnt/dev/config + --genesis-json /mnt/dev/config/genesis.json" + + bootcoop: + image: dicoop/bootcoop:dev # или :testnet / :main / :latest + depends_on: [node] + restart: "no" + environment: + CHAIN_URL: http://node:8888 + EOSIO_PUB_KEY: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV + EOSIO_PRV_KEY: 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 + RPC_WAIT_TIMEOUT_MS: "180000" +``` + +Запуск: + +```bash +docker compose up -d node +docker compose up bootcoop # one-shot, выходит после успеха +``` + +Bootcoop ждёт `${CHAIN_URL}/v1/chain/get_info`, затем катит контракты на ноду. +По выходу с кодом 0 — цепь готова к работе. + +### Версионирование + +`dicoop/bootcoop:` всегда multi-stage'ится из `dicoop/contracts:` с +тем же `` (dev/testnet/main). Контракты и bootstrap синхронны по sha +коммита mono-репо — no skew. + +Точный пин по коммиту: `dicoop/bootcoop:dev-` (тегается каждой сборкой). + +### Дополнительные данные (опционально) + +Если в стороннем проекте всё же нужны mono-данные (voskhod, ant, совет) — +выставить флаги, и поднять рядом mongo + postgres: + +```yaml + environment: + CHAIN_URL: http://node:8888 + MONGO_URI: mongodb://mongo:27017/cooperative-x + POSTGRES_HOST: postgres + POSTGRES_USERNAME: postgres + POSTGRES_PASSWORD: postgres!23!23 + POSTGRES_DATABASE: voskhod + INSTALL_INITIAL_DATA: "1" # voskhod + ant + совет + INSTALL_EXTRA_DATA: "1" # + расширенный совет (5 пайщиков) +``` + +Без этих флагов запускается чистый chain-only сценарий. + ## Тестирование Перед запуском тестов необходима работающая инфраструктура (см. `docker-compose.yaml` в корне проекта):