RAILSHOT.
Обратно в залата

Railshot

AI deployment & operations platform

Внедряване на локално създадено уеб приложение в подготвени облачни и локални среди и последваща експлоатация.

AI платформа за внедряване и експлоатация, която отвежда локално създадено уеб приложение в подготвени облачни или локални (on-premises) среди и го поддържа в работа.

28 септември 2026 г. – 4 октомври 2026 г. · Завършен

Екипен проект · моята част: планиране и реализация на CI, CSP клъстери и интерфейс с Ansible, експлоатация, преглед на кода и интеграция в екипа

SoftBank Hackathon 2026 powered by KOREC & ProgateУчастник в предварителния кръг · обявяването на финалистите се очаква на 26 октомври 2026 г. (към 7 октомври 2026 г.)

  • УебРеализирано · хакатон
  • MCP сървърРеализирано · отдалечен · локален

Оперативният клъстер и клъстерите за клиентски приложения са отделни, а публичният път е отделен от управлението на внедряването.

В оперативния K3s таблото, продуктовият API и build controller са разположени на възли с роля platform, а runner Job са на възел с роля build, докато Argo CD отговаря за внедряването. Клиентските приложения работят в определен namespace на отделен еднонодов клъстер K3s + Cilium за всяка регистрирана цел.

Карта на клъстерите · по декларациите и кода при публичния къмит 645e28a
Карта на оперативния и клиентските клъстери на RailshotОперативният клъстер K3s и регистриран клъстер за клиентско приложение. В оперативния клъстер namespace railshot-system поставя таблото, продуктовия API, отдалечения MCP (само когато е подаден образът му) и build controller на възли с роля platform; runner Job в namespace railshot-build поемат задачи на GitHub Actions на възела с роля build, маркиран с taint. Release job, хостван в GitHub, публикува тествания пакет в GHCR. Продуктовият API прави къмит на работното натоварване в config Git и синхронизира Application в namespace argocd, а Argo CD прилага Deployment, NodePort Service и NetworkPolicy в регистрирания namespace на клиентския клъстер. Заявките към приложението влизат през L7 входна точка на доставчика към NodePort и Service на възела, а после към Pod на приложението. Вердиктът за внедряването се основава само на състоянието в Argo и на проверката на публичния URL; диагностиката на Pod, логовете и метриките се четат като отделни сигнали. Входовете на оператора за инсталиране и регистрация са отделени от payload на приложението на клиента.Потребител на Railshotтабло · MCPBootstrap от оператораинсталиране · регистрация · SecretGHCRобрази по digestхранилище config Gitworkload.json · revisionL7 входна точка на доставчикаALB · GCP LB · AmphoraПотребител на приложениетопубличен HTTPSVM за наблюдениеизвън клиентския K3s · Composerailshot-systemdashboard · nginxотдалечен MCP · само с образbuild controller · CronJobпродуктов API · cd.js → bridge.pyargocdArgo CD · ApplicationAppProject · cluster SecretCronJob за подновяване · на всеки 2 hrailshot-buildrunner Job · hostNetwork · Docker socketrailshot-deploy.ymlloop job · self-hosted runnerrelease job · GitHub-hosted<app namespace>Deployment · Pod · образ по digestNodePort Service · LocalNetworkPolicy · само изброените CIDRSA railshot-argocd · токенkube-systemCilium · Helm · VXLANrailshot-observabilitynode-exporterkube-state-metricsОперативен клъстер · K3sAWS · възли по роливъзли с роля platformnodeSelectorвъзел с роля buildNoSchedule taintGitHubActions · GHCRКлъстер за клиентско приложение · примерпо един за всяка регистрирана целЕдин възел K3s · serverCilium · kube-proxy е запазен1workflow_dispatch2попълване на runner Job3поемане на задачата4тестван пакет5 публикуване по digest · release job · GitHub-hosted → GHCR51workload commit · push2revision3 Application sync · продуктов API · cd.js → bridge.py → Argo CD · Application34прилагане в namespace5изтегляне по digest1HTTPS 4432NodePort3 към Pod · NodePort Service · Local → Deployment · Pod · образ по digest34 прилагане на политиката · Cilium · Helm · VXLAN → NetworkPolicy · само изброените CIDR45 табло · API · Потребител на Railshot → dashboard · nginx51 ревизия · health · образи · продуктов API · cd.js → bridge.py → Argo CD · Application12публична HTTPS проверка3Диагностика на Pod · не вердикт4край на лога · 100 реда на Pod5scrape · NodePort6Blackbox probe1рендиране на платформата · Secret2bootstrap за регистрация3инсталиране на K3s · Cilium4TokenRequest · 6 h

