Добавить в корзинуПозвонить
Найти в Дзене
Lyakhov Eugene

Реализация Feature Toggle инфраструктуры

Приняли решение использовать Trunk-Based Development с Feature Toggles. Нам необходимо выбрать конкретную реализацию инфраструктуры для управления флагами. Описание: Самый зрелый open source feature flag сервер. TypeScript/Node.js, PostgreSQL, Web UI. Apache 2.0. Плюсы: 12k+ GitHub stars, 10+ лет разработки, большое community. Helm Chart, Java SDK, React SDK (через Edge proxy). Prometheus метрики. Работает air-gapped (Apache 2.0, нет license checks). Минусы: Вердикт: Стратегический риск — Edge EOL убивает React-сценарий через 10 месяцев. Описание: Open source feature flag платформа. C#/.NET, PostgreSQL + Redis, Web UI. MIT лицензия. Плюсы: Unlimited проекты и окружения бесплатно. RBAC, change requests, scheduled changes — бесплатно. Java SDK, React SDK, WebSocket real-time. Работает air-gapped (MIT, нет license checks). Минусы: Вердикт: Много фич бесплатно, но высокий risk чужого стека и bus factor. Описание: Git-native feature flag решение. Go, flags хранятся в Git как YAML. Fair Co
Оглавление

Контекст

Приняли решение использовать Trunk-Based Development с Feature Toggles. Нам необходимо выбрать конкретную реализацию инфраструктуры для управления флагами.

Ограничения среды

  • Air-gapped Kubernetes кластер в Yandex Cloud — нет выхода в интернет
  • Docker-образы загружаются через внутренний Container Registry
  • Никакие решения с license check / phone-home не работают
  • Стек: Java (Spring Boot), React, Envoy API Gateway, GitLab CI/CD, ArgoCD, Helm Charts
  • Секреты: Yandex Lockbox + External Secrets Operator

Требования

  • Уровень сложности флагов: kill switches (boolean on/off) + targeting по контексту
  • Три окружения: dev, stage, prod
  • Надёжность: если система флагов недоступна, приложения продолжают работать
  • Минимум дополнительной инфраструктуры

Рассмотренные варианты

1. Unleash OSS

Описание: Самый зрелый open source feature flag сервер. TypeScript/Node.js, PostgreSQL, Web UI. Apache 2.0.

Плюсы: 12k+ GitHub stars, 10+ лет разработки, большое community. Helm Chart, Java SDK, React SDK (через Edge proxy). Prometheus метрики. Работает air-gapped (Apache 2.0, нет license checks).

Минусы:

  • OSS ограничен 1 проектом и 2 окружениями (dev + prod). Эти лимиты нельзя обойти через env vars. Для трёх окружений (dev/stage/prod) потребуется либо workaround, либо отдельный инстанс.
  • Edge OSS (proxy для React) достигает End of Life 31 декабря 2026. После этого — без security-обновлений. Enterprise Edge — платный.
  • Нет SSO, нет fine-grained RBAC, нет change requests в OSS.
  • Enterprise: $75/seat/month (minimum 5 seats = $4,500/год).

Вердикт: Стратегический риск — Edge EOL убивает React-сценарий через 10 месяцев.

2. FeatBit OSS

Описание: Open source feature flag платформа. C#/.NET, PostgreSQL + Redis, Web UI. MIT лицензия.

Плюсы: Unlimited проекты и окружения бесплатно. RBAC, change requests, scheduled changes — бесплатно. Java SDK, React SDK, WebSocket real-time. Работает air-gapped (MIT, нет license checks).

Минусы:

  • Bus factor: 1-2 активных мейнтейнера. Проект может прекратить развитие.
  • C#/.NET стек — наша команда не может дебажить server-side код.
  • 5-6 Docker-образов (UI, API Server, Evaluation Server, Data Analytics, Redis, PostgreSQL) — больше компонентов для air-gapped registry.
  • Документация слабая. Маленькое community (~2.5k stars).
  • SSO — только Enterprise ($3,999/год).

Вердикт: Много фич бесплатно, но высокий risk чужого стека и bus factor.

3. Flipt v2

Описание: Git-native feature flag решение. Go, flags хранятся в Git как YAML. Fair Core License.

Плюсы: Git-native — идеально для GitOps (GitLab + ArgoCD). Modern UI. OpenFeature провайдеры. OFREP-совместимость.

Минусы:

  • Fair Core License (не open source). Бесплатная версия делает license check через интернет при старте. В air-gapped — не запускается.
  • Air-gapped режим — Pro фича ($1,000/год).
  • GitLab integration (merge proposals) — тоже Pro.

