Створення NaaS-платформи: оркестрація нод, K8s, білінг

Коли блокчейн-нод стає сотні, ручне керування перетворюється на хаос, а інфраструктура — на вузьке місце бізнесу. Ми розробляємо NaaS-платформи під ключ: від оркестрації нод на Kubernetes до білінгу та RPC-проксі. Наша команда бере на себе весь цикл — від аудиту до підтримки, забезпечуючи надійне рішення, яке масштабується разом із вашими завданнями.
Часті запитання

Запуск блокчейн-ноди вручну — просте завдання для однієї ноди. Коли їх стає сотня, це вже інфраструктурний проєкт з K8s, StatefulSet, snapshot bootstrap та білінгом. Ми займаємося Node-as-a-Service розробкою під ключ і побудували не одну таку платформу: від вибору клієнтів (Ethereum, Solana, BNB) до production-grade API Gateway з rate limiting та compute units. З нашої практики: один із клієнтів Fortune 500 замінив ручне управління нодами на NaaS — витрати на інфраструктуру знизилися на 40%, що принесло економію $15 000 на місяць, а річна економія перевищила $180 000. Зв'яжіться з нами — оцінимо ваш проєкт за 2 дні.

Як працює Node-as-a-Service платформа?

NaaS-платформа надає клієнтам єдиний RPC-ендпоінт, за яким прихована оркестрація десятків і сотень нод. Кожна нода запускається в K8s як StatefulSet з власним PersistentVolumeClaim. Для бюджетного сегменту ноди розділяються між клієнтами (shared), для вимогливих — виділяються цілком (dedicated) або кластерами з балансуванням (node clusters).

Чому стандартний Kubernetes не підходить для блокчейн-нод?

Звичайний Deployment в K8s не враховує специфіку блокчейн-нод, тому Kubernetes для блокчейн-інфраструктури вимагає використання StatefulSet. Ноди потребують stateful-сховища (сотні гігабайт), фіксованих P2P-портів та захисту від перезапусків без втрати синхронізації. Використовуємо StatefulSet з PVC та headless service — це гарантує, що при збої под не перествориться на іншому вузлі, а дані залишаться прив'язаними до storage.

Приклад конфігурації StatefulSet для Ethereum ноди:

apiVersion: apps/v1 kind: StatefulSet metadata: name: ethereum-geth spec: serviceName: "geth" replicas: 1 selector: matchLabels: app: ethereum-geth template: spec: containers: - name: geth image: ethereum/client-go:v1.13.14 args: ["--datadir=/data", "--http", "--http.addr=0.0.0.0", "--http.vhosts=*", "--http.api=eth,net,web3,txpool", "--ws", "--ws.addr=0.0.0.0", "--maxpeers=50", "--cache=4096"] ports: - containerPort: 8545 - containerPort: 8546 - containerPort: 30303 protocol: TCP - containerPort: 30303 protocol: UDP volumeMounts: - name: data mountPath: /data resources: requests: memory: "16Gi" cpu: "4" limits: memory: "32Gi" cpu: "8" volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: "fast-nvme" resources: requests: storage: 3Ti 

Проблеми, які вирішуємо

Snapshot bootstrapping

Синхронізація Ethereum mainnet з нуля (snap sync) займає 12–24 години, а архівна нода (archive node) — до 5 тижнів. Для NaaS це критично: клієнт платить з першої хвилини. Ми використовуємо snapshot distribution: кожні 7 днів створюємо актуальну копію бази даних, інкрементальні diffs — щоденно. Bootstrap ноди з snapshot займає 10–15 хвилин.

Порівняння режимів синхронізації нод Ethereum:

Режим Розмір даних Час синхронізації RPC-доступність
Snap sync ~500 GB 12–24 год Full
Full sync ~1.2 TB 3–5 днів Архів
Archive (архівна нода) ~15 TB 5–7 тижнів Архів + трасування

Ізоляція клієнтів

В одній платформі можуть працювати як стартапи з free tier, так і enterprise з гарантіями SLA. Розділяємо ресурси через три моделі мультитенантності, кожна зі своїм підходом до білінгу блокчейн-інфраструктури.

Модель Ізоляція Типовий кейс Приклад ціноутворення
Shared Низька (один процес) Free tier, тестові проєкти Оплата за CU
Dedicated Висока (виділена нода) Production, стабільний RPC Фіксована ставка
Node cluster Максимальна (репліки + LB) Enterprise, HA Індивідуальний розрахунок

Для білінгу блокчейн-інфраструктури використовуємо compute units — кожен RPC-метод має вагу в CU: eth_blockNumber — 10 CU, eth_call — 26 CU, trace_replayTransaction — 75 CU.

Як ми це робимо: стек і кейси

RPC-проксі з інтелектуальною маршрутизацією

Кастомний проксі на Go фільтрує небезпечні методи (наприклад, debug_* тільки для premium), розподіляє запити між archive та full нодами та кешує відповіді (TTL — 1 секунда для eth_blockNumber). Rate limiting реалізовано через Redis sliding window — він точніше token bucket для RPC-навантажень.

// Приклад RPC проксі з routing logic
package proxy

type RPCRouter struct {
	archivePool   NodePool
	fullNodePool  NodePool
	cacheClient   *redis.Client
}

var archiveMethods = map[string]bool{
	"eth_getBalance":           true,
	"eth_call":                 true,
	"eth_getStorageAt":         true,
	"trace_call":               true,
	"trace_replayTransaction":  true,
}