Изграждане → публикуване на образа

Продуктовият API иска изпълнение в GitHub Actions, а runner на build възела поема и проверява задачата. Само пакет, преминал същите проверки, се публикува в GHCR от release job, хостван в GitHub.

  1. продуктов API · cd.js → bridge.pyrailshot-systemизпълнение · прилагане: workflow_dispatchloop job · self-hosted runnerrailshot-deploy.yml

    Продуктовият API иска изпълнение в GitHub Actions с tenant, app, source commit и цел. API никога не извиква runner Job директно.

  2. build controller · CronJobrailshot-systemизпълнение · прилагане: попълване на runner Jobrunner Job · hostNetwork · Docker socketrailshot-build

    CronJob на build controller (всяка минута, на platform възел) създава runner Job в namespace railshot-build. Неговата Role позволява само get, list и create за Job, както и get, update и patch върху единствения Secret за регистрация на runner; тя не може да създава namespace или други Secret.

  3. runner Job · hostNetwork · Docker socketrailshot-buildизпълнение · прилагане: поемане на задачатаloop job · self-hosted runnerrailshot-deploy.yml

    Runner на възела с роля build (точен hostname, NoSchedule toleration) поема loop job по етикетите self-hosted и го изпълнява. Изходният код на клиента се изпълнява в съществуващите ограничени Docker контейнери за изграждане и проверка.

  4. runner Job · hostNetwork · Docker socketrailshot-buildданни: тестван пакетrelease job · GitHub-hostedrailshot-deploy.yml

    Loop job оставя пакета, преминал същите проверки, а release job поема само този пакет.

  5. release job · GitHub-hostedrailshot-deploy.ymlданни: публикуване по digestGHCR

    Release job, хостван в GitHub (ubuntu-24.04), публикува образа на тествания пакет в GHCR, без да го изгражда отново. Публикуване на образи никога не се извършва в клъстера за клиентски приложения.

Config Git → Argo → namespace на клиента

Config Git носи желаните ресурси, а GHCR байтовете на образа. Argo CD прилага само в регистрирания namespace на клиента.

  1. продуктов API · cd.js → bridge.pyrailshot-systemданни: workload commit · pushхранилище config Git

    cd.js изпълнява bridge.py, който прави къмит и push на workload.json само когато записът за публикуване и регистрираната цел съвпадат, след което прочита обратно отдалечената ревизия. Git носи желаните ресурси; GHCR носи байтовете на образа.

  2. хранилище config Gitданни: revisionArgo CD · Applicationargocd

    Application чете само ограничените си хранилище с конфигурация, път и ревизия.

  3. продуктов API · cd.js → bridge.pyrailshot-systemизпълнение · прилагане: Application syncArgo CD · Applicationargocd

    Посоченият Application се задава чрез server-side apply и се иска синхронизиране на една точна ревизия без prune. ServiceAccount railshot-product на продуктовия API държи както инсталирания от оператора bootstrap за регистрация (create за Secret, AppProject и Application в argocd; get, update и escalate за посочени Role), така и правата get и patch, добавени с точно име за всяка валидирана цел. Create в Kubernetes не може да се ограничи по име, затова валидирането на входа в продукта също държи имената в обхвата.

  4. Argo CD · Applicationargocdизпълнение · прилагане: прилагане в namespace<app namespace>

    Argo CD прилага в определения namespace на клиентския клъстер с идентификационните данни на регистрирания Secret на клъстера. AppProject позволява само видове в рамките на namespace и никакви ресурси на ниво клъстер.

  5. Deployment · Pod · образ по digest<app namespace>данни: изтегляне по digestGHCR

    Публикуваният образ по digest се изтегля с pull Secret, посочен по име в същия namespace. Стойностите на Secret никога не попадат в артефакта или в config Git.

Публичен път на заявките