Вердикт: Не работает в air-gapped без оплаты.

4. flagd + ConfigMap + OpenFeature SDK (GitOps)

Описание: CNCF-проект flagd — лёгкий daemon для evaluation флагов. Флаги хранятся как YAML/JSON в Git-репозитории, синхронизируются в Kubernetes через ConfigMap и ArgoCD. Приложения используют vendor-neutral OpenFeature SDK.

Плюсы:

  • Apache 2.0 — нет license checks, нет phone-home, нет ограничений.
  • CNCF-стандарт (OpenFeature — Incubating project). Vendor-neutral API.
  • Минимум зависимостей: никаких БД, Redis, отдельных серверов. Только ConfigMap.
  • Наш существующий workflow: Git → GitLab MR → ArgoCD → ConfigMap → flagd.
  • In-Process режим: evaluation engine встраивается прямо в JVM, не нужен sidecar.
  • 2 Docker-образа максимум (flagd, если sidecar) или 0 дополнительных (in-process).
  • Evaluation в наносекундах (из памяти JVM).
  • Если flagd недоступен — приложение работает с последним кэшем.

Минусы:

  • Нет UI — управление только через Git (YAML) и kubectl.
  • Нет готового решения для React (нет Edge proxy). Требуется BFF-endpoint в Java-сервисе.
  • Изменение флага = коммит + MR + merge + ArgoCD sync (минуты, не секунды).
  • Нет встроенного audit log, RBAC, SSO (audit = Git history, RBAC = GitLab permissions).

Вердикт: Идеально для текущего этапа — zero cost, максимальная надёжность, встраивается в существующий GitOps workflow.

5. Собственная разработка (Spring Boot + React UI)

Описание: Evaluation engine на Java (Spring Boot), Admin UI на React, PostgreSQL для хранения. Полный контроль.

Плюсы: Полный контроль. Наш стек — можем дебажить и развивать. UI для нетехнических пользователей. Нет внешних зависимостей от чужих roadmap.

Минусы:

  • Недели-месяцы разработки вместо решения за день.
  • Поддержка: баги, security-патчи, SDK-обновления — всё на нас.
  • Reinventing the wheel для solved problem.

Вердикт: Преждевременно. Может быть рассмотрено в будущем, если появится реальная потребность в UI.

Решение

Выбран: Вариант 4 — flagd + ConfigMap + OpenFeature SDK (GitOps-подход).

Архитектура

┌─────────────────────────────────────────────────────────┐
│ GitLab Repository │
│ │
│ feature-flags/ │
│ ├── dev/ │
│ │ └── flags.json │
│ ├── stage/ │
│ │ └── flags.json │
│ └── prod/ │
│ └── flags.json │
└───────────────────────┬─────────────────────────────────┘
│ ArgoCD sync

┌─────────────────────────────────────────────────────────┐
│ Kubernetes (air-gapped) │
│ │
│ ┌─────────────────────────────┐ │
│ │ ConfigMap: feature-flags │ │
│ │ (per environment) │ │
│ └──────────────┬──────────────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────────┐ │
│ │Svc A │ │Svc B │ │React BFF │──▶ React App │
│ │ │ │ │ │ │ │
│ │flagd │ │flagd │ │flagd │ │
│ │in- │ │in- │ │in-proc + │ │
│ │proc │ │proc │ │/api/flags│ │
│ └──────┘ └──────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘

Формат файла флагов

{
"$schema": "https://flagd.dev/schema/v0/flags.json",
"flags": {
"new-payment-engine": {
"state": "ENABLED",
"variants": {
"on": true,
"off": false
},
"defaultVariant": "off",
"targeting": {
"if": [
{ "in": ["user-123", "user-456", { "var": "userId" }] },
"on",
"off"
]
}
},
"maintenance-mode": {
"state": "ENABLED",
"variants": {
"on": true,
"off": false
},
"defaultVariant": "off"
}
}
}

Java SDK — интеграция в микросервис

Maven зависимости:

<!-- OpenFeature SDK (vendor-neutral API) -->
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
</dependency>

<!-- flagd Provider (in-process evaluation) -->
<dependency>
<groupId>dev.openfeature.contrib.providers</groupId>
<artifactId>flagd</artifactId>
</dependency>

Spring Boot конфигурация:

