Railshot
AI deployment & operations platform
Een lokaal gebouwde webapp uitrollen naar voorbereide cloud- en on-premises-omgevingen en daarna laten draaien.
Een AI-platform voor uitrol en beheer dat een lokaal gebouwde webapp naar voorbereide cloud- of on-premises-omgevingen brengt en blijft laten draaien.
Operationele en klantappclusters zijn gescheiden, en het publieke pad blijft los van de uitrolbesturing.
In de operationele K3s staan het dashboard, de product-API en de buildcontroller op nodes met de platformrol en runner-Jobs op een node met de buildrol, terwijl Argo CD de uitrol verzorgt. Klantapps draaien in een aangewezen namespace van een apart single-node-cluster met K3s + Cilium per geregistreerd doel.
Build → image publiceren
De product-API vraagt een GitHub Actions-run aan, en de runner op de buildnode neemt de job aan en controleert hem. Alleen een bundle die dezelfde controles doorstond, wordt door een door GitHub gehoste release-job naar GHCR gepubliceerd.
product-API · cd.js → bridge.py
railshot-systemuitvoeren · toepassen: workflow_dispatchloop job · self-hosted runnerrailshot-deploy.ymlDe product-API vraagt een GitHub Actions-run aan met tenant, app, source commit en target. De API roept nooit rechtstreeks een runner-Job aan.
build controller · CronJob
railshot-systemuitvoeren · toepassen: runner-Job aanvullenrunner Job · hostNetwork · Docker socketrailshot-buildDe CronJob van de buildcontroller (elke minuut, op een platformnode) maakt runner-Jobs aan in de namespace railshot-build. Zijn Role staat alleen get, list en create op Jobs toe plus get, update en patch op het ene runner-registratie-Secret; namespaces of andere Secrets kan hij niet aanmaken.
runner Job · hostNetwork · Docker socket
railshot-builduitvoeren · toepassen: job aannemenloop job · self-hosted runnerrailshot-deploy.ymlDe runner op de node met de buildrol (exacte hostnaam, NoSchedule-toleration) neemt de loop-job aan via zijn self-hosted labels en voert hem uit. Klantbroncode draait in de bestaande beperkte Docker-build- en controlecontainers.
runner Job · hostNetwork · Docker socket
railshot-buildgegevens: geteste bundlerelease job · GitHub-hostedrailshot-deploy.ymlDe loop-job laat de bundle achter die dezelfde controles doorstond, en de release-job neemt alleen die bundle aan.
release job · GitHub-hosted
railshot-deploy.ymlgegevens: publiceren per digestGHCREen door GitHub gehoste release-job (ubuntu-24.04) publiceert het image van de geteste bundle zonder rebuild naar GHCR. Images worden nooit binnen het klantappcluster gepubliceerd.
Config-Git → Argo → klantnamespace
Config-Git draagt de gewenste resources en GHCR de imagebytes. Argo CD past alleen toe op de geregistreerde klantnamespace.
product-API · cd.js → bridge.py
railshot-systemgegevens: workload commit · pushconfig-Git-repositorycd.js draait bridge.py, dat workload.json alleen commit en pusht als de publicatievastlegging en het geregistreerde doel overeenkomen, en daarna de remote revisie terugleest. Git draagt de gewenste resources; GHCR draagt de imagebytes.
config-Git-repositorygegevens: revisionArgo CD · Application
argocdDe Application leest alleen haar beperkte configrepository, pad en revisie.
product-API · cd.js → bridge.py
railshot-systemuitvoeren · toepassen: Application syncArgo CD · ApplicationargocdDe benoemde Application wordt via server-side apply ingesteld, en er wordt een sync van precies één revisie aangevraagd zonder prune. Het ServiceAccount railshot-product van de product-API heeft zowel de door de operator geïnstalleerde registratie-bootstrap (create voor Secrets, AppProjects en Applications in argocd; get, update en escalate op benoemde Roles) als get- en patch-rechten die per gevalideerd doel op exacte naam worden toegevoegd. Kubernetes-create kan niet op naam worden beperkt, dus houdt ook de inputvalidatie van het product de namen binnen bereik.
Argo CD · Application
argocduitvoeren · toepassen: toepassen op namespace<app namespace>Argo CD past toe op de aangewezen namespace in het klantcluster met de credential van het geregistreerde cluster-Secret. Het AppProject staat alleen namespaced kinds toe en geen clusterbrede resources.
Deployment · Pod · digest-image
<app namespace>gegevens: pull per digestGHCRHet gepubliceerde digest-image wordt opgehaald met een pull-Secret waarnaar in dezelfde namespace op naam wordt verwezen. Secret-waarden komen nooit in het artefact of in config-Git terecht.
Publiek verzoekpad
Appverzoeken lopen L7-ingang van de provider → NodePort van de node → Service → app-Pod. De policyhandhaving van Cilium is een aparte controle, geen hop die het verzoek draagt. De weg naar het operationele dashboard is een apart pad.
Appgebruikergegevens: HTTPS 443L7-ingang van de provider
Appgebruikers bereiken de L7-ingang van de provider via de geregistreerde hostnaam. Elke provider implementeert zijn eigen ingang.
L7-ingang van de providergegevens: NodePortNodePort Service · Local
<app namespace>De ingang stuurt door naar het privéadres en de NodePort van de node. De NodePort is die welke bij de registratie van het doel is toegewezen.
NodePort Service · Local
<app namespace>gegevens: naar de PodDeployment · Pod · digest-image<app namespace>De Service stuurt het verzoek naar de app-Pod (Deployment) op dezelfde node. Met externalTrafficPolicy Local bereikt het bronadres de controle op geregistreerde CIDR’s van de NetworkPolicy ongewijzigd.
Cilium · Helm · VXLAN
kube-systemuitvoeren · toepassen: policy afdwingenNetworkPolicy · opgegeven CIDR’s<app namespace>Cilium dwingt de NetworkPolicy af: ingress alleen vanaf de geregistreerde CIDR’s naar de app-poort; standaard geen egress, behalve naar een goedgekeurd databaseadres. Cloudfirewalls en hostregels blijven nodig.
Railshot-gebruikergegevens: dashboard · APIdashboard · nginx
railshot-systemGebruikers komen via de operationele ingang bij het nginx-dashboard, en nginx staat vóór de product-API. De dashboard-Service is alleen een NodePort als er een goedgekeurde nodepoort is opgegeven; de API blijft ClusterIP.
Verifiëren · observeren
Het uitroloordeel steunt alleen op de Argo-status en de controle van de publieke URL. Pod-diagnostiek, actuele logs en operationele metrics zijn aparte signalen die het nooit veranderen.
product-API · cd.js → bridge.py
railshot-systemobserveren: revisie · health · imagesArgo CD · ApplicationargocdDeployed vereist de syncrevisie van de Application, Synced en Healthy, de operation Succeeded, en image-referenties in de status van de Argo-Application die gelijk zijn aan de digest-images van de beoordeelde Deployment. Het is geen directe gate op de imageID van de Pod, en een groene Argo-status alleen bewijst de overeenkomst niet.
product-API · cd.js → bridge.py
railshot-systemobserveren: publieke HTTPS-controleL7-ingang van de providerDe geregistreerde publieke URL wordt gecontroleerd zonder redirects. Succeeded wordt alleen vastgelegd met zowel het Argo-oordeel als deze controle.
product-API · cd.js → bridge.py
railshot-systemobserveren: Pod-diagnostiek · niet het oordeelDeployment · Pod · digest-image<app namespace>Na het Argo-oordeel en de publieke controle worden de Deployment, ReplicaSets en Pods apart gelezen met de geregistreerde credential, en imageID en gereedheid worden toegevoegd als diagnose ready, progressing of unavailable. Een mislukte of afwijkende diagnose verandert nooit het oordeel deployed of succeeded.
product-API · cd.js → bridge.py
railshot-systemobserveren: log-tail · 100 regels per PodDeployment · Pod · digest-image<app namespace>Alleen voor de momenteel uitgerolde operation, met de vertrouwde config en de geregistreerde credential. Voor elke huidige Pod (hoogstens drie) moet de digest van het draaiende image gelijk zijn aan de verwachte digest; daarna worden per Pod tot 100 geredigeerde regels gelezen binnen een bytelimiet. Een oudere poging antwoordt superseded; zonder configuratie not_configured. Dit is geen logaggregatie.
Observer-VMobserveren: scrape · NodePortsrailshot-observability
Prometheus op de observer-VM scrapet node-exporter en kube-state-metrics via twee door de firewall beperkte NodePorts. Ontbrekende of verouderde waarden zijn onbekend, niet nul.
Observer-VMobserveren: Blackbox probeL7-ingang van de provider
probe_success=1 betekent een 2xx op die probelocatie. Het bewijst niet de toegang van elke gebruiker of de uitgerolde versie, en het promoveert published nooit tot deployed.
Operator: installatie · registratie
Clusterinstallatie, de registratie-bootstrap en doelinput, Secrets en de inrichting van de credentialvernieuwing zijn operatorinput, nooit onderdeel van de payload van de tenant-app.
Operator-bootstrapuitvoeren · toepassen: platform renderen · Secretrailshot-system
De operator rendert de platformdeclaratie met render-platform.py en levert de private operationele config en Secrets aan. De remote MCP wordt alleen opgenomen als het image wordt aangeleverd, de persoonlijke gateway (WireGuard) alleen met --personal.
Operator-bootstrapuitvoeren · toepassen: registratie-bootstrapAppProject · cluster Secret
argocdDe operator installeert in argocd de registratie-bootstrap-Role en een lege registratie-Role en bereidt de doelinput voor. De registratiehelpers die de product-API draait (environment.py, applications.py) schrijven daarna het Secret railshot-<target> met een afgebakende credential (clusterResources false, toegestane namespaces opgesomd) en voegen de gevalideerde exacte namen toe aan de registratie-Role. Registratie per app koppelt een namespace app-<id> aan een AppProject met dezelfde naam.
Operator-bootstrapuitvoeren · toepassen: K3s · Cilium installerenCilium · Helm · VXLAN
kube-systeminstall-k3s.sh installeert een single-node K3s-server (flannel, network policy, traefik en servicelb uit; kube-proxy behouden), en Cilium wordt geïnstalleerd als Helm-release (kubeProxyReplacement false, VXLAN, Hubble uit).
vernieuwings-CronJob · elke 2 u
argocduitvoeren · toepassen: TokenRequest · 6 urailshot-argocd SA · token<app namespace>De CronJob railshot-credentials vraagt elke twee uur een nieuw token van zes uur aan voor het klant-SA. De Role aan klantzijde staat alleen token create voor het eigen SA toe. Zes uur is de TTL van één token, niet het moment waarop operatortoegang eindigt.
Alle verbindingen even zwaar. Kies een stroom om alleen het pad daarvan te markeren, met genummerde stappen.
- Doorgetrokken · richting waarin verzoeken, bundles, images en declaraties stromen
- Gestreept · runverzoeken, toepassen, installatie, credentials
- Lange streep-punt · status, logs, probes en metrics lezen; los van het oordeel
- Dikke zwarte lijn · de gekozen stroom; nummers geven de volgorde
- Vak · een namespace, naam in de kop (geen node)
- Binnenchip · een component in die namespace
- Gestreept vak · buiten de clusters
- railshot-system · product
- argocd · uitrolbevoegdheid
- railshot-build · host-Docker-bevoegdheid
- GitHub · klantcluster
De plaatsingsbeslissing van October 2 in docs/architecture (twee rolnodes) en het diagram in de openbare README zijn geschiedenis; deze kaart volgt de declaraties en code van 645e28a. Pijlen tonen oorzaak en richting, geen bewijs dat elk providerpad nu actief is.
- Namespaces en nodes
- Een namespace is een naambereik: geen hardware en op zichzelf ook geen beveiligingsgrens. De rollen platform en build zijn schedulingplaatsing via nodeSelector en taint; deze kaart legt het aantal nodes van het operationele cluster niet vast. Ook de nodeplaatsing van Argo CD is een aparte controle.
- Bevoegdheid van de buildnode
- Runner-Jobs draaien met hostNetwork, de Docker-socket van de host, NET_ADMIN en root. Een namespace, taint of RBAC neemt de host-Docker-bevoegdheid niet weg, dus dit is geen isolatie van de VM-beheerder en geen sandbox voor willekeurige code.
- Klantnamespace
- Elk geregistreerd doel gebruikt een niet-standaard namespace en AppProject (bijvoorbeeld tenant-demo, of app-<id> per app). Alleen de Deployment van één dienst (automount van het ServiceAccount-token uit), een NodePort-Service en een NetworkPolicy, plus optioneel een PVC of migratie-Job, worden aangemaakt; naar Secrets wordt alleen op naam verwezen (het pull-Secret en een goedgekeurde DATABASE_URL), ze worden nooit aangemaakt.
- AWS-ingang
- Route 53 Alias → gedeelde ALB HTTPS 443 → privéadres en NodePort van de klantnode. Veel apps hergebruiken één node, elk met een eigen namespace, Application en NodePort.
- GCP-ingang
- Globale EXTERNAL_MANAGED HTTPS-LB → zonale GCE_VM_IP_PORT NEG → privé-NodePort van de bestaande VM. Certificaten komen uit Certificate Manager met DNS-autorisatie. De module bezit de VM noch de VPC, en één VM blijft een single point of failure.
- OpenStack-ingang
- Amphora-TLS-listener 443 met L7-policies voor host en pad → HTTP-NodePort. Het standaardadres is een private VIP; Octavia, K3s, de database en DNS vallen buiten de module. Publieke bereikbaarheid en de gereedheid van Amphora ter plaatse vereisen een aparte acceptatie, en met deze module is nog geen apply ter plaatse geverifieerd.
- Tussen providers
- De drie ingangen zijn aparte implementaties, zonder automatische failover of replicatie tussen providers. Het klantappcluster is een voorbeeld van een geregistreerd doel, geen bewering dat dezelfde uitrol tegelijk op elke cloud draait.
- Opties van de operator
- De persoonlijke gateway (WireGuard) wordt alleen deel van het platform als de operator --personal inschakelt; het is geen verplicht pad voor klantclouds. In de ondersteunde directe modus mag de observer-VM de operationele control-VM delen.