func (r *RPCRouter) Route(req *RPCRequest) NodePool {
	if archiveMethods[req.Method] {
		if req.RequiresHistoricalBlock() {
			return r.archivePool
		}
	}
	return r.fullNodePool
}

func (r *RPCRouter) Handle(w http.ResponseWriter, req *RPCRequest, apiKey string) {
	cacheKey := req.CacheKey()
	if cached, err := r.cacheClient.Get(ctx, cacheKey).Bytes(); err == nil {
		w.Write(cached)
		return
	}
	pool := r.Route(req)
	node := pool.GetHealthyNode()
	resp := node.Forward(req)
	if req.IsCacheable() {
		r.cacheClient.Set(ctx, cacheKey, resp, req.CacheTTL())
	}
	r.billing.RecordRequest(apiKey, req.Method, resp.ComputeUnits())
	w.Write(resp)
}

Health checking з урахуванням стану ноди

Ping не гарантує, що нода обробляє запити. Використовуємо перевірку синхронізації: якщо SyncProgress не nil або блок старше 2 хвилин — нода виключається з пулу. Health перевірки запускаємо кожні 15 секунд.

type NodeHealthChecker struct {
    client *ethclient.Client
}

func (h *NodeHealthChecker) IsHealthy(ctx context.Context) (bool, error) {
    syncing, err := h.client.SyncProgress(ctx)
    if err != nil {
        return false, err
    }
    if syncing != nil {
        return false, fmt.Errorf("node is syncing: %d/%d", syncing.CurrentBlock, syncing.HighestBlock)
    }
    header, err := h.client.HeaderByNumber(ctx, nil)
    if err != nil {
        return false, err
    }
    blockAge := time.Since(time.Unix(int64(header.Time), 0))
    if blockAge > 2*time.Minute {
        return false, fmt.Errorf("block too old: %v", blockAge)
    }
    return true, nil
}

Rate limiting на Redis

func (rl *RateLimiter) Allow(ctx context.Context, apiKey string, rps int) (bool, error) {
	now := time.Now().UnixMilli()
	window := int64(1000)
	pipe := rl.redis.Pipeline()
	pipe.ZRemRangeByScore(ctx, apiKey, "0", strconv.FormatInt(now-window, 10))
	pipe.ZCard(ctx, apiKey)
	pipe.ZAdd(ctx, apiKey, redis.Z{Score: float64(now), Member: now})
	pipe.Expire(ctx, apiKey, 2*time.Second)
	results, err := pipe.Exec(ctx)
	count := results[1].(*redis.IntCmd).Val()
	return count < int64(rps), nil
}

Білінг на основі compute units

CREATE TABLE api_keys (
    id UUID PRIMARY KEY,
    customer_id UUID NOT NULL,
    key_hash BYTEA NOT NULL,
    tier VARCHAR(20) NOT NULL,
    rate_limit_rps INTEGER NOT NULL,
    monthly_cu_limit BIGINT,
    node_type VARCHAR(20) NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE usage_records (
    id BIGSERIAL PRIMARY KEY,
    api_key_id UUID NOT NULL REFERENCES api_keys(id),
    method VARCHAR(100) NOT NULL,
    chain_id INTEGER NOT NULL,
    compute_units INTEGER NOT NULL,
    response_time_ms INTEGER,
    recorded_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_usage_billing ON usage_records (api_key_id, recorded_at);

Як ми будуємо NaaS-платформу: етапи та терміни

  1. Аналітика та аудит (1–2 тижні): визначаємо цільові блокчейни, модель мультитенантності, вимоги до SLA та регіону.
  2. Проектування архітектури (1–2 тижні): обираємо клієнти (Geth, Reth, Erigon, Solana Agave), готуємо схеми K8s, API Gateway, білінгу.
  3. Реалізація core infrastructure (4–6 тижнів): StatefulSet templates, snapshot bootstrap pipeline, health checker.
  4. Розробка API Gateway та білінгу (6–8 тижнів): RPC проксі, rate limiting, compute units, інтеграція Stripe.
  5. Observability та self-service portal (6–9 тижнів): Prometheus + Grafana, alerting, веб-інтерфейс для управління ключами та перегляду метрик.
  6. Тестування та деплой (2–3 тижні): навантажувальне тестування, security audit, запуск у production.

Разом: від 16 до 23 тижнів до production-ready платформи. Якщо ви хочете прискорити етап, зв'яжіться з нашими інженерами — ми запропонуємо відповідний темп.

Що входить у роботу

  • Документація: архітектурна схема, інструкції з додавання нових ланцюгів, runbook для on-call.
  • Доступи: репозиторій з шаблонами, CI/CD pipeline, моніторинг (Grafana dashboards).
  • Навчання: 2–3 сесії для вашої команди (DevOps та backend).
  • Підтримка: 3 місяці після запуску (багфікс, консультації).

Типові помилки при розробці NaaS

  • Використання hostNetwork для P2P портів — втрачається ізоляція. Краще NodePort або LoadBalancer з фіксованим портом на ноду.
  • Відсутність кешування частих RPC-методів (eth_chainId, eth_blockNumber) — збільшує навантаження на ноду та білінг.
  • Health check тільки по TCP — нода може бути живою, але відставати від мережі на сотні блоків.

Якщо ви зіткнулися з подібними проблемами або хочете уникнути їх, замовте розробку NaaS-платформи у нас. Детальніше про StatefulSet. Ми накопичили 10+ років досвіду в блокчейн-інфраструктурі та реалізували 50+ проєктів, включаючи платформи для Fortune 500. Зв'яжіться з нами — оцінимо вашу задачу та запропонуємо оптимальне рішення.

Напрямки блокчейн-розробки

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142