Заявките към приложението минават по пътя L7 входна точка на доставчика → NodePort на възела → Service → Pod на приложението. Прилагането на политиките от Cilium е отделен контрол, а не стъпка, която пренася заявката. Пътят към оперативното табло е отделен.

  1. Потребител на приложениетоданни: HTTPS 443L7 входна точка на доставчика

    Потребителите на приложението достигат L7 входната точка на доставчика чрез регистрирания hostname. Всеки доставчик реализира собствена входна точка.

  2. L7 входна точка на доставчикаданни: NodePortNodePort Service · Local<app namespace>

    Входната точка препраща към частния адрес и NodePort на възела. NodePort е този, разпределен при регистрацията на целта.

  3. NodePort Service · Local<app namespace>данни: към PodDeployment · Pod · образ по digest<app namespace>

    Service изпраща заявката към Pod на приложението (Deployment) на същия възел. При externalTrafficPolicy Local адресът на източника стига непроменен до проверката на регистрираните CIDR в NetworkPolicy.

  4. Cilium · Helm · VXLANkube-systemизпълнение · прилагане: прилагане на политикатаNetworkPolicy · само изброените CIDR<app namespace>

    Cilium прилага NetworkPolicy: входящ трафик само от регистрираните CIDR към порта на приложението; по подразбиране без изходящ трафик, освен към одобрен адрес на база данни. Облачните защитни стени и правилата на хоста продължават да имат значение.

  5. Потребител на Railshotданни: табло · APIdashboard · nginxrailshot-system

    Потребителите влизат през оперативната входна точка към таблото с nginx, а nginx стои пред продуктовия API. Service на таблото е NodePort само когато е зададен одобрен порт на възела; API остава ClusterIP.

Проверка · наблюдение

Вердиктът за внедряването се основава само на състоянието в Argo и на проверката на публичния URL. Диагностиката на Pod, текущите логове и оперативните метрики са отделни сигнали, които никога не го променят.

  1. продуктов API · cd.js → bridge.pyrailshot-systemнаблюдение: ревизия · health · образиArgo CD · Applicationargocd

    За deployed са нужни ревизията на синхронизиране на Application, Synced и Healthy, operation Succeeded и съвпадение на препратките към образи, записани в състоянието на Argo Application, с образите по digest на прегледания Deployment. Това не е пряка порта по imageID на Pod, а зеленото състояние в Argo само по себе си не установява съвпадението.

  2. продуктов API · cd.js → bridge.pyrailshot-systemнаблюдение: публична HTTPS проверкаL7 входна точка на доставчика

    Регистрираният публичен URL се проверява без пренасочвания. Succeeded се записва само при вердикта от Argo и тази проверка.

  3. продуктов API · cd.js → bridge.pyrailshot-systemнаблюдение: Диагностика на Pod · не вердиктDeployment · Pod · образ по digest<app namespace>

    След вердикта от Argo и публичната проверка Deployment, ReplicaSet и Pod се четат отделно с регистрираните идентификационни данни, а imageID и готовността се добавят като диагностика ready, progressing или unavailable. Неуспешна или различаваща се диагностика никога не променя вердикта deployed или succeeded.

  4. продуктов API · cd.js → bridge.pyrailshot-systemнаблюдение: край на лога · 100 реда на PodDeployment · Pod · образ по digest<app namespace>

    Само за текущо внедрената операция, с доверената конфигурация и регистрираните идентификационни данни. За всеки текущ Pod (най-много три) digest на работещия образ трябва да съвпада с очаквания digest; след това се четат до 100 реда със заличени данни на Pod в рамките на лимит в байтове. За по-стар опит отговорът е superseded; без конфигурация – not_configured. Това не е агрегиране на логове.

  5. VM за наблюдениенаблюдение: scrape · NodePortrailshot-observability

    Prometheus на VM за наблюдение събира node-exporter и kube-state-metrics през два NodePort, ограничени със защитна стена. Липсващите или остарелите стойности са неизвестни, а не нула.

  6. VM за наблюдениенаблюдение: Blackbox probeL7 входна точка на доставчика

    probe_success=1 означава 2xx в тази точка на пробата. Това не доказва нито достъпа на всеки потребител, нито внедрената версия и никога не повишава published до deployed.

Инсталиране · регистрация от оператора

Инсталирането на клъстера, bootstrap за регистрацията и входните данни за целта, Secret и настройката за подновяване на идентификационните данни са входове на оператора и никога не са част от payload на приложението на клиента.

  1. Bootstrap от оператораизпълнение · прилагане: рендиране на платформата · Secretrailshot-system

    Операторът рендира декларацията на платформата с render-platform.py и подава непубличната оперативна конфигурация и Secret. Отдалеченият MCP се включва само когато е подаден образът му, а личният gateway (WireGuard) само с --personal.

  2. Bootstrap от оператораизпълнение · прилагане: bootstrap за регистрацияAppProject · cluster Secretargocd

    Операторът инсталира в argocd Role за bootstrap на регистрацията и празна Role registrations и подготвя входните данни за целта. След това помощните програми за регистрация, изпълнявани от продуктовия API (environment.py, applications.py), записват Secret railshot-<target> с ограничени идентификационни данни (clusterResources false, изброени разрешени namespace) и добавят валидираните точни имена в Role registrations. Регистрацията на всяко приложение обвързва namespace app-<id> с AppProject със същото име.

  3. Bootstrap от оператораизпълнение · прилагане: инсталиране на K3s · CiliumCilium · Helm · VXLANkube-system

    install-k3s.sh инсталира еднонодов K3s server (flannel, network policy, traefik и servicelb изключени; kube-proxy запазен), а Cilium се инсталира като Helm release (kubeProxyReplacement false, VXLAN, Hubble изключен).

  4. CronJob за подновяване · на всеки 2 hargocdизпълнение · прилагане: TokenRequest · 6 hSA railshot-argocd · токен<app namespace>

    CronJob railshot-credentials иска на всеки два часа нов шестчасов токен за клиентския SA. Role от страна на клиента позволява само token create за собствения му SA. Шест часа е TTL на един токен, а не моментът, в който приключва достъпът на оператора.

Всички връзки с еднаква дебелина. Изберете поток, за да се откроят само неговият път и номерираните стъпки.

  • Плътна · посоката, в която текат заявките, пакетите, образите и декларациите
  • Прекъсната · заявки за изпълнение, прилагане, инсталиране, идентификационни данни
  • Дълга щрих-пунктирна · четене на състояние, логове, проби, метрики; отделно от вердикта
  • Дебела черна линия · избраният поток; числата показват реда
  • Кутия · namespace, с името в заглавието (не е възел)
  • Вътрешен етикет · компонент в този namespace
  • Прекъсната кутия · извън клъстерите
  • railshot-system · продукт
  • argocd · правомощие за внедряване
  • railshot-build · правомощие върху Docker на хоста
  • GitHub · клиентски клъстер

Решението за разположение от 2 октомври в docs/architecture (два възела по роли) и диаграмата в публичния README са история; тази карта следва декларациите и кода при 645e28a. Стрелките показват причина и посока, а не доказателство, че всеки път на доставчик работи в момента.

Namespace и възли
Namespace е обхват на имена: нито хардуер, нито сам по себе си граница на сигурността. Ролите platform и build са разположение при планирането чрез nodeSelector и taint; тази карта не фиксира броя на възлите в оперативния клъстер. Разположението на Argo CD по възли също е отделна проверка.
Правомощия на build възела
Runner Job работят с hostNetwork, Docker сокета на хоста, NET_ADMIN и root. Namespace, taint или RBAC не премахват правомощието върху Docker на хоста, затова това не е нито изолация от администратора на VM, нито sandbox за произволен код.
Namespace на клиента
Всяка регистрирана цел използва namespace и AppProject, различни от тези по подразбиране (например tenant-demo или app-<id> за всяко приложение). Създават се само Deployment на една услуга (с изключено автоматично монтиране на токена на ServiceAccount), NodePort Service и NetworkPolicy, както и по избор PVC или Job за миграция; Secret само се посочват по име (pull Secret и одобрен DATABASE_URL) и никога не се създават.
Входна точка в AWS
Route 53 Alias → споделен ALB HTTPS 443 → частният адрес и NodePort на клиентския възел. Много приложения използват един възел, всяко със собствени namespace, Application и NodePort.
Входна точка в GCP
Глобален EXTERNAL_MANAGED HTTPS LB → зонален GCE_VM_IP_PORT NEG → частният NodePort на съществуващата VM. Сертификатите идват от Certificate Manager с DNS авторизация. Модулът не притежава нито VM, нито VPC, а една VM остава единична точка на отказ.
Входна точка в OpenStack
Amphora TLS listener 443 с L7 политики по Host и път → HTTP NodePort. Адресът по подразбиране е частен VIP; Octavia, K3s, базата данни и DNS са извън модула. Публичната достъпност и готовността на Amphora на място изискват отделно приемане, а прилагане на място с този модул още не е потвърдено.
Между доставчиците
Трите входни точки са отделни реализации, без автоматичен failover или репликация между доставчиците. Клъстерът за клиентско приложение е пример за регистрирана цел, а не твърдение, че едно и също внедряване работи едновременно във всеки облак.
Опции на оператора
Личният gateway (WireGuard) се присъединява към платформата само когато операторът включи --personal; той не е задължителен път за клиентските облаци. В поддържания режим direct VM за наблюдение може да споделя оперативната контролна VM.