Railshot
AI deployment & operations platform
Driftsätt en lokalt byggd webbapp i förberedda moln- och on-premises-miljöer och driv den sedan.
En AI-plattform för driftsättning och drift som tar en lokalt byggd webbapp till förberedda moln- eller on-premises-miljöer och håller den igång.
Drift- och kundappkluster är åtskilda, och den publika vägen hålls åtskild från driftsättningsstyrningen.
I drift-K3s placeras dashboard, produkt-API och build controller på noder med platform-roll och runner-Jobs på en nod med build-roll, medan Argo CD sköter driftsättningen. Kundappar körs i ett angivet namespace i ett separat K3s + Cilium-kluster med en nod för varje registrerat mål.
Bygge → publicera image
Produkt-API:et begär en GitHub Actions-körning, och runnern på build-noden tar jobbet och kontrollerar det. Bara en bundle som klarade samma kontroller publiceras till GHCR av ett GitHub-hostat release-jobb.
produkt-API · cd.js → bridge.py
railshot-systemköra · tillämpa: workflow_dispatchloop job · self-hosted runnerrailshot-deploy.ymlProdukt-API:et begär en GitHub Actions-körning med tenant, app, source commit och target. API:et anropar aldrig ett runner-Job direkt.
build controller · CronJob
railshot-systemköra · tillämpa: fyll på runner-Jobrunner Job · hostNetwork · Docker socketrailshot-buildBuild controllerns CronJob (varje minut, på en platform-nod) skapar runner-Jobs i namespacet railshot-build. Dess Role tillåter bara get, list och create på Jobs samt get, update och patch på det enda Secret för runner-registrering; den kan inte skapa namespaces eller andra Secrets.
runner Job · hostNetwork · Docker socket
railshot-buildköra · tillämpa: ta emot jobbloop job · self-hosted runnerrailshot-deploy.ymlRunnern på noden med build-roll (exakt hostname, NoSchedule-toleration) tar loop-jobbet utifrån dess self-hosted-etiketter och kör det. Kundens källkod körs i de befintliga begränsade Docker-containrarna för bygge och kontroll.
runner Job · hostNetwork · Docker socket
railshot-builddata: testad bundlerelease job · GitHub-hostedrailshot-deploy.ymlLoop-jobbet lämnar den bundle som klarade samma kontroller, och release-jobbet tar bara den bundlen.
release job · GitHub-hosted
railshot-deploy.ymldata: publicera via digestGHCREtt GitHub-hostat release-jobb (ubuntu-24.04) publicerar den testade bundlens image till GHCR utan att bygga om den. Publicering av images sker aldrig inuti kundappklustret.
Config-Git → Argo → kundens namespace
Config-Git bär de önskade resurserna och GHCR image-byten. Argo CD tillämpar bara på det registrerade kund-namespacet.
produkt-API · cd.js → bridge.py
railshot-systemdata: workload commit · pushconfig-Git-repositorycd.js kör bridge.py, som bara committar och pushar workload.json när publiceringsloggen och det registrerade målet stämmer överens, och sedan läser tillbaka fjärr-revisionen. Git bär de önskade resurserna; GHCR bär image-byten.
config-Git-repositorydata: revisionArgo CD · Application
argocdApplication läser bara sitt begränsade config-repository, sin sökväg och sin revision.
produkt-API · cd.js → bridge.py
railshot-systemköra · tillämpa: Application syncArgo CD · ApplicationargocdDen namngivna Application sätts med server-side apply, och en sync av en exakt revision begärs utan prune. Produkt-API:ets ServiceAccount railshot-product har både den registrerings-bootstrap som operatören installerat (create på Secrets, AppProjects och Applications i argocd; get, update och escalate på namngivna Roles) och get- och patch-rättigheter som läggs till med exakt namn för varje validerat mål. Kubernetes create kan inte begränsas efter namn, så produktens indatavalidering håller också namnen inom omfånget.
Argo CD · Application
argocdköra · tillämpa: tillämpa på namespace<app namespace>Argo CD tillämpar på det angivna namespacet i kundklustret med autentiseringsuppgiften från det registrerade cluster-Secret. AppProject tillåter bara namespace-avgränsade kinds och inga resurser på klusternivå.
Deployment · Pod · digest-image
<app namespace>data: pull via digestGHCRDen publicerade digest-imagen hämtas med ett pull-Secret som refereras med namn i samma namespace. Secret-värden hamnar aldrig i artefakten eller config-Git.
Publik förfrågningsväg
Appförfrågningar går leverantörens L7-ingång → nodens NodePort → Service → appens Pod. Ciliums tillämpning av policy är en separat kontroll, inte ett steg som bär förfrågan. Vägen in till driftdashboarden är en separat väg.
Appanvändaredata: HTTPS 443Leverantörens L7-ingång
Appanvändare når leverantörens L7-ingång via det registrerade hostnamnet. Varje leverantör implementerar sin egen ingång.
Leverantörens L7-ingångdata: NodePortNodePort Service · Local
<app namespace>Ingången vidarebefordrar till nodens privata adress och NodePort. NodePort är den som tilldelades vid registreringen av målet.
NodePort Service · Local
<app namespace>data: till PodDeployment · Pod · digest-image<app namespace>Service skickar förfrågan till appens Pod (Deployment) på samma nod. Med externalTrafficPolicy Local når källadressen oförändrad fram till NetworkPolicyns kontroll av registrerade CIDR:er.
Cilium · Helm · VXLAN
kube-systemköra · tillämpa: tillämpa policyNetworkPolicy · endast angivna CIDR:er<app namespace>Cilium tillämpar NetworkPolicy: ingress bara från de registrerade CIDR:erna till appens port; ingen egress som standard, utom en godkänd databasadress. Molnbrandväggar och värdregler spelar fortfarande roll.
Railshot-användaredata: dashboard · APIdashboard · nginx
railshot-systemAnvändare kommer via driftingången till nginx-dashboarden, och nginx står framför produkt-API:et. Dashboardens Service är en NodePort bara när en godkänd nodport anges; API:et förblir ClusterIP.
Verifiera · observera
Driftsättningsdomen vilar bara på Argo-status och kontrollen av den publika URL:en. Pod-diagnostik, aktuella loggar och driftmätvärden är separata signaler som aldrig ändrar den.
produkt-API · cd.js → bridge.py
railshot-systemobservera: revision · health · imagesArgo CD · ApplicationargocdDeployed kräver Applicationens sync-revision, Synced och Healthy, operation Succeeded och att image-referenserna i Argo Applicationens status är lika med den granskade Deploymentens digest-images. Det är ingen direkt grind på Poddens imageID, och en grön Argo-status ensam fastställer inte överensstämmelsen.
produkt-API · cd.js → bridge.py
railshot-systemobservera: publik HTTPS-kontrollLeverantörens L7-ingångDen registrerade publika URL:en kontrolleras utan omdirigeringar. Succeeded registreras bara med både Argo-domen och denna kontroll.
produkt-API · cd.js → bridge.py
railshot-systemobservera: Pod-diagnostik · inte domenDeployment · Pod · digest-image<app namespace>Efter Argo-domen och den publika kontrollen läses Deployment, ReplicaSets och Pods separat med den registrerade autentiseringsuppgiften, och imageID och beredskap läggs till som diagnos: ready, progressing eller unavailable. En misslyckad eller avvikande diagnos ändrar aldrig domen deployed eller succeeded.
produkt-API · cd.js → bridge.py
railshot-systemobservera: logg-tail · 100 rader per PodDeployment · Pod · digest-image<app namespace>Bara för den för närvarande driftsatta operationen, med den betrodda configen och den registrerade autentiseringsuppgiften. För varje aktuell Pod (högst tre) måste den körande image-digesten vara lika med den förväntade digesten; därefter läses upp till 100 maskerade rader per Pod inom en bytegräns. Ett äldre försök svarar superseded; utan konfiguration not_configured. Det är inte loggaggregering.
Observations-VMobservera: scrape · NodePortsrailshot-observability
Prometheus på observations-VM:en scrapar node-exporter och kube-state-metrics via två NodePorts som begränsas av en brandvägg. Saknade eller inaktuella värden är okända, inte noll.
Observations-VMobservera: Blackbox probeLeverantörens L7-ingång
probe_success=1 betyder en 2xx från den plats där proben körs. Det bevisar varken alla användares åtkomst eller den driftsatta versionen, och det uppgraderar aldrig published till deployed.
Operatörsinstallation · registrering
Klusterinstallation, registreringsbootstrap och indata för mål, Secrets och uppsättningen för förnyelse av autentiseringsuppgifter är operatörsindata, aldrig en del av tenant-appens payload.
Operatörsbootstrapköra · tillämpa: generera platform · Secretrailshot-system
Operatören genererar platform-deklarationen med render-platform.py och tillhandahåller den privata driftkonfigurationen och Secrets. Fjärr-MCP:n ingår bara när dess image tillhandahålls, och den personliga gatewayen (WireGuard) bara med --personal.
Operatörsbootstrapköra · tillämpa: registreringsbootstrapAppProject · cluster Secret
argocdOperatören installerar en Role för registreringsbootstrap och en tom Role för registreringar i argocd och förbereder indata för målen. Registreringshjälparna som produkt-API:et kör (environment.py, applications.py) skriver sedan Secret railshot-<target> med en avgränsad autentiseringsuppgift (clusterResources false, tillåtna namespaces angivna) och lägger till de validerade exakta namnen i registreringarnas Role. Registrering per app binder ett namespace app-<id> till ett AppProject med samma namn.
Operatörsbootstrapköra · tillämpa: installera K3s · CiliumCilium · Helm · VXLAN
kube-systeminstall-k3s.sh installerar en K3s-server med en nod (flannel, network policy, traefik och servicelb avstängda; kube-proxy behållen), och Cilium installeras som en Helm-release (kubeProxyReplacement false, VXLAN, Hubble avstängd).
förnyelse-CronJob · varannan timme
argocdköra · tillämpa: TokenRequest · 6 hrailshot-argocd SA · tokenutfärdande<app namespace>CronJob railshot-credentials begär varannan timme en ny token på sex timmar för kundens SA. Role på kundsidan tillåter bara token create för dess egen SA. Sex timmar är en tokens TTL, inte när operatörens åtkomst upphör.
Alla kopplingar med samma tjocklek. Välj ett flöde för att bara markera dess väg, med numrerade steg.
- Heldragen · riktningen som förfrågningar, bundles, images och deklarationer flödar i
- Streckad · körbegäran, tillämpa, installera, autentiseringsuppgifter
- Lång streck-punkt · läsning av status, loggar, prober, mätvärden; skilt från domen
- Kraftig svart linje · det valda flödet; siffrorna anger ordningen
- Ruta · ett namespace, namnet i rubriken (inte en nod)
- Inre chip · en komponent i det namespacet
- Streckad ruta · utanför klustren
- railshot-system · produkt
- argocd · driftsättningsbefogenhet
- railshot-build · behörighet till värdens Docker
- GitHub · kundkluster
Placeringsbeslutet från 2 oktober i docs/architecture (två rollnoder) och diagrammet i den offentliga README-filen är historik; denna karta följer deklarationerna och koden vid 645e28a. Pilarna visar orsak och riktning, inte bevis för att alla provider-vägar är aktiva nu.
- Namespaces och noder
- Ett namespace är ett namnområde: varken hårdvara eller i sig en säkerhetsgräns. Rollerna platform och build är schemaläggningsplacering via nodeSelector och taint; denna karta fastställer inte antalet noder i driftklustret. Argo CD:s nodplacering är också en separat kontroll.
- Build-nodens behörighet
- Runner-Jobs körs med hostNetwork, värdens Docker-socket, NET_ADMIN och root. Ett namespace, en taint eller RBAC tar inte bort behörigheten till värdens Docker, så detta är varken isolering på VM-administratörsnivå eller en sandlåda för godtycklig kod.
- Kundens namespace
- Varje registrerat mål använder ett namespace och ett AppProject som inte är standard (till exempel tenant-demo eller app-<id> per app). Bara en tjänsts Deployment (automount av ServiceAccount-token avstängd), NodePort-Service och NetworkPolicy samt en valfri PVC eller ett migration-Job skapas; Secrets refereras bara med namn (pull-Secret och en godkänd DATABASE_URL) och skapas aldrig.
- AWS-ingång
- Route 53 Alias → delad ALB HTTPS 443 → kundnodens privata adress och NodePort. Många appar återanvänder en nod, var och en med sitt eget namespace, sin Application och sin NodePort.
- GCP-ingång
- Global EXTERNAL_MANAGED HTTPS LB → zonal GCE_VM_IP_PORT NEG → den befintliga VM:ens privata NodePort. Certifikat kommer från Certificate Manager med DNS-auktorisering. Modulen äger varken VM:en eller VPC:n, och en VM förblir en enskild felpunkt.
- OpenStack-ingång
- Amphora TLS-lyssnare 443 med L7-policyer för Host och sökväg → HTTP NodePort. Standardadressen är en privat VIP; Octavia, K3s, databasen och DNS ligger utanför modulen. Publik nåbarhet och Amphora-beredskap på plats kräver separat acceptans, och ingen tillämpning på plats har ännu verifierats med denna modul.
- Mellan leverantörer
- De tre ingångarna är separata implementationer, utan automatisk failover eller replikering mellan leverantörer. Kundappklustret är ett exempel på ett registrerat mål, inget påstående om att samma driftsättning körs i alla moln samtidigt.
- Operatörsval
- Den personliga gatewayen (WireGuard) ingår i plattformen bara när operatören aktiverar --personal; den är ingen obligatorisk väg för kundmoln. I det stödda direct-läget kan observations-VM:en dela driftens kontroll-VM.