@Configuration
public class FeatureFlagConfig {

@Bean
public OpenFeatureAPI openFeatureAPI() {
OpenFeatureAPI api = OpenFeatureAPI.getInstance();

// In-process: evaluation внутри JVM, флаги из файла
FlagdProvider provider = new FlagdProvider(
FlagdOptions.builder()
.resolverType(Config.Resolver.IN_PROCESS)
.offlineFlagSourcePath("/etc/feature-flags/flags.json")
.build()
);

api.setProviderAndWait(provider);
return api;
}

@Bean
public Client featureFlagClient(OpenFeatureAPI api) {
return api.getClient();
}
}

Использование в коде:

@RestController
public class PaymentController {

private final Client featureFlags;

@PostMapping("/pay")
public ResponseEntity<?> processPayment(@RequestBody PaymentRequest req) {
boolean newEngine = featureFlags.getBooleanValue(
"new-payment-engine", false,
new MutableContext(req.getUserId())
);

if (newEngine) {
return newPaymentService.process(req);
} else {
return oldPaymentService.process(req);
}
}
}

React — через BFF endpoint

В одном из Java-сервисов (API Gateway или BFF):

@RestController
@RequestMapping("/api/flags")
public class FeatureFlagController {

private final Client featureFlags;

@GetMapping
public Map<String, Boolean> getFlags(@RequestParam String userId) {
MutableContext ctx = new MutableContext(userId);
return Map.of(
"new-payment-engine", featureFlags.getBooleanValue("new-payment-engine", false, ctx),
"dark-mode", featureFlags.getBooleanValue("dark-mode", false, ctx),
"maintenance-mode", featureFlags.getBooleanValue("maintenance-mode", false, ctx)
);
}
}

React:

const { data: flags } = useSWR(`/api/flags?userId=${userId}`, fetcher);

if (flags?.['new-payment-engine']) {
return <NewCheckout />;
} else {
return <OldCheckout />;
}

Helm — монтирование ConfigMap

# values.yaml
featureFlags:
enabled: true
configMapName: feature-flags

# deployment.yaml
volumes:
- name: feature-flags
configMap:
name: {{ .Values.featureFlags.configMapName }}

volumeMounts:
- name: feature-flags
mountPath: /etc/feature-flags
readOnly: true

Workflow изменения флага

1. Разработчик редактирует feature-flags/prod/flags.json в GitLab
2. Создаёт Merge Request
3. Code review (кто approve — тот несёт ответственность)
4. Merge в main
5. ArgoCD обнаруживает изменение → обновляет ConfigMap
6. flagd in-process подхватывает новый файл (file watcher)
7. Следующий запрос пользователя видит новое значение флага

Время от merge до применения: ~1-3 минуты (ArgoCD sync interval).

Почему не UI-решения

Проведён детальный анализ всех основных решений с UI. Ключевые выводы:

-2

Последствия

Положительные

  • Запуск за день: ConfigMap + OpenFeature SDK — всё, что нужно
  • $0 стоимость: нет лицензий, подписок, license checks
  • Air-gapped native: никаких обращений к внешним сервисам
  • Vendor-neutral: OpenFeature SDK позволяет заменить flagd на любой другой бэкенд (Unleash, Flipt, собственный) без изменения бизнес-кода
  • Минимум инфраструктуры: нет дополнительных БД, серверов, sidecar-ов
  • Git = audit log: вся история изменений флагов в Git (кто, когда, что, зачем, через MR)
  • Git = RBAC: GitLab permissions контролируют, кто может мержить изменения флагов
  • Git = approval workflow: MR review = change request
  • Знакомый workflow: GitLab MR → ArgoCD — команда уже это использует каждый день

Отрицательные

  • Нет UI для нетехнических пользователей. PM не может сам нажать кнопку.
  • Изменение = коммит. Минуты, не секунды. Для экстренного отключения — медленнее, чем кнопка в UI.
  • BFF для React — ручная работа. Каждый новый флаг для фронтенда нужно добавить в endpoint.

Митигация

  • Если появится потребность в UI — можно мигрировать на Unleash/FeatBit/собственное решение, заменив только OpenFeature Provider. Бизнес-код останется без изменений.
  • Для экстренного отключения: kubectl edit configmap feature-flags работает за секунды без MR.
  • BFF endpoint можно сделать динамическим (возвращает все флаги из файла, без хардкода).

План внедрения

-3

Страховка на собеседовании

Знание есть, но стресс мешает?
Бесплатное сообщество для прокачки карьеры в IT

Подпишись на https://t.me/IT_Interview_Partner_Bot
Подпишись на
https://t.me/LyakhovEugene