Ваш ноутбук — это ваша среда стейджинга. Буквально.
В этой статье мы пройдём путь от локального исходного кода полиглотного микросервисного приложения до продакшн-кластера Kubernetes с TLS, Auth0-авторизацией и Stripe-вебхуками — всё работает сквозь, end-to-end. Без облачного стейджинга. Без Docker Compose. Без ручного написания YAML.
Приложение называется oauth-example — демо из четырёх сервисов, которое можно склонировать и повторять шаг за шагом.
Что мы строим
Микросервисное приложение с реальными внешними интеграциями:
Browser → UI (React/nginx)
↓
Gateway (Go) ← Auth0 OIDC login/callback
↓ ← Stripe webhook receiver
┌────┴────┐
Orders Inventory
(Python) (Node.js)
Postgres MongoDB
Redis ←──── shared event queue
-
UI — React-дашборд, раздаваемый через nginx
-
Gateway — обратный прокси на Go с Auth0 OIDC и верификацией Stripe-вебхуков
-
Orders — Python FastAPI с Postgres, публикует события в Redis
-
Inventory — Node.js Fastify с MongoDB, потребляет события заказов из Redis
Самое интересное: Auth0 требует публичный HTTPS-адрес для callback-редиректа, а Stripe — публичный HTTPS-эндпоинт для вебхуков. Именно это делает локальную разработку мучительной — и именно это решает kindling.
Шаг 1: инициализация кластера
brew install kindlingdev/tap/kindling
kindling init
Всё. У вас теперь есть Kind-кластер с оператором, встроенным container registry и Traefik ingress-контроллером. Полностью локально, полностью одноразово.
Шаг 2: регистрация CI-раннера
kindling runners -u <github-user> -r oauth-test -t <github-pat>
Команда разворачивает self-hosted GitHub Actions runner внутри вашего Kind-кластера. Когда вы пушите код, CI запускается локально — сборки выполняются через Kaniko, образы попадают во встроенный registry по адресу localhost:5001. Никакого DockerHub. Никакого ECR. Никакого ожидания удалённого CI.
Шаг 3: генерация CI-воркфлоу
kindling generate -k <api-key> -r .
ИИ Kindling анализирует репозиторий — находит четыре сервиса, определяет языки и фреймворки, читает Dockerfile’ы, обнаруживает манифесты деплоя — и генерирует GitHub Actions воркфлоу, который собирает и деплоит всё. Сгенерированный воркфлоу берёт на себя:
-
сборку каждого сервиса через Kaniko
-
пуш образов во встроенный registry
-
применение DSE-манифестов (DevStagingEnvironment)
-
связывание сервисов между собой через переменные окружения
-
подготовку зависимостей (Postgres, Redis, MongoDB)
Этот воркфлоу не надо писать вручную и поддерживать. Запушили код — он запустится сам.
Шаг 4: создание аккаунтов Auth0 и Stripe, настройка учётных данных
Манифест деплоя шлюза ссылается на секреты через secretKeyRef — Kubernetes не запустит под, если они отсутствуют. Создайте аккаунты во внешних сервисах и задайте учётные данные до первого деплоя.
Создание приложения в Auth0
-
Зарегистрируйтесь или войдите на auth0.com
-
В Auth0 Dashboard перейдите в Applications → Create Application
-
Назовите приложение, например
oauth-example-dev, выберите Regular Web Application и нажмите Create -
На вкладке Settings скопируйте три значения — они понадобятся чуть позже:
-
Domain (например,
your-tenant.us.auth0.com) -
Client ID
-
Client Secret
-
Callback URL’ы пока не настраивайте — для этого нужен публичный tunnel URL, который появится после деплоя.
Создание Stripe webhook endpoint
-
Зарегистрируйтесь или войдите на dashboard.stripe.com
-
Убедитесь, что включён Test mode (переключатель в правом верхнем углу)
-
Откройте вкладку Webhooks в Workbench
Сам webhook endpoint вы создадите позже, когда получите tunnel URL. Пока просто скопируйте Stripe Secret Key в разделе Developers → API keys — он начинается с sk_test_.
Задание предварительных секретов
Задайте учётные данные, чтобы поды могли стартовать:
kindling secrets set AUTH0_DOMAIN your-tenant.auth0.com
kindling secrets set AUTH0_CLIENT_ID your-client-id
kindling secrets set AUTH0_CLIENT_SECRET your-client-secret
kindling secrets set SESSION_SECRET $(openssl rand -hex 32)
kindling secrets set STRIPE_SECRET_KEY sk_test_your_stripe_secret_key
kindling secrets set STRIPE_WEBHOOK_SECRET placeholder
kindling secrets set PUBLIC_URL http://localhost
STRIPE_WEBHOOK_SECRET и PUBLIC_URL — заглушки: шлюз запустится без них, но не упадёт. Настоящие значения вы зададите после запуска тоннеля.
Обратите внимание: STRIPE_SECRET_KEY (начинается с sk_test_) — это ваш Stripe API key из раздела Developers → API keys. Он отличается от STRIPE_WEBHOOK_SECRET (начинается с whsec_) — это signing secret для вебхука, который вы получите после создания webhook endpoint на шаге 6.
DSE-манифесты ссылаются на эти значения через secretKeyRef — оператор передаёт их в под шлюза как переменные окружения. Никаких секретов в YAML. Никаких секретов в .env-файлах. Никаких секретов в git.
Шаг 5: пуш и деплой
git add -A && git commit -m "initial deploy"
git push origin main
Раннер подхватывает пуш, собирает все четыре образа, оператор деплоит их. Проверьте статус:
kindling status
▸ Dev Staging Environments
📦 jeff-vincent-gateway 9090 jeff-vincent-gateway.localhost
📦 jeff-vincent-inventory 3000 jeff-vincent-inventory.localhost
📦 jeff-vincent-orders 5000 jeff-vincent-orders.localhost
📦 jeff-vincent-ui 80 jeff-vincent-ui.localhost
▸ All Deployments
jeff-vincent-gateway 1/1
jeff-vincent-inventory 1/1
jeff-vincent-inventory-mongodb 1/1
jeff-vincent-orders 1/1
jeff-vincent-orders-postgres 1/1
jeff-vincent-orders-redis 1/1
jeff-vincent-ui 1/1
Четыре сервиса, три базы данных — всё запущено. Откройте http://jeff-vincent-ui.localhost, и дашборд будет живым. Auth0 и Stripe пока не подключены — это следующий шаг.
Шаг 6: запуск тоннеля и настройка OAuth + вебхуков
Теперь, когда сервисы запущены, нужен публичный HTTPS URL для Auth0 callback’ов и Stripe-вебхуков. Kindling использует бесплатные quick tunnels от Cloudflare. Создайте бесплатный аккаунт Cloudflare, перейдите в Protect and Connect > Networking > Tunnels и создайте тоннель. Затем запустите Cloudflare daemon на локальной машине:
brew install cloudflared &&
sudo cloudflared service install <your-token>
kindling expose
Вы получите публичный URL вида https://verb-noun-adj-noun.trycloudflare.com. Скопируйте его.
Тоннель работает в фоне. URL меняется при каждом перезапуске, поэтому callback URL’ы в Auth0 и Stripe нужно обновлять, когда требуется тестировать внешние интеграции. Для большинства повседневных задач тоннель не нужен вовсе.
Настройка callback URL’ов в Auth0
Вернитесь в настройки Auth0-приложения и задайте следующие значения:
Auth0 Dashboard → Applications → oauth-example-dev → Settings → Application URIs Allowed Callback URLs https://<your-tunnel-url>/auth/callback Allowed Logout URLs https://<your-tunnel-url> Allowed Web Origins https://<your-tunnel-url>
Замените <your-tunnel-url> на URL из kindling expose (например, verb-noun-adj-noun.trycloudflare.com).
Нажмите Save Changes.
Callback URL — это адрес, на который Auth0 перенаправляет пользователя после аутентификации. Он должен точно совпадать с тем, что шлюз передаёт в OIDC authorization request. Путь /auth/callback обрабатывается OIDC callback handler’ом шлюза: он обменивает authorization code на токены и устанавливает session cookie.
OIDC-интеграция шлюза использует Universal Login от Auth0 — кастомная страница входа не нужна. Подробнее — в руководстве по началу работы с Auth0.
Создание Stripe webhook endpoint
Теперь создайте webhook endpoint в Stripe, указав tunnel URL:
-
В Workbench → Webhooks нажмите Create an event destination
-
Пройдите через мастер создания:
Events from Your account API version Выберите версию по умолчанию (или последнюю) Events checkout.session.completed payment_intent.succeeded
-
Нажмите Continue, затем выберите Webhook endpoint как тип назначения
-
Нажмите Continue и задайте:
Endpoint URL https://<your-tunnel-url>/webhooks/stripe
-
Нажмите Create destination
-
Выберите созданный endpoint и нажмите Click to reveal, чтобы скопировать signing secret (
whsec_…)
Webhook URL — адрес, на который Stripe отправляет POST-запросы с данными событий. Шлюз получает запрос на /webhooks/stripe, верифицирует заголовок Stripe-Signature по signing secret через HMAC-SHA256 и пересылает валидные payload’ы в сервис orders. Неверифицированные запросы отклоняются с кодом 400. Подробнее о верификации подписей и типах событий — в документации Stripe по вебхукам.
Задание настоящих PUBLIC_URL и webhook secret
Теперь обновите значения-заглушки на реальные:
kindling secrets set PUBLIC_URL https://<your-tunnel-url>
kindling secrets set STRIPE_WEBHOOK_SECRET whsec_your_signing_secret
Под шлюза перезапустится автоматически и подхватит новые значения. Убедитесь через kindling status, что шлюз снова в состоянии 1/1.
Шаг 7: внутренний цикл разработки
Теперь вы разрабатываете. Вы меняете код и хотите видеть изменения сразу. Проверьте статус:
kindling status
▸ Dev Staging Environments
📦 jeff-vincent-gateway 9090 jeff-vincent-gateway.localhost
📦 jeff-vincent-inventory 3000 jeff-vincent-inventory.localhost
📦 jeff-vincent-orders 5000 jeff-vincent-orders.localhost
📦 jeff-vincent-ui 80 jeff-vincent-ui.localhost
▸ All Deployments
jeff-vincent-gateway 1/1
jeff-vincent-inventory 1/1
jeff-vincent-inventory-mongodb 1/1
jeff-vincent-orders 1/1
jeff-vincent-orders-postgres 1/1
jeff-vincent-orders-redis 1/1
jeff-vincent-ui 1/1
Четыре сервиса, три базы данных — всё запущено. Откройте http://jeff-vincent-ui.localhost, и дашборд будет живым.
Шаг 6: внутренний цикл разработки
Вы разрабатываете. Код меняется — изменения нужны немедленно.
kindling sync -d jeff-vincent-gateway
Изменения файлов синхронизируются напрямую в работающий под — без пересборки образа и повторного деплоя. Для Go-сервисов бинарник перекомпилируется прямо внутри контейнера. Для Python и Node.js изменение файла автоматически запускает перезагрузку.
Нужно отлаживать код пошагово? Запустите debug из корня проекта:
cd /path/to/oauth-test
kindling debug -d jeff-vincent-orders --port 5678
|
Примечание
|
kindling debug нужно запускать из корня проекта — команде требуется доступ к дереву исходников для настройки сеанса отладки.
|
Подключите отладчик IDE к localhost:5678 и расставляйте точки останова в сервисе orders прямо во время его работы внутри кластера — с живыми Postgres и Redis.
Шаг 8: тестирование OAuth и Stripe
Когда сервисы запущены и секреты настроены, проверьте, что всё связано:
curl http://jeff-vincent-gateway.localhost/auth/status
# {"auth0_configured":true,"callback_url":"https://<your-tunnel-url>/auth/callback"}
curl http://jeff-vincent-gateway.localhost/stripe/status
# {"stripe_webhook_configured":true,"webhook_url":"https://<your-tunnel-url>/webhooks/stripe"}
Откройте tunnel URL в браузере (например, https://verb-noun-adj-noun.trycloudflare.com), нажмите Login — загрузится универсальная страница входа Auth0, вы аутентифицируетесь, и callback перенаправит обратно на tunnel URL. Запрос проходит по цепочке: Cloudflare → localhost:80 → Traefik → ingress шлюза, который обменивает код на токены и устанавливает session cookie. Полный OIDC flow — локально.
Для Stripe вызовите тестовое событие из Stripe Dashboard или воспользуйтесь Stripe CLI. Событие поступает на шлюз по tunnel URL тем же путём — Cloudflare → localhost:80 → Traefik → шлюз — подпись верифицируется по signing secret, payload пересылается в сервис orders, который обновляет статус заказа в Postgres.
Шаг 9: деплой в продакшн
Dev-окружение проверено. Auth0 callbacks работают. Stripe-вебхуки приходят. Пора запускать в продакшн.
kindling dashboard --prod-context <your-prod-cluster-context>
Продакшн-дашборд подключается к реальному кластеру. Дальше:
-
Snapshot — оператор фиксирует точные теги образов, переменные окружения и конфигурацию зависимостей
-
Deploy — образы перетегируются и пушатся в продакшн registry, манифесты применяются
-
TLS — cert-manager автоматически выпускает сертификаты Let’s Encrypt
|
Примечание
|
После деплоя нужно обновить A-запись DNS вашего домена, указав IP нового балансировщика нагрузки (найдите его командой kubectl get svc traefik -n traefik). Распространение DNS может занять несколько минут — в это время браузер может показывать предупреждение «Ваше подключение не является приватным» (ERR_CERT_AUTHORITY_INVALID). Это нормально. Займитесь чем-нибудь другим — и не сидите, судорожно обновляя страницу. Когда DNS распространится, cert-manager завершит ACME challenge и сертификат Let’s Encrypt будет выпущен автоматически.
|
В продакшне замените секреты на продакшн-значения:
-
AUTH0_DOMAIN→ ваш продакшн tenant в Auth0 -
AUTH0_CLIENT_ID/AUTH0_CLIENT_SECRET→ credentials продакшн-приложения -
STRIPE_SECRET_KEY→ продакшн API key Stripe (начинается сsk_live_) -
STRIPE_WEBHOOK_SECRET→ продакшн signing secret вебхука (начинается сwhsec_) -
PUBLIC_URL→ ваш продакшн домен
Тот же код, та же архитектура, та же модель деплоя. Меняются только секреты и домен.
Что произошло
Проследим весь путь:
-
Исходный код на ноутбуке
-
kindling init— локальный Kind-кластер с оператором, registry и ingress -
kindling generate— CI-воркфлоу, сгенерированный ИИ -
kindling secrets set— Auth0/Stripe credentials заданы, поды могут стартовать -
git push— локальный раннер собирает образы через Kaniko, деплоит через оператор -
kindling expose+kindling secrets set— тоннель запущен, callback URL’ы в Auth0/Stripe настроены,PUBLIC_URLобновлён -
kindling sync— живые изменения кода без пересборки -
Тест OAuth + Stripe — сквозная проверка callback flow’ов
-
Деплой в продакшн — те же образы, та же конфигурация, реальный кластер с TLS
Никакого Docker Compose. Никаких Helm-чартов. Никакого Terraform. Никаких расходов на облачный стейджинг. Никаких расхождений в духе «у меня работает» между dev и prod.
Вся среда стейджинга живёт на ноутбуке. Если здесь работает — будет работать в продакшне: тот же Kubernetes, те же контейнерные образы, та же сетевая модель.
Попробуйте сами
brew install kindlingdev/tap/kindling
git clone https://github.com/kindling-sh/oauth-example
cd oauth-example
kindling init
kindling runners -u <user> -r oauth-example -t <pat>
kindling generate -k <api-key> -r .
# Задаём credentials, чтобы поды могли стартовать
kindling secrets set AUTH0_DOMAIN <your-domain>
kindling secrets set AUTH0_CLIENT_ID <your-id>
kindling secrets set AUTH0_CLIENT_SECRET <your-secret>
kindling secrets set SESSION_SECRET $(openssl rand -hex 32)
kindling secrets set STRIPE_SECRET_KEY <sk_test_...>
kindling secrets set STRIPE_WEBHOOK_SECRET placeholder
kindling secrets set PUBLIC_URL http://localhost
# Деплоим
git push origin main
# Запускаем тоннель, настраиваем callback URL'ы в Auth0/Stripe, обновляем секреты
kindling expose
# скопируйте tunnel URL, добавьте его в дашборды Auth0 и Stripe
kindling secrets set PUBLIC_URL <your-tunnel-url>
kindling secrets set STRIPE_WEBHOOK_SECRET <whsec_...>
Ваш ноутбук — это ваша среда стейджинга. Начинайте